`
+ } else { //disabled
+ text += `
`
+ }
+
+ if (tech.tech[i].isFieldTech) {
+ text += build.fieldTechText(i)
+ } else if (tech.tech[i].isGunTech) {
+ text += build.gunTechText(i)
+ } else if (tech.tech[i].isSkin) {
+ text += build.skinTechText(i)
+ } else if (tech.tech[i].isJunk) {
+ text += build.junkTechText(i)
+ } else {
+ text += build.techText(i)
+ }
+ text += '
'
+ }
+ }
+ document.getElementById("experiment-grid").innerHTML = text
+ // for (let i = 0, len = tech.tech.length; i < len; i++) {
+ // if (tech.tech[i].count)
+ // document.getElementById("tech-" + i).classList.add("build-tech-selected")
+ // }
+
+ document.getElementById("difficulty-select-experiment").value = document.getElementById("difficulty-select").value
+ document.getElementById("difficulty-select-experiment").addEventListener("input", () => {
+ simulation.difficultyMode = Number(document.getElementById("difficulty-select-experiment").value)
+ lore.setTechGoal()
+ localSettings.difficultyMode = Number(document.getElementById("difficulty-select-experiment").value)
+ document.getElementById("difficulty-select").value = document.getElementById("difficulty-select-experiment").value
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ });
+ //add tooltips
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (document.getElementById(`tech-${i}`)) {
+ document.getElementById(`tech-${i}`).setAttribute('data-descr', tech.tech[i].requires); //add tooltip
+ // document.getElementById(`tech-${i}`).setAttribute('title', tech.tech[i].requires); //add tooltip
+ }
+ }
+ //highlight selected
+
+ },
+ nameLink(text) { //converts text into a clickable wikipedia search
+ return `
${text} `
+ },
+ reset() {
+ build.isExperimentSelection = true;
+ build.isExperimentRun = true;
+ simulation.startGame(true); //starts game, but pauses it
+ build.isExperimentSelection = true;
+ build.isExperimentRun = true;
+ simulation.paused = true;
+ b.inventory = []; //removes guns and ammo
+ for (let i = 0, len = b.guns.length; i < len; ++i) {
+ b.guns[i].count = 0;
+ b.guns[i].have = false;
+ if (b.guns[i].ammo != Infinity) b.guns[i].ammo = 0;
+ }
+ b.activeGun = null;
+ b.inventoryGun = 0;
+ simulation.makeGunHUD();
+ m.resetSkin()
+ tech.setupAllTech();
+ build.populateGrid();
+ document.getElementById("field-0").classList.add("build-field-selected");
+ document.getElementById("experiment-grid").style.display = "grid"
+ },
+ shareURL(isCustom = false) {
+ let url = "https://landgreen.github.io/sidescroller/index.html?"
+ url += `&seed=${Math.initialSeed}`
+ let count = 0;
+ for (let i = 0; i < b.inventory.length; i++) {
+ if (b.guns[b.inventory[i]].have) {
+ url += `&gun${count}=${encodeURIComponent(b.guns[b.inventory[i]].name.trim())}`
+ count++
+ }
+ }
+ count = 0;
+ for (let i = 0; i < tech.tech.length; i++) {
+ for (let j = 0; j < tech.tech[i].count; j++) {
+ if (!tech.tech[i].isLore && !tech.tech[i].isJunk && !tech.tech[i].isNonRefundable) {
+ url += `&tech${count}=${encodeURIComponent(tech.tech[i].name.trim())}`
+ count++
+ }
+ }
+ }
+ url += `&molMode=${encodeURIComponent(simulation.molecularMode)}`
+ // if (property === "molMode") {
+ // simulation.molecularMode = Number(set[property])
+ // m.fieldUpgrades[i].description = m.fieldUpgrades[i].setDescription()
+ // document.getElementById(`field-${i}`).innerHTML = `
${build.nameLink(m.fieldUpgrades[i].name)}
${m.fieldUpgrades[i].description}`
+ // }
+
+ url += `&field=${encodeURIComponent(m.fieldUpgrades[m.fieldMode].name.trim())}`
+ url += `&difficulty=${simulation.difficultyMode}`
+ if (isCustom) {
+ // url += `&level=${Math.abs(Number(document.getElementById("starting-level").value))}`
+ // alert('n-gon build URL copied to clipboard.\nPaste into browser address bar.')
+ } else {
+ simulation.makeTextLog("n-gon build URL copied to clipboard.
Paste into browser address bar.")
+ }
+ console.log('n-gon build URL copied to clipboard.\nPaste into browser address bar.')
+ console.log(url)
+ navigator.clipboard.writeText(url).then(function () {
+ /* clipboard successfully set */
+ if (isCustom) {
+ setTimeout(function () {
+ alert('n-gon build URL copied to clipboard.\nPaste into browser address bar.')
+ }, 300);
+ }
+ }, function () {
+ /* clipboard write failed */
+ if (isCustom) {
+ setTimeout(function () {
+ alert('copy failed')
+ }, 300);
+ }
+ console.log('copy failed')
+ });
+
+ },
+ hasExperimentalMode: false,
+ startExperiment() { //start playing the game after exiting the experiment menu
+ build.isExperimentSelection = false;
+ spawn.setSpawnList(); //gives random mobs, not starter mobs
+ spawn.setSpawnList();
+ if (b.inventory.length > 0) {
+ b.activeGun = b.inventory[0] //set first gun to active gun
+ b.inventoryGun = 0;
+ simulation.makeGunHUD();
+ }
+ for (let i = 0; i < bullet.length; ++i) Matter.Composite.remove(engine.world, bullet[i]);
+ bullet = []; //remove any bullets that might have spawned from tech
+ build.hasExperimentalMode = false
+ if (!simulation.isCheating) {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].count > 0 && !tech.tech[i].isLore) simulation.isCheating = true;
+ }
+ if (b.inventory.length !== 0 || m.fieldMode !== 0) simulation.isCheating = true;
+ }
+ if (simulation.isCheating) { //if you are cheating remove any lore you might have gotten
+ lore.techCount = 0;
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isLore) {
+ tech.tech[i].frequency = 0; //remove lore power up chance
+ tech.tech[i].count = 0; //remove lore power up chance
+ }
+ }
+ simulation.updateTechHUD();
+ } else { //if you have no tech (not cheating) remove all power ups that might have spawned from tech
+ for (let i = 0; i < powerUp.length; ++i) Matter.Composite.remove(engine.world, powerUp[i]);
+ powerUp = [];
+ // if (build.hasExperimentalMode) {
+ // for (let i = 0; i < 7; i++) tech.giveTech("undefined")
+ // }
+ }
+ document.body.style.cursor = "none";
+ document.body.style.overflow = "hidden"
+ document.getElementById("experiment-grid").style.display = "none"
+ simulation.paused = false;
+ requestAnimationFrame(cycle);
+ }
+}
+
+function openExperimentMenu() {
+ document.getElementById("experiment-button").style.display = "none";
+ document.getElementById("training-button").style.display = "none";
+ const el = document.getElementById("experiment-grid")
+ el.style.display = "grid"
+ document.body.style.overflowY = "scroll";
+ document.body.style.overflowX = "hidden";
+ document.getElementById("info").style.display = 'none'
+ build.reset();
+}
+
+//record settings so they can be reproduced in the experimental menu
+document.getElementById("experiment-button").addEventListener("click", () => { //setup build run
+ // let field = 0;
+ // let inventory = [];
+ // let techList = [];
+ // if (!simulation.firstRun) {
+ // field = m.fieldMode
+ // inventory = [...b.inventory]
+ // for (let i = 0; i < tech.tech.length; i++) {
+ // techList.push(tech.tech[i].count)
+ // }
+ // }
+ openExperimentMenu();
+});
+
+
+// ************************************************************************************************
+// inputs
+// ************************************************************************************************
+const input = {
+ fire: false, // left mouse
+ field: false, // right mouse
+ up: false, // jump
+ down: false, // crouch
+ left: false,
+ right: false,
+ isPauseKeyReady: true,
+ key: {
+ fire: "KeyF",
+ field: "Space",
+ up: "KeyW", // jump
+ down: "KeyS", // crouch
+ left: "KeyA",
+ right: "KeyD",
+ pause: "KeyP",
+ nextGun: "KeyE",
+ previousGun: "KeyQ",
+ testing: "KeyT"
+ },
+ setDefault() {
+ input.key = {
+ fire: "KeyF",
+ field: "Space",
+ up: "KeyW", // jump
+ down: "KeyS", // crouch
+ left: "KeyA",
+ right: "KeyD",
+ pause: "KeyP",
+ nextGun: "KeyE",
+ previousGun: "KeyQ",
+ testing: "KeyT"
+ }
+ input.controlTextUpdate()
+ },
+ controlTextUpdate() {
+ function cleanText(text) {
+ return text.replace('Key', '').replace('Digit', '')
+ }
+ if (!input.key.fire) input.key.fire = "KeyF"
+ document.getElementById("key-fire").innerHTML = cleanText(input.key.fire)
+ document.getElementById("key-field").innerHTML = cleanText(input.key.field)
+ document.getElementById("key-up").innerHTML = cleanText(input.key.up)
+ document.getElementById("key-down").innerHTML = cleanText(input.key.down)
+ document.getElementById("key-left").innerHTML = cleanText(input.key.left)
+ document.getElementById("key-right").innerHTML = cleanText(input.key.right)
+ document.getElementById("key-pause").innerHTML = cleanText(input.key.pause)
+ document.getElementById("key-next-gun").innerHTML = cleanText(input.key.nextGun)
+ document.getElementById("key-previous-gun").innerHTML = cleanText(input.key.previousGun)
+ document.getElementById("key-testing").innerHTML = cleanText(input.key.testing) //if (localSettings.loreCount > 0)
+
+ document.getElementById("splash-up").innerHTML = cleanText(input.key.up)[0]
+ document.getElementById("splash-down").innerHTML = cleanText(input.key.down)[0]
+ document.getElementById("splash-left").innerHTML = cleanText(input.key.left)[0]
+ document.getElementById("splash-right").innerHTML = cleanText(input.key.right)[0]
+ document.getElementById("splash-next-gun").innerHTML = cleanText(input.key.nextGun)[0]
+ document.getElementById("splash-previous-gun").innerHTML = cleanText(input.key.previousGun)[0]
+
+ localSettings.key = input.key
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ },
+ focus: null,
+ setTextFocus() {
+ const backgroundColor = "#fff"
+ document.getElementById("key-fire").style.background = backgroundColor
+ document.getElementById("key-field").style.background = backgroundColor
+ document.getElementById("key-up").style.background = backgroundColor
+ document.getElementById("key-down").style.background = backgroundColor
+ document.getElementById("key-left").style.background = backgroundColor
+ document.getElementById("key-right").style.background = backgroundColor
+ document.getElementById("key-pause").style.background = backgroundColor
+ document.getElementById("key-next-gun").style.background = backgroundColor
+ document.getElementById("key-previous-gun").style.background = backgroundColor
+ document.getElementById("key-testing").style.background = backgroundColor
+ if (input.focus) input.focus.style.background = 'rgb(0, 200, 255)';
+ document.getElementById("key-num").style.background = backgroundColor //always not highlighted
+ },
+ setKeys(event) {
+ //check for duplicate keys
+ if (event.code && !(
+ event.code === "ArrowRight" ||
+ event.code === "ArrowLeft" ||
+ event.code === "ArrowUp" ||
+ event.code === "ArrowDown" ||
+ event.code === input.key.fire ||
+ event.code === input.key.field ||
+ event.code === input.key.up ||
+ event.code === input.key.down ||
+ event.code === input.key.left ||
+ event.code === input.key.right ||
+ event.code === input.key.pause ||
+ // event.code === "Escape" ||
+ event.code === input.key.nextGun ||
+ event.code === input.key.previousGun ||
+ event.code === input.key.testing ||
+ event.code === "Digit1" || event.code === "Digit2" || event.code === "Digit3" || event.code === "Digit4" || event.code === "Digit5" || event.code === "Digit6" || event.code === "Digit7" || event.code === "Digit8" || event.code === "Digit9" || event.code === "Digit0" || event.code === "Minus" || event.code === "Equal"
+ )) {
+ switch (input.focus.id) {
+ case "key-fire":
+ input.key.fire = event.code
+ break;
+ case "key-field":
+ input.key.field = event.code
+ break;
+ case "key-up":
+ input.key.up = event.code
+ break;
+ case "key-down":
+ input.key.down = event.code
+ break;
+ case "key-left":
+ input.key.left = event.code
+ break;
+ case "key-right":
+ input.key.right = event.code
+ break;
+ case "key-pause":
+ input.key.pause = event.code
+ break;
+ case "key-next-gun":
+ input.key.nextGun = event.code
+ break;
+ case "key-previous-gun":
+ input.key.previousGun = event.code
+ break;
+ case "key-testing":
+ input.key.testing = event.code
+ break;
+ }
+ }
+ input.controlTextUpdate()
+ input.endKeySensing()
+ },
+ endKeySensing() {
+ window.removeEventListener("keydown", input.setKeys);
+ input.focus = null
+ input.setTextFocus()
+ }
+}
+
+document.getElementById("control-table").addEventListener('click', (event) => {
+ if (event.target.className === 'key-input') {
+ input.focus = event.target
+ input.setTextFocus()
+ window.addEventListener("keydown", input.setKeys);
+ }
+});
+document.getElementById("control-details").addEventListener("toggle", function () {
+ input.controlTextUpdate()
+ input.endKeySensing();
+})
+
+document.getElementById("control-reset").addEventListener('click', input.setDefault);
+
+window.addEventListener("keyup", function (event) {
+ switch (event.code) {
+ case input.key.right:
+ case "ArrowRight":
+ input.right = false
+ break;
+ case input.key.left:
+ case "ArrowLeft":
+ input.left = false
+ break;
+ case input.key.up:
+ case "ArrowUp":
+ input.up = false
+ break;
+ case input.key.down:
+ case "ArrowDown":
+ input.down = false
+ break;
+ case input.key.fire:
+ input.fire = false
+ break
+ case input.key.field:
+ input.field = false
+ break
+ }
+});
+
+window.addEventListener("keydown", function (event) {
+ // console.log(event.code)
+ switch (event.code) {
+ case input.key.right:
+ case "ArrowRight":
+ input.right = true
+ break;
+ case input.key.left:
+ case "ArrowLeft":
+ input.left = true
+ break;
+ case input.key.up:
+ case "ArrowUp":
+ input.up = true
+ break;
+ case input.key.down:
+ case "ArrowDown":
+ input.down = true
+ break;
+ case input.key.fire:
+ input.fire = true
+ break
+ case input.key.field:
+ input.field = true
+ break
+ case input.key.nextGun:
+ simulation.nextGun();
+ break
+ case input.key.previousGun:
+ simulation.previousGun();
+ break
+ case input.key.pause:
+ if (!simulation.isChoosing && input.isPauseKeyReady && m.alive) {
+ input.isPauseKeyReady = false
+ setTimeout(function () {
+ input.isPauseKeyReady = true
+ }, 300);
+ if (simulation.paused) {
+ build.unPauseGrid()
+ simulation.paused = false;
+ // level.levelAnnounce();
+ document.body.style.cursor = "none";
+ requestAnimationFrame(cycle);
+ } else if (!tech.isNoDraftPause) {
+ simulation.paused = true;
+ build.pauseGrid()
+ document.body.style.cursor = "auto";
+
+ if (tech.isPauseSwitchField || simulation.testing) {
+ document.getElementById("pause-field").addEventListener("click", () => {
+ const energy = m.energy //save current energy
+ if (m.fieldMode === 4 && simulation.molecularMode < 3) {
+ simulation.molecularMode++
+ m.fieldUpgrades[4].description = m.fieldUpgrades[4].setDescription()
+ } else {
+ m.setField((m.fieldMode === m.fieldUpgrades.length - 1) ? 0 : m.fieldMode + 1) //cycle to next field
+ if (m.fieldMode === 4) {
+ simulation.molecularMode = 0
+ m.fieldUpgrades[4].description = m.fieldUpgrades[4].setDescription()
+ }
+ }
+ m.energy = energy //return to current energy
+ // document.getElementById("pause-field").innerHTML = `
${m.fieldUpgrades[m.fieldMode].name}
${m.fieldUpgrades[m.fieldMode].description}`
+ document.getElementById("pause-field").style.backgroundImage = `url('img/field/${m.fieldUpgrades[m.fieldMode].name}${m.fieldMode === 0 ? Math.floor(Math.random() * 10) : ""}.webp')`
+ document.getElementById("pause-field").innerHTML = `
+
+
${build.nameLink(m.fieldUpgrades[m.fieldMode].name)}
+ ${m.fieldUpgrades[m.fieldMode].description}
`
+ });
+ }
+ }
+ }
+ break
+ case input.key.testing:
+ if (m.alive && localSettings.loreCount > 0 && !simulation.paused) {
+ if (simulation.difficultyMode > 4) {
+ simulation.makeTextLog("
testing mode disabled for this difficulty ");
+ break
+ }
+ if (simulation.testing) {
+ simulation.testing = false;
+ simulation.loop = simulation.normalLoop
+ if (simulation.isConstructionMode) document.getElementById("construct").style.display = 'none'
+ simulation.makeTextLog("", 0);
+ } else { //if (keys[191])
+ simulation.testing = true;
+ simulation.loop = simulation.testingLoop
+ if (simulation.isConstructionMode) document.getElementById("construct").style.display = 'inline'
+ if (simulation.testing) tech.setCheating();
+ simulation.makeTextLog(
+ `
+
+ T
+ toggle testing
+
+
+ R
+ teleport to mouse
+
+
+ F
+ cycle field
+
+
+ G
+ all guns
+
+
+ H
+ +100% defense
+
+
+ B
+ damage, research
+
+
+ N
+ fill health, energy
+
+
+ Y
+ random tech
+
+
+ U
+ next level
+
+
+ J
+ clear mobs
+
+
+ I/O
+ zoom in / out
+
+
+ 1-8
+ spawn things
+
+
+ ⇧X
+ restart
+
+
`, Infinity);
+ }
+ }
+ break
+ }
+ if (b.inventory.length > 1 && !simulation.testing) {
+ switch (event.code) {
+ case "Digit1":
+ simulation.switchToGunInInventory(0);
+ break
+ case "Digit2":
+ simulation.switchToGunInInventory(1);
+ break
+ case "Digit3":
+ simulation.switchToGunInInventory(2);
+ break
+ case "Digit4":
+ simulation.switchToGunInInventory(3);
+ break
+ case "Digit5":
+ simulation.switchToGunInInventory(4);
+ break
+ case "Digit6":
+ simulation.switchToGunInInventory(5);
+ break
+ case "Digit7":
+ simulation.switchToGunInInventory(6);
+ break
+ case "Digit8":
+ simulation.switchToGunInInventory(7);
+ break
+ case "Digit9":
+ simulation.switchToGunInInventory(8);
+ break
+ case "Digit0":
+ simulation.switchToGunInInventory(9);
+ break
+ case "Minus":
+ simulation.switchToGunInInventory(10);
+ break
+ case "Equal":
+ simulation.switchToGunInInventory(11);
+ break
+ }
+ }
+
+ if (simulation.testing) {
+ if (event.key === "X") m.death(); //only uppercase
+ switch (event.key.toLowerCase()) {
+ case "o":
+ simulation.isAutoZoom = false;
+ simulation.zoomScale /= 0.9;
+ simulation.setZoom();
+ break;
+ case "i":
+ simulation.isAutoZoom = false;
+ simulation.zoomScale *= 0.9;
+ simulation.setZoom();
+ break
+ case "`":
+ powerUps.directSpawn(simulation.mouseInGame.x, simulation.mouseInGame.y, "research");
+ break
+ case "1":
+ powerUps.directSpawn(simulation.mouseInGame.x, simulation.mouseInGame.y, "heal");
+ break
+ case "2":
+ powerUps.directSpawn(simulation.mouseInGame.x, simulation.mouseInGame.y, "ammo");
+ break
+ case "3":
+ powerUps.directSpawn(simulation.mouseInGame.x, simulation.mouseInGame.y, "gun");
+ break
+ case "4":
+ powerUps.directSpawn(simulation.mouseInGame.x, simulation.mouseInGame.y, "field");
+ break
+ case "5":
+ powerUps.directSpawn(simulation.mouseInGame.x, simulation.mouseInGame.y, "tech");
+ break
+ case "6":
+ spawn.bodyRect(simulation.mouseInGame.x, simulation.mouseInGame.y, 50, 50);
+ break
+ case "7":
+ const pick = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)];
+ spawn[pick](simulation.mouseInGame.x, simulation.mouseInGame.y);
+ break
+ case "8":
+ spawn.randomLevelBoss(simulation.mouseInGame.x, simulation.mouseInGame.y);
+ break
+ case "f":
+ const mode = (m.fieldMode === m.fieldUpgrades.length - 1) ? 0 : m.fieldMode + 1
+ m.setField(mode)
+ break
+ case "g":
+ b.giveGuns("all", 1000)
+ break
+ case "h":
+ // m.health = Infinity
+ if (m.immuneCycle === Infinity) {
+ m.immuneCycle = 0 //you can't take damage
+ } else {
+ m.immuneCycle = Infinity //you can't take damage
+ }
+
+ // m.energy = Infinity
+ // document.getElementById("health").style.display = "none"
+ // document.getElementById("health-bg").style.display = "none"
+ break
+ case "n":
+ m.addHealth(Infinity)
+ m.energy = m.maxEnergy
+ break
+ case "y":
+ tech.giveTech()
+ break
+ case "b":
+ tech.isRerollDamage = true
+ powerUps.research.changeRerolls(1000000)
+ break
+ case "r":
+ m.resetHistory();
+ Matter.Body.setPosition(player, simulation.mouseInGame);
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: 0
+ });
+ // move bots to player
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ break
+ case "u":
+ level.nextLevel();
+ break
+ case "j":
+ for (let i = 0, len = mob.length; i < len; ++i) mob[i].damage(Infinity, true)
+ setTimeout(() => {
+ for (let i = 0, len = mob.length; i < len; ++i) mob[i].damage(Infinity, true)
+ }, 100);
+ setTimeout(() => {
+ for (let i = 0, len = mob.length; i < len; ++i) mob[i].damage(Infinity, true)
+ }, 200);
+ break
+ case "l":
+ document.getElementById("field").style.display = "none"
+ document.getElementById("guns").style.display = "none"
+ document.getElementById("tech").style.display = "none"
+ break
+ }
+ }
+});
+//mouse move input
+document.body.addEventListener("mousemove", (e) => {
+ simulation.mouse.x = e.clientX;
+ simulation.mouse.y = e.clientY;
+});
+
+document.body.addEventListener("mouseup", (e) => {
+ // input.fire = false;
+ // console.log(e)
+ if (e.button === 0) {
+ input.fire = false;
+ } else if (e.button === 2) {
+ input.field = false;
+ }
+});
+
+document.body.addEventListener("mousedown", (e) => {
+ if (e.button === 0) {
+ input.fire = true;
+ } else if (e.button === 2) {
+ input.field = true;
+ }
+});
+
+document.body.addEventListener("mouseenter", (e) => { //prevents mouse getting stuck when leaving the window
+ if (e.button === 1) {
+ input.fire = true;
+ } else {
+ input.fire = false;
+ }
+
+ if (e.button === 3) {
+ input.field = true;
+ } else {
+ input.field = false;
+ }
+});
+document.body.addEventListener("mouseleave", (e) => { //prevents mouse getting stuck when leaving the window
+ if (e.button === 1) {
+ input.fire = true;
+ } else {
+ input.fire = false;
+ }
+
+ if (e.button === 3) {
+ input.field = true;
+ } else {
+ input.field = false;
+ }
+});
+
+document.body.addEventListener("wheel", (e) => {
+ if (!simulation.paused) {
+ if (e.deltaY > 0) {
+ simulation.nextGun();
+ } else {
+ simulation.previousGun();
+ }
+ }
+}, {
+ passive: true
+});
+
+//**********************************************************************
+// local storage
+//**********************************************************************
+let localSettings
+
+function localStorageCheck() {
+ try {
+ return 'localStorage' in window && window['localStorage'] !== null;
+ } catch (e) {
+ return false;
+ }
+
+}
+if (localStorageCheck()) {
+ localSettings = JSON.parse(localStorage.getItem("localSettings"))
+ if (localSettings) {
+ console.log('localStorage is enabled')
+ localSettings.isAllowed = true
+ localSettings.isEmpty = false
+ } else {
+ console.log('localStorage is enabled, local settings empty')
+ localSettings = {
+ isAllowed: true,
+ isEmpty: true
+ }
+ }
+} else {
+ console.log("localStorage is disabled")
+ localSettings = {
+ isAllowed: false
+ }
+}
+
+if (localSettings.isAllowed && !localSettings.isEmpty) {
+ console.log('restoring previous settings')
+
+ if (localSettings.key) {
+ input.key = localSettings.key
+ } else {
+ input.setDefault()
+ }
+
+ if (localSettings.loreCount === undefined) {
+ localSettings.loreCount = 0
+ localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ }
+
+ simulation.isCommunityMaps = localSettings.isCommunityMaps
+ document.getElementById("community-maps").checked = localSettings.isCommunityMaps
+
+ if (localSettings.difficultyMode === undefined) localSettings.difficultyMode = "2"
+ simulation.difficultyMode = localSettings.difficultyMode
+ lore.setTechGoal()
+ document.getElementById("difficulty-select").value = localSettings.difficultyMode
+
+ if (localSettings.fpsCapDefault === undefined) localSettings.fpsCapDefault = 'max'
+ if (localSettings.personalSeeds === undefined) localSettings.personalSeeds = [];
+ if (localSettings.fpsCapDefault === 'max') {
+ simulation.fpsCapDefault = 999999999;
+ } else {
+ simulation.fpsCapDefault = Number(localSettings.fpsCapDefault)
+ }
+ document.getElementById("fps-select").value = localSettings.fpsCapDefault
+
+ if (!localSettings.banList) localSettings.banList = ""
+ if (localSettings.banList.length === 0 || localSettings.banList === "undefined") {
+ localSettings.banList = ""
+ localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ }
+ document.getElementById("banned").value = localSettings.banList
+
+ if (!localSettings.isLoreDoesNotNeedReset) {
+ localSettings.isLoreDoesNotNeedReset = true
+ localSettings.loreCount = 0; //this sets what conversation is heard
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ }
+ if (localSettings.isHideImages === undefined) localSettings.isHideImages = true //default to hide images
+ document.getElementById("hide-images").checked = localSettings.isHideImages
+
+ if (localSettings.isHideHUD === undefined) localSettings.isHideHUD = false
+ document.getElementById("hide-hud").checked = localSettings.isHideHUD
+
+} else {
+ console.log('setting default localSettings')
+ const isAllowed = localSettings.isAllowed //don't overwrite isAllowed value
+ localSettings = {
+ banList: "",
+ isAllowed: isAllowed,
+ personalSeeds: [],
+ isJunkExperiment: false,
+ isCommunityMaps: false,
+ difficultyMode: '2',
+ fpsCapDefault: 'max',
+ runCount: 0,
+ isTrainingNotAttempted: true,
+ levelsClearedLastGame: 0,
+ loreCount: 0,
+ isLoreDoesNotNeedReset: false,
+ isHuman: false,
+ key: undefined,
+ isHideImages: true, //default to hide images
+ isHideHUD: false,
+ };
+ input.setDefault()
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ document.getElementById("community-maps").checked = localSettings.isCommunityMaps
+ simulation.isCommunityMaps = localSettings.isCommunityMaps
+ document.getElementById("hide-images").checked = localSettings.isHideImages
+ document.getElementById("difficulty-select").value = localSettings.difficultyMode
+ document.getElementById("fps-select").value = localSettings.fpsCapDefault
+ document.getElementById("banned").value = localSettings.banList
+}
+document.getElementById("control-testing").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
+// document.getElementById("experiment-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
+
+input.controlTextUpdate()
+
+//**********************************************************************
+// settings
+//**********************************************************************
+document.getElementById("fps-select").addEventListener("input", () => {
+ let value = document.getElementById("fps-select").value
+ if (value === 'max') {
+ simulation.fpsCapDefault = 999999999;
+ } else {
+ simulation.fpsCapDefault = Number(value)
+ }
+ localSettings.fpsCapDefault = value
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+});
+
+document.getElementById("banned").addEventListener("input", () => {
+ localSettings.banList = document.getElementById("banned").value
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+});
+
+document.getElementById("community-maps").addEventListener("input", () => {
+ simulation.isCommunityMaps = document.getElementById("community-maps").checked
+ localSettings.isCommunityMaps = simulation.isCommunityMaps
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+});
+
+// difficulty-select-experiment event listener is set in build.makeGrid
+document.getElementById("difficulty-select").addEventListener("input", () => {
+ simulation.difficultyMode = Number(document.getElementById("difficulty-select").value)
+ lore.setTechGoal()
+ localSettings.difficultyMode = simulation.difficultyMode
+ localSettings.levelsClearedLastGame = 0 //after changing difficulty, reset run history
+ localSettings.entanglement = undefined //after changing difficulty, reset stored tech
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+});
+
+
+document.getElementById("updates").addEventListener("toggle", function () {
+ function loadJSON(path, success, error) { //generic function to get JSON
+ var xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState === XMLHttpRequest.DONE) {
+ if (xhr.status === 200) {
+ if (success)
+ success(JSON.parse(xhr.responseText));
+ } else {
+ if (error)
+ error(xhr);
+ }
+ }
+ };
+ xhr.open("GET", path, true);
+ xhr.send();
+ }
+ let text = `
n-gon :
todo list and complete
change-log `
+ document.getElementById("updates-div").innerHTML = text
+
+ /// https://api.github.com/repos/landgreen/n-gon/stats/commit_activity
+ loadJSON('https://api.github.com/repos/landgreen/n-gon/commits',
+ function (data) {
+ // console.log(data)
+ for (let i = 0, len = 20; i < len; i++) {
+ text += "
" + data[i].commit.author.date.substr(0, 10) + " - "; //+ "
"
+ text += data[i].commit.message
+ if (i < len - 1) text += "
"
+ }
+ document.getElementById("updates-div").innerHTML = text.replace(/\n/g, "
")
+ },
+ function (xhr) {
+ console.error(xhr);
+ }
+ );
+})
+const sound = {
+ tone(frequency, end = 1000, gain = 0.05) {
+ const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); //setup audio context
+ const oscillator = audioCtx.createOscillator();
+ const gainNode = audioCtx.createGain();
+ gainNode.gain.value = gain; //controls volume
+ oscillator.connect(gainNode);
+ gainNode.connect(audioCtx.destination);
+ oscillator.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
+ oscillator.frequency.value = frequency; // value in hertz
+ oscillator.start();
+ setTimeout(() => {
+ audioCtx.suspend()
+ audioCtx.close()
+ }, end)
+ // return audioCtx
+ },
+ portamento(frequency, end = 1000, shiftRate = 10, gain = 0.05) {
+ const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); //setup audio context
+ const oscillator = audioCtx.createOscillator();
+ const gainNode = audioCtx.createGain();
+ gainNode.gain.value = gain; //controls volume
+ oscillator.connect(gainNode);
+ gainNode.connect(audioCtx.destination);
+ oscillator.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
+ oscillator.frequency.value = frequency; // value in hertz
+ oscillator.start();
+ for (let i = 0, len = end * 0.1; i < len; i++) oscillator.frequency.setValueAtTime(frequency + i * shiftRate, audioCtx.currentTime + i * 0.01);
+ setTimeout(() => {
+ audioCtx.suspend()
+ audioCtx.close()
+ }, end)
+ // return audioCtx
+ }
+}
+
+// preload images so they load cleaner
+// MDN Scripting and preloads - https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload
+// if (!localSettings.isHideImages) {
+// for (let i = 0, len = b.guns.length; i < len; i++) {
+// const preloadLink = document.createElement("link");
+// preloadLink.href = "img/gun/" + b.guns[i].name + ".webp";
+// preloadLink.rel = "preload";
+// preloadLink.as = "image";
+// document.head.appendChild(preloadLink);
+// }
+// for (let i = 1, len = m.fieldUpgrades.length; i < len; i++) {
+// const preloadLink = document.createElement("link");
+// preloadLink.href = "img/field/" + m.fieldUpgrades[i].name + ".webp";
+// preloadLink.rel = "preload";
+// preloadLink.as = "image";
+// document.head.appendChild(preloadLink);
+// }
+// for (let i = 0, len = tech.tech.length; i < len; i++) {
+// if (!tech.tech[i].isJunk) {
+// const preloadLink = document.createElement("link");
+// preloadLink.href = "img/" + tech.tech[i].name + ".webp";
+// preloadLink.rel = "preload";
+// preloadLink.as = "image";
+// document.head.appendChild(preloadLink);
+// }
+// }
+// }
+
+
+//preload images early
+if (!localSettings.isHideImages) {
+ addEventListener("load", () => {
+ let urls = new Array()
+ for (let i = 0, len = b.guns.length; i < len; i++) urls.push("img/gun/" + b.guns[i].name + ".webp")
+ for (let i = 1, len = m.fieldUpgrades.length; i < len; i++) urls.push("img/field/" + m.fieldUpgrades[i].name + ".webp")
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (!tech.tech[i].isJunk && !tech.tech[i].isLore) urls.push("img/" + tech.tech[i].name + ".webp")
+ }
+ let images = new Array()
+ for (let i = 0; i < urls.length; i++) {
+ images[i] = new Image()
+ images[i].src = urls[i]
+ }
+ // console.log(urls, images)
+ });
+ document.getElementById("choose-grid").classList.add('choose-grid');
+} else {
+ document.getElementById("choose-grid").classList.add('choose-grid-no-images');
+}
+
+
+//**********************************************************************
+// main loop
+//**********************************************************************
+simulation.loop = simulation.normalLoop;
+
+function cycle() {
+ if (!simulation.paused) requestAnimationFrame(cycle);
+ const now = Date.now();
+ const elapsed = now - simulation.then; // calc elapsed time since last loop
+ if (elapsed > simulation.fpsInterval) { // if enough time has elapsed, draw the next frame
+ simulation.then = now - (elapsed % simulation.fpsInterval); // Get ready for next frame by setting then=now. Also, adjust for fpsInterval not being multiple of 16.67
+
+ simulation.cycle++; //tracks game cycles
+ m.cycle++; //tracks player cycles //used to alow time to stop for everything, but the player
+ if (simulation.clearNow) {
+ simulation.clearNow = false;
+ simulation.clearMap();
+ level.start();
+ }
+ simulation.loop();
+ }
+}
+
+// function cycle() {
+// if (!simulation.paused) requestAnimationFrame(cycle);
+// const now = Date.now();
+// const elapsed = now - simulation.then; // calc elapsed time since last loop
+// if (elapsed > simulation.fpsInterval) { // if enough time has elapsed, draw the next frame
+// simulation.then = now - (elapsed % simulation.fpsInterval); // Get ready for next frame by setting then=now. Also, adjust for fpsInterval not being multiple of 16.67
+
+// simulation.cycle++; //tracks game cycles
+// m.cycle++; //tracks player cycles //used to alow time to stop for everything, but the player
+// if (simulation.clearNow) {
+// simulation.clearNow = false;
+// simulation.clearMap();
+// level.start();
+// }
+// simulation.loop();
+// }
+// }
+
+// let timeStart = performance.now()
+// //0, 16.6666666666, 33.333333333333, 50.000000000
+// function cycle(timestamp) {
+// if (!simulation.paused) requestAnimationFrame(cycle);
+// if (timestamp - timeStart > 0) { //simulation.fpsInterval) { // if enough time has elapsed, draw the next frame
+// console.log(timestamp - timeStart)
+// timeStart = timestamp
+// simulation.cycle++; //tracks game cycles
+// m.cycle++; //tracks player cycles //used to alow time to stop for everything, but the player
+// if (simulation.clearNow) {
+// simulation.clearNow = false;
+// simulation.clearMap();
+// level.start();
+// }
+// simulation.loop();
+// }
+// }
+
+// let count = 1
+// let timeStart = performance.now()
+// const cycle = (timestamp) => {
+// // if (timeStart === undefined) timeStart = timestamp
+// // console.log(timestamp, timeStart)
+// if (timestamp - timeStart > tech.brainStormDelay * count) {
+// count++
+// powerUps.tech.effect();
+// document.getElementById("choose-grid").style.pointerEvents = "auto"; //turn off the normal 500ms delay
+// document.body.style.cursor = "auto";
+// document.getElementById("choose-grid").style.transitionDuration = "0s";
+// }
+// if (count < 5 && simulation.isChoosing) {
+// requestAnimationFrame(cycle);
+// } else {
+// tech.isBrainstormActive = false
+// }
+// }
+// requestAnimationFrame(cycle);
\ No newline at end of file
diff --git a/ngon/js/level.js b/ngon/js/level.js
new file mode 100644
index 00000000..76ae11ec
--- /dev/null
+++ b/ngon/js/level.js
@@ -0,0 +1,31701 @@
+let body = []; //non static bodies
+let map = []; //all static bodies
+let cons = []; //all constraints between a point and a body
+let consBB = []; //all constraints between two bodies
+let composite = [] //rotors and other map elements that don't fit
+const level = {
+ defaultZoom: 1400,
+ onLevel: -1,
+ levelsCleared: 0,
+ // playableLevels: ["pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion"],
+ //see level.populateLevels: (intro, ... , reservoir or factory, reactor, ... , gauntlet, final) added later
+ playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock"],
+ communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "dojo", "tlinat", "ruins", "ace", "crimsonTowers"],
+ trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon", "diamagnetism"],
+ levels: [],
+ start() {
+ if (level.levelsCleared === 0) { //this code only runs on the first level
+ // simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode
+ // simulation.isHorizontalFlipped = true
+ // tech.giveTech("performance")
+ // level.difficultyIncrease(3 * 4) //30 is near max on hard //60 is near max on why
+ // spawn.setSpawnList();
+ // spawn.setSpawnList();
+ // m.maxHealth = m.health = 100
+ // tech.isRerollDamage = true
+ // powerUps.research.changeRerolls(99999)
+ // m.immuneCycle = Infinity //you can't take damage
+ // tech.tech[297].frequency = 100
+ // m.couplingChange(10)
+ // m.setField("molecular assembler") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole
+ // m.energy = 0
+ // simulation.molecularMode = 2
+ // m.damage(0.1);
+ // b.giveGuns("super balls") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
+ // b.giveGuns("drones") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
+ // b.guns[3].ammo = 100000000
+ // requestAnimationFrame(() => { tech.giveTech("MACHO") });
+ // for (let i = 0; i < 1; ++i) tech.giveTech("additive manufacturing")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("dark star")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("foam-bot")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("nail-bot")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("sound-bot upgrade")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("nail-bot upgrade")
+ // requestAnimationFrame(() => { for (let i = 0; i < 30; i++) tech.giveTech("laser-bot") });
+ // for (let i = 0; i < 1; i++) tech.giveTech("laser-bot upgrade")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("uncertainty principle")
+ // for (let i = 0; i < 1; ++i) tech.giveTech("mechanical resonance")
+ // for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech");
+ // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research");
+ // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling");
+ // level.testing();
+
+ // for (let i = 0; i < 10; ++i) spawn.sniper(1900, -500)
+ // for (let i = 0; i < 1; ++i) spawn.slasher2(1900, -500)
+ // for (let i = 0; i < 1; ++i) spawn.shooterBoss(1900, -2500)
+ // spawn.suckerBoss(1900, -500, 25)
+ // spawn.slasher2(2000, -1150)
+ // spawn.zombie(-3000, -500 + 300 * Math.random(), 30, 5, "white") // zombie(x, y, radius, sides, color)
+ // for (let i = 0; i < 20; ++i) spawn.starter(1000 + 1000 * Math.random(), -500 + 300 * Math.random())
+ // tech.addJunkTechToPool(2)
+ // tech.tech[322].frequency = 100
+ // spawn.tetherBoss(1900, -500, { x: 1900, y: -500 })
+ // for (let i = 0; i < 40; ++i) tech.giveTech()
+
+ level[simulation.isTraining ? "walk" : "intro"]() //normal starting level **************************************************
+
+ // simulation.isAutoZoom = false; //look in close
+ // simulation.zoomScale *= 0.5;
+ // simulation.setZoom();
+ // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech");
+ // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "boost");
+ // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "heal");
+ // for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "field", false);
+ //lore testing
+ // for (let i = 0; i < 5; i++) tech.giveTech("undefined")
+ // lore.techCount = 2
+ // simulation.isCheating = false //true;
+ // level.levelsCleared = 10
+ // localSettings.loreCount = 5 //this sets what conversation is heard
+ // if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ // level.onLevel = -1 //this sets level.levels[level.onLevel] = undefined which is required to run the conversation
+ // level.null()
+ // localSettings.isHuman = true
+ // tech.isNoDraftPause = false //disable pause
+ // mobs.mobDeaths = 200 //to prevent pacifist mode
+ // for (let i = 0; i < 13; i++) level.nextLevel(); //jump to final boss
+ // lore.unlockTesting();
+ // tech.giveTech("tinker"); //show junk tech in experiment mode
+ // m.storeTech()
+ // powerUps.spawn(m.pos.x, m.pos.y, "entanglement", false);
+ } else {
+ spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
+
+ // spawn.pickList = ["focuser", "focuser"]
+ level[level.levels[level.onLevel]](); //picks the current map from the the levels array
+ if (!simulation.isCheating && !build.isExperimentRun && !simulation.isTraining) {
+ localSettings.runCount += level.levelsCleared //track the number of total runs locally
+ localSettings.levelsClearedLastGame = level.levelsCleared
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ }
+ }
+ if (!simulation.isTraining) level.levelAnnounce();
+ simulation.noCameraScroll();
+ simulation.setZoom();
+ level.addToWorld(); //add bodies to game engine
+ simulation.draw.setPaths();
+ b.respawnBots();
+ m.resetHistory();
+
+ if (tech.isForeverDrones) {
+ if (tech.isDroneRadioactive) {
+ for (let i = 0; i < tech.isForeverDrones * 0.25; i++) {
+ b.droneRadioactive({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5)
+ bullet[bullet.length - 1].endCycle = Infinity
+ }
+ } else {
+ for (let i = 0; i < tech.isForeverDrones; i++) {
+ b.drone({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5)
+ bullet[bullet.length - 1].endCycle = Infinity
+ }
+ }
+ }
+ if (tech.isMACHO) spawn.MACHO()
+ for (let i = 0; i < tech.wimpCount; i++) {
+ spawn.WIMP()
+ mob[mob.length - 1].isDecoupling = true //so you can find it to remove
+ for (let j = 0, len = 4; j < len; j++) powerUps.spawn(level.exit.x + 100 * (Math.random() - 0.5), level.exit.y - 100 + 100 * (Math.random() - 0.5), "research", false)
+ }
+ // if (tech.isFlipFlopLevelReset && !tech.isFlipFlopOn) {
+ if ((tech.isRelay || tech.isFlipFlop) && !tech.isFlipFlopOn) {
+ tech.isFlipFlopOn = true
+ if (tech.isFlipFlopHealth) m.setMaxHealth()
+ if (tech.isRelayEnergy) m.setMaxEnergy()
+ m.eyeFillColor = m.fieldMeterColor
+ simulation.makeTextLog(`tech.isFlipFlopOn
= true`);
+ }
+ // if (m.plasmaBall) m.plasmaBall.reset()
+ if (m.plasmaBall) m.plasmaBall.fire()
+ if (localSettings.entanglement && localSettings.entanglement.levelName === level.levels[level.onLevel]) {
+ const flip = localSettings.entanglement.isHorizontalFlipped === simulation.isHorizontalFlipped ? 1 : -1
+ powerUps.directSpawn(flip * localSettings.entanglement.position.x, localSettings.entanglement.position.y, "entanglement", false);
+ }
+ level.newLevelOrPhase()
+ },
+ newLevelOrPhase() { //runs on each new level but also on final boss phases
+ //used for generalist and pigeonhole principle
+ tech.buffedGun++
+ if (tech.buffedGun > b.inventory.length - 1) tech.buffedGun = 0;
+ if (tech.isGunCycle && b.activeGun !== null && b.inventory.length) {
+ b.inventoryGun = tech.buffedGun;
+ simulation.switchGun();
+ }
+ if (tech.isGunChoice && Number.isInteger(tech.buffedGun) && b.inventory.length) {
+ var gun = b.guns[b.inventory[tech.buffedGun]].name
+ simulation.makeTextLog(`pigeonhole principle:
+${(31 * Math.max(0, b.inventory.length)).toFixed(0)}% damage for
${gun} `, 600);
+ }
+ if (tech.isSwitchReality && level.levelsCleared !== 0) {
+ simulation.makeTextLog(`simulation.amplitude
= ${Math.random()}`);
+ m.switchWorlds()
+ simulation.trails()
+ powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "tech", false);
+ }
+ if (tech.isHealLowHealth) {
+ if (tech.isEnergyHealth) {
+ var len = 4 * (1 - m.energy / m.maxEnergy) //as a percent
+ } else {
+ var len = 4 * (1 - m.health / m.maxHealth) //as a percent
+ }
+ for (let i = 0; i < len; i++) powerUps.spawn(player.position.x + 90 * (Math.random() - 0.5), player.position.y + 90 * (Math.random() - 0.5), "heal", false);
+ }
+ },
+ trainingText(say) {
+ simulation.lastLogTime = 0; //clear previous messages
+ simulation.isTextLogOpen = true
+ simulation.makeTextLog(`
supervised.learning (${(Date.now() / 1000).toFixed(0)} s ): ${say}`, Infinity)
+ simulation.isTextLogOpen = false
+ // lore.trainer.text("Wow. Just a platform.")
+ },
+ trainingBackgroundColor: "#e1e1e1",
+ custom() { },
+ customTopLayer() { },
+ setDifficulty() {
+ simulation.difficulty = 0
+ m.dmgScale = 1; //damage done by player decreases each level
+ simulation.accelScale = 1 //mob acceleration increases each level
+ simulation.CDScale = 1 //mob CD time decreases each level
+ simulation.dmgScale = Math.max(0.1, 0.29 * simulation.difficulty) //damage done by mobs scales with total levels
+ simulation.healScale = 1 / (1 + simulation.difficulty * 0.045) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
+ },
+ difficultyIncrease(num = 1) {
+ for (let i = 0; i < num; i++) {
+ simulation.difficulty++
+ m.dmgScale *= 0.905; //damage done by player decreases each level
+ if (simulation.accelScale < 6) simulation.accelScale *= 1.024 //mob acceleration increases each level
+ if (simulation.CDScale > 0.15) simulation.CDScale *= 0.964 //mob CD time decreases each level
+ }
+ simulation.dmgScale = Math.max(0.1, 0.285 * simulation.difficulty) //damage done by mobs scales with total levels
+ simulation.healScale = 1 / (1 + simulation.difficulty * 0.045) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
+ // console.log(`CD = ${simulation.CDScale}`)
+ },
+ difficultyDecrease(num = 1) { //used in easy mode for simulation.reset()
+ for (let i = 0; i < num; i++) {
+ simulation.difficulty--
+ m.dmgScale /= 0.905; //damage done by player decreases each level
+ if (simulation.accelScale > 1) simulation.accelScale /= 1.024 //mob acceleration increases each level
+ if (simulation.CDScale < 1) simulation.CDScale /= 0.964 //mob CD time decreases each level
+ }
+ if (simulation.difficulty < 1) simulation.difficulty = 0;
+ simulation.dmgScale = Math.max(0.1, 0.285 * simulation.difficulty) //damage done by mobs scales with total levels
+ simulation.healScale = 1 / (1 + simulation.difficulty * 0.045)
+ },
+ difficultyText() {
+ if (simulation.difficultyMode === 1) {
+ return "easy"
+ } else if (simulation.difficultyMode === 2) {
+ return "normal"
+ } else if (simulation.difficultyMode === 4) {
+ return "hard"
+ } else if (simulation.difficultyMode === 6) {
+ return "why"
+ }
+ },
+ levelAnnounce() {
+ const difficulty = simulation.isCheating ? "testing" : level.difficultyText()
+ if (level.levelsCleared === 0) {
+ document.title = "n-gon: (" + difficulty + ")";
+ } else {
+ document.title = `n-gon: ${level.levelsCleared} ${level.levels[level.onLevel]} (${difficulty})`
+ simulation.makeTextLog(`
level .onLevel
= "
${level.levels[level.onLevel]} "`);
+ }
+ // simulation.makeTextLog(`
+ // input.key.up = ["
${input.key.up} ", "
ArrowUp "]
+ //
input.key.left = ["
${input.key.left} ", "
ArrowLeft "]
+ //
input.key.down = ["
${input.key.down} ", "
ArrowDown "]
+ //
input.key.right = ["
${input.key.right} ", "
ArrowRight "]
+ //
+ //
m .fieldMode = "
${m.fieldUpgrades[m.fieldMode].name} "
+ //
input.key.field = ["
${input.key.field} ", "
right mouse "]
+ //
m .field.description = "
${m.fieldUpgrades[m.fieldMode].description} "
+ // `, 1200);
+ },
+ disableExit: false,
+ nextLevel() {
+ if (!level.disableExit) {
+ level.levelsCleared++;
+ level.onLevel++; //cycles map to next level
+ if (simulation.isTraining) {
+ if (level.onLevel > level.levels.length - 1) {
+ level.disableExit = true
+ document.getElementById("health").style.display = "none"
+ document.getElementById("health-bg").style.display = "none"
+ document.getElementById("defense-bar").style.display = "none"
+ document.getElementById("damage-bar").style.display = "none"
+ document.getElementById("text-log").style.display = "none"
+ document.getElementById("fade-out").style.opacity = 1; //slowly fades out
+ setTimeout(function () {
+ simulation.paused = true;
+ level.disableExit = false;
+ engine.world.bodies.forEach((body) => {
+ Matter.Composite.remove(engine.world, body)
+ })
+ Engine.clear(engine);
+ simulation.splashReturn();
+ }, 6000);
+ return
+ } else {
+ level.setDifficulty()
+ }
+ } else {
+ if (level.onLevel > level.levels.length - 1) level.onLevel = 0;
+ level.difficultyIncrease(simulation.difficultyMode)
+ }
+
+ //reset lost tech display
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].isLost) tech.tech[i].isLost = false;
+ }
+ tech.isDeathAvoidedThisLevel = false;
+ simulation.updateTechHUD();
+ simulation.clearNow = true; //triggers in simulation.clearMap to remove all physics bodies and setup for new map
+ }
+ },
+ populateLevels() { //run a second time if URL is loaded
+ if (document.getElementById("banned").value) { //remove levels from ban list in settings
+ const banList = document.getElementById("banned").value.replace(/,/g, ' ').replace(/\s\s+/g, ' ').replace(/[^\w\s]/g, '') //replace commas with spaces, replace double spaces with single, remove strange symbols
+ const remove = banList.split(" ");
+ // console.log('remove these', remove)
+ // console.log('community levels before', level.communityLevels)
+ for (let i = 0; i < remove.length; i++) {
+ const index = level.communityLevels.indexOf(remove[i])
+ if (index !== -1) {
+ level.communityLevels.splice(index, 1);
+ // console.log('removed level:', remove[i])
+ requestAnimationFrame(() => { simulation.makeTextLog(`banned level:
${remove[i]} `); });
+ }
+ }
+ // console.log('community levels after', level.communityLevels)
+ // console.log('Landgreen levels before', level.playableLevels)
+ for (let i = 0; i < remove.length; i++) {
+ if (level.playableLevels.length + level.communityLevels.length * simulation.isCommunityMaps < 10) break //can't remove too many levels
+ const index = level.playableLevels.indexOf(remove[i])
+ if (index !== -1) {
+ level.playableLevels.splice(index, 1);
+ // console.log('removed level:', remove[i])
+ requestAnimationFrame(() => { simulation.makeTextLog(`banned level:
${remove[i]} `); });
+ }
+ }
+ // console.log('Landgreen levels after', level.playableLevels)
+ }
+
+ if (document.getElementById("seed").value) { //check for player entered seed in settings
+ Math.initialSeed = String(document.getElementById("seed").value)
+ Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it
+ }
+
+ if (simulation.isTraining) {
+ simulation.isHorizontalFlipped = false
+ level.levels = level.trainingLevels.slice(0) //copy array, not by just by assignment
+ } else { //add remove and shuffle levels for the normal game (not training levels)
+ level.levels = level.playableLevels.slice(0) //copy array, not by just by assignment
+ if (simulation.isCommunityMaps) {
+ level.levels = level.levels.concat(level.communityLevels)
+ simulation.isHorizontalFlipped = false;
+ } else {
+ simulation.isHorizontalFlipped = (Math.seededRandom() < 0.5) ? true : false //if true, some maps are flipped horizontally
+ }
+ level.levels = shuffle(level.levels); //shuffles order of maps with seeded random
+ level.levels.length = 9 //remove any extra levels past 9
+ level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.6, level.levels.length)), 0, Math.random() < 0.5 ? "factory" : "reservoir"); //add level to the back half of the randomized levels list
+ level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.6, level.levels.length)), 0, "reactor"); //add level to the back half of the randomized levels list
+ if (!build.isExperimentSelection || (build.hasExperimentalMode && !simulation.isCheating)) { //experimental mode is endless, unless you only have an experiment Tech
+ level.levels.unshift("intro"); //add level to the start of the randomized levels list
+ level.levels.push("subway"); //add level to the end of the randomized levels list
+ level.levels.push("final"); //add level to the end of the randomized levels list
+ }
+ }
+ //set seeded random lists of mobs and bosses
+ spawn.mobTypeSpawnOrder = []
+ for (let i = 0; i < level.levels.length; i++) spawn.mobTypeSpawnOrder.push(spawn.fullPickList[Math.floor(Math.seededRandom(0, spawn.fullPickList.length))])
+ spawn.bossTypeSpawnOrder = []
+ for (let i = 0; i < level.levels.length * 2; i++) spawn.bossTypeSpawnOrder.push(spawn.randomBossList[Math.floor(Math.seededRandom(0, spawn.randomBossList.length))])
+ },
+ flipHorizontal() {
+ const flipX = (who) => {
+ for (let i = 0, len = who.length; i < len; i++) {
+ Matter.Body.setPosition(who[i], {
+ x: -who[i].position.x,
+ y: who[i].position.y
+ })
+ }
+ }
+ flipX(map)
+ flipX(body)
+ flipX(mob)
+ flipX(powerUp)
+ for (let i = 0, len = cons.length; i < len; i++) {
+ cons[i].pointA.x *= -1
+ cons[i].pointB.x *= -1
+ }
+ for (let i = 0, len = consBB.length; i < len; i++) {
+ consBB[i].pointA.x *= -1
+ consBB[i].pointB.x *= -1
+ }
+ level.exit.x = -level.exit.x - 100 //minus the 100 because of the width of the graphic
+ },
+ exitCount: 0,
+ // playerExitCheck() {
+ // if (
+ // player.position.x > level.exit.x &&
+ // player.position.x < level.exit.x + 100 &&
+ // player.position.y > level.exit.y - 150 &&
+ // player.position.y < level.exit.y - 40 &&
+ // player.velocity.y < 0.1
+ // ) {
+ // level.exitCount++
+ // if (level.exitCount > 120) {
+ // level.exitCount = 0
+ // level.nextLevel()
+ // }
+ // }
+ // },
+ setPosToSpawn(xPos, yPos) {
+ m.spawnPos.x = m.pos.x = xPos;
+ m.spawnPos.y = m.pos.y = yPos;
+ level.enter.x = m.spawnPos.x - 50;
+ level.enter.y = m.spawnPos.y + 20;
+ m.transX = m.transSmoothX = canvas.width2 - m.pos.x;
+ m.transY = m.transSmoothY = canvas.height2 - m.pos.y;
+ m.Vx = m.spawnVel.x;
+ m.Vy = m.spawnVel.y;
+ player.force.x = 0;
+ player.force.y = 0;
+ Matter.Body.setPosition(player, m.spawnPos);
+ Matter.Body.setVelocity(player, m.spawnVel);
+ //makes perfect diamagnetism tech: Lenz's law show up in the right spot at the start of a level
+ m.fieldPosition = {
+ x: m.pos.x,
+ y: m.pos.y
+ }
+ m.fieldAngle = m.angle
+ },
+ enter: {
+ x: 0,
+ y: 0,
+ draw() {
+ ctx.beginPath();
+ ctx.moveTo(level.enter.x, level.enter.y + 30);
+ ctx.lineTo(level.enter.x, level.enter.y - 80);
+ ctx.bezierCurveTo(level.enter.x, level.enter.y - 170, level.enter.x + 100, level.enter.y - 170, level.enter.x + 100, level.enter.y - 80);
+ ctx.lineTo(level.enter.x + 100, level.enter.y + 30);
+ ctx.lineTo(level.enter.x, level.enter.y + 30);
+ ctx.fillStyle = "#ccc";
+ ctx.fill();
+ }
+ },
+ exit: {
+ x: 0,
+ y: 0,
+ drawAndCheck() {
+ if ( //check
+ player.position.x > level.exit.x &&
+ player.position.x < level.exit.x + 100 &&
+ player.position.y > level.exit.y - 150 &&
+ player.position.y < level.exit.y - 0 &&
+ player.velocity.y < 0.15
+ ) {
+ // level.exitCount += input.down ? 8 : 2
+ level.exitCount += 2
+ } else if (level.exitCount > 0) {
+ level.exitCount -= 2
+ }
+
+ ctx.beginPath();
+ ctx.moveTo(level.exit.x, level.exit.y + 30);
+ ctx.lineTo(level.exit.x, level.exit.y - 80);
+ ctx.bezierCurveTo(level.exit.x, level.exit.y - 170, level.exit.x + 100, level.exit.y - 170, level.exit.x + 100, level.exit.y - 80);
+ ctx.lineTo(level.exit.x + 100, level.exit.y + 30);
+ ctx.lineTo(level.exit.x, level.exit.y + 30);
+ ctx.fillStyle = "#0ff";
+ ctx.fill();
+
+ if (level.exitCount > 0) { //stroke outline of door from 2 sides, grows with count
+ ctx.beginPath();
+ ctx.moveTo(level.exit.x, level.exit.y + 40);
+ ctx.lineTo(level.exit.x, level.exit.y - 80);
+ ctx.bezierCurveTo(level.exit.x, level.exit.y - 148, level.exit.x + 50, level.exit.y - 148, level.exit.x + 50, level.exit.y - 148);
+ ctx.moveTo(level.exit.x + 100, level.exit.y + 40);
+ ctx.lineTo(level.exit.x + 100, level.exit.y - 80);
+ ctx.bezierCurveTo(level.exit.x + 100, level.exit.y - 148, level.exit.x + 50, level.exit.y - 148, level.exit.x + 50, level.exit.y - 148);
+ ctx.setLineDash([200, 200]);
+ ctx.lineDashOffset = Math.max(-15, 185 - 2.1 * level.exitCount)
+ ctx.strokeStyle = "#444"
+ ctx.lineWidth = 2
+ ctx.stroke();
+ ctx.setLineDash([0, 0]);
+
+ if (level.exitCount > 100) {
+ level.exitCount = 0
+ level.nextLevel()
+ }
+ }
+ },
+ // draw() {
+ // ctx.beginPath();
+ // ctx.moveTo(level.exit.x, level.exit.y + 30);
+ // ctx.lineTo(level.exit.x, level.exit.y - 80);
+ // ctx.bezierCurveTo(level.exit.x, level.exit.y - 170, level.exit.x + 100, level.exit.y - 170, level.exit.x + 100, level.exit.y - 80);
+ // ctx.lineTo(level.exit.x + 100, level.exit.y + 30);
+ // ctx.lineTo(level.exit.x, level.exit.y + 30);
+ // ctx.fillStyle = "#0ff";
+ // ctx.fill();
+ // }
+ },
+ addToWorld() { //needs to be run to put bodies into the world
+ for (let i = 0; i < map.length; i++) {
+ map[i].collisionFilter.category = cat.map;
+ map[i].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(map[i], true); //make static
+ Composite.add(engine.world, map[i]); //add to world
+ }
+ },
+ spinner(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0) {
+ x += width / 2
+ y += height / 2
+ const who = body[body.length] = Bodies.rectangle(x, y, width, height, {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ isNotHoldable: true,
+ frictionAir: frictionAir,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0,
+ });
+ Matter.Body.setAngle(who, angle)
+ Matter.Body.setAngularVelocity(who, angularVelocity);
+ Matter.Body.setDensity(who, density)
+ Composite.add(engine.world, who); //add to world
+ who.classType = "body"
+
+ const constraint = Constraint.create({ //fix rotor in place, but allow rotation
+ pointA: {
+ x: who.position.x,
+ y: who.position.y
+ },
+ bodyB: who,
+ stiffness: 1,
+ damping: 1
+ });
+ Composite.add(engine.world, constraint);
+ return constraint
+ },
+ rotor(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0, rotationForce = 0.0005) {
+ x += width / 2
+ y += height / 2
+ const who = body[body.length] = Bodies.rectangle(x, y, width, height, {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ isNotHoldable: true,
+ frictionAir: frictionAir,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0,
+ rotationForce: rotationForce
+ });
+ Matter.Body.setAngle(who, angle)
+ Matter.Body.setAngularVelocity(who, angularVelocity);
+
+ Matter.Body.setDensity(who, density)
+ const constraint = Constraint.create({ //fix rotor in place, but allow rotation
+ pointA: {
+ x: who.position.x,
+ y: who.position.y
+ },
+ bodyB: who,
+ stiffness: 1,
+ damping: 1
+ });
+ Composite.add(engine.world, constraint);
+ who.center = {
+ x: who.position.x,
+ y: who.position.y
+ }
+ who.rotate = function () {
+ if (!m.isBodiesAsleep) {
+ Matter.Body.applyForce(this, {
+ x: this.position.x + 100,
+ y: this.position.y + 100
+ }, {
+ x: this.rotationForce * this.mass,
+ y: 0
+ })
+ } else {
+ Matter.Body.setAngularVelocity(this, 0);
+ }
+ }
+ // if (rotate) {
+ // rotor.rotate = function() {
+ // if (!m.isBodiesAsleep) {
+ // Matter.Body.applyForce(rotor, {
+ // x: rotor.position.x + 100,
+ // y: rotor.position.y + 100
+ // }, {
+ // x: rotate * rotor.mass,
+ // y: 0
+ // })
+ // } else {
+ // Matter.Body.setAngularVelocity(rotor, 0);
+ // }
+ // }
+ // }
+
+ Composite.add(engine.world, who); //add to world
+ who.classType = "body"
+
+ return who
+ },
+ boost(x, y, height = 1000) { //height is how high the player will be flung above y
+ who = map[map.length] = Matter.Bodies.fromVertices(x + 50, y + 35, Vertices.fromPath("120 40 -120 40 -50 -40 50 -40"), {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ boostBounds: {
+ min: {
+ x: x,
+ y: y - 20
+ },
+ max: {
+ x: x + 100,
+ y: y
+ }
+ },
+ yVelocity: -1.21 * Math.sqrt(Math.abs(height)),
+ query() {
+ // check for collisions
+ query = (who) => {
+ if (Matter.Query.region(who, this.boostBounds).length > 0) {
+ list = Matter.Query.region(who, this.boostBounds)
+ Matter.Body.setVelocity(list[0], {
+ x: list[0].velocity.x + (Math.random() - 0.5) * 2.5, //add a bit of horizontal drift to reduce endless bounces
+ y: this.yVelocity //give a upwards velocity
+ });
+ }
+ }
+ query(body)
+ query(mob)
+ query(bullet)
+ query(powerUp)
+ //player collision
+ if (Matter.Query.region([player], this.boostBounds).length > 0 && !input.down) {
+ m.buttonCD_jump = 0; // reset short jump counter to prevent short jumps on boosts
+ m.hardLandCD = 0 // disable hard landing
+ if (player.velocity.y > 26) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: -15 //gentle bounce if coming down super fast
+ });
+ } else {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x + (Math.random() - 0.5) * 2.5,
+ y: this.yVelocity //give a upwards velocity that will put the player that the height desired
+ });
+ }
+ }
+
+ //draw
+ ctx.fillStyle = "rgba(200,0,255,0.15)";
+ ctx.fillRect(this.boostBounds.min.x, this.boostBounds.min.y - 10, 100, 30);
+ ctx.fillStyle = "rgba(200,0,255,0.05)";
+ ctx.fillRect(this.boostBounds.min.x, this.boostBounds.min.y - 50, 100, 70);
+ // ctx.fillStyle = "rgba(200,0,255,0.02)";
+ // ctx.fillRect(x, y - 120, 100, 120);
+ },
+ });
+ return who
+ },
+ elevator(x, y, width, height, maxHeight, force = 0.003, friction = {
+ up: 0.01,
+ down: 0.2
+ }, isAtTop = false) {
+ x += width / 2
+ y += height / 2
+ maxHeight += height / 2
+ const yTravel = maxHeight - y
+ force += simulation.g
+ const who = body[body.length] = Bodies.rectangle(x, isAtTop ? maxHeight : y, width, height, {
+ collisionFilter: {
+ category: cat.body, //cat.map,
+ mask: cat.map | cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ inertia: Infinity, //prevents rotation
+ isNotHoldable: true,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0,
+ frictionAir: 0.001,
+ holdX: x,
+ move() {
+ if (!m.isBodiesAsleep) {
+ if (this.isUp) { //moving up still with high air friction
+ this.force.y -= force * this.mass //hard force propels up, even with high friction
+
+ if (this.position.y < maxHeight) { //switch to down mode
+ this.isUp = false
+ this.frictionAir = friction.down
+ //adds a hard jerk at the top of vertical motion because it's fun
+ Matter.Body.setPosition(this, {
+ x: this.holdX,
+ y: maxHeight
+ });
+ Matter.Body.setVelocity(this, {
+ x: 0,
+ y: 0
+ });
+ }
+ } else if (this.position.y + 10 * this.velocity.y > y) { //free falling down, with only air friction
+ Matter.Body.setVelocity(this, { //slow down early to avoid a jerky stop that can pass through blocks
+ x: 0,
+ y: this.velocity.y * 0.7
+ });
+ if (this.position.y + this.velocity.y > y) { //switch to up mode
+ this.isUp = true
+ this.frictionAir = friction.up
+ }
+ }
+ Matter.Body.setVelocity(this, { x: 0, y: this.velocity.y });
+ }
+ //edge limits
+ if (this.position.y < maxHeight) {
+ Matter.Body.setPosition(this, {
+ x: this.holdX,
+ y: maxHeight
+ });
+ } else if (this.position.y > y) {
+ Matter.Body.setPosition(this, {
+ x: this.holdX,
+ y: y
+ });
+ }
+ // hold horizontal position
+ Matter.Body.setPosition(this, {
+ x: this.holdX,
+ y: this.position.y
+ });
+
+ },
+ off() {
+ Matter.Body.setPosition(this, {
+ x: this.holdX,
+ y: this.position.y
+ });
+ Matter.Body.setVelocity(this, {
+ x: 0,
+ y: this.velocity.y
+ });
+ },
+ constraint: this.null,
+ addConstraint() {
+ this.constraint = Constraint.create({
+ pointA: {
+ x: this.position.x,
+ y: this.position.y
+ },
+ bodyB: this,
+ stiffness: 0.01,
+ damping: 0.3
+ });
+ Composite.add(engine.world, this.constraint);
+ },
+ removeConstraint() {
+ Composite.remove(engine.world, this.constraint, true)
+ },
+ drawTrack() {
+ ctx.fillStyle = "#ccc"
+ ctx.fillRect(this.holdX, y, 5, yTravel)
+ }
+ });
+ Matter.Body.setDensity(who, 0.01) //10x density for added stability
+ Composite.add(engine.world, who); //add to world
+ who.classType = "body"
+ return who
+ },
+ spring(x, y, v = "-100 0 100 0 70 40 0 50 -70 40", force = 0.01, distance = 300, angle = 0) {
+ const who = body[body.length] = Matter.Bodies.fromVertices(x, y, Vertices.fromPath(v), {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ inertia: Infinity, //prevents rotation
+ isNotHoldable: true,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0,
+ frictionAir: 1,
+ density: 0.1,
+ isReady: true,
+ isResetting: false,
+ query() {
+ if (this.isReady) {
+ if (Matter.Query.collides(this, [player]).length) {
+ this.isReady = false
+ this.constraint.stiffness = 0
+ this.constraint.damping = 0 //0.3
+ this.frictionAir = 0
+ Matter.Body.setVelocity(this, {
+ x: 0,
+ y: 0
+ });
+ //show graphically being ready?
+
+ }
+ } else {
+ if (this.isResetting) {
+ this.constraint.stiffness += 0.0005
+ if (this.constraint.stiffness > 0.1) {
+ this.isResetting = false
+ this.isReady = true
+ }
+ } else {
+ if (Vector.magnitudeSquared(Vector.sub(this.position, {
+ x: x,
+ y: y
+ })) < distance * distance) {
+ this.force.y -= force * this.mass
+ } else {
+ this.constraint.damping = 1
+ this.frictionAir = 1
+ this.isResetting = true
+ Matter.Body.setVelocity(this, {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ }
+ }
+ });
+ who.constraint = Constraint.create({
+ pointA: {
+ x: who.position.x,
+ y: who.position.y
+ },
+ bodyB: who,
+ stiffness: 1,
+ damping: 1
+ });
+ Composite.add(engine.world, who.constraint);
+ return who
+ },
+ // rotor(x, y, rotate = 0, radius = 800, width = 40, density = 0.0005) {
+ // const rotor1 = Matter.Bodies.rectangle(x, y, width, radius, {
+ // density: density,
+ // isNotHoldable: true,
+ // isNonStick: true,
+ // collisionFilter: {
+ // category: cat.map,
+ // mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ // },
+ // });
+ // const rotor2 = Matter.Bodies.rectangle(x, y, width, radius, {
+ // angle: Math.PI / 2,
+ // density: density,
+ // isNotHoldable: true,
+ // isNonStick: true,
+ // collisionFilter: {
+ // category: cat.map,
+ // mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ // },
+ // });
+ // rotor = Body.create({ //combine rotor1 and rotor2
+ // parts: [rotor1, rotor2],
+ // restitution: 0,
+ // collisionFilter: {
+ // category: cat.map,
+ // mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ // },
+ // });
+ // Matter.Body.setPosition(rotor, {
+ // x: x,
+ // y: y
+ // });
+ // Composite.add(engine.world, [rotor]);
+ // body[body.length] = rotor1
+ // body[body.length] = rotor2
+
+ // // setTimeout(function() {
+ // // rotor.collisionFilter.category = cat.body;
+ // // rotor.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet //| cat.map
+ // // }, 1000);
+
+ // const constraint = Constraint.create({ //fix rotor in place, but allow rotation
+ // pointA: {
+ // x: x,
+ // y: y
+ // },
+ // bodyB: rotor
+ // });
+ // Composite.add(engine.world, constraint);
+
+ // if (rotate) {
+ // rotor.rotate = function() {
+ // if (!m.isBodiesAsleep) {
+ // Matter.Body.applyForce(rotor, {
+ // x: rotor.position.x + 100,
+ // y: rotor.position.y + 100
+ // }, {
+ // x: rotate * rotor.mass,
+ // y: 0
+ // })
+ // } else {
+ // Matter.Body.setAngularVelocity(rotor, 0);
+ // }
+ // }
+ // }
+ // composite[composite.length] = rotor
+ // return rotor
+ // },
+ toggle(x, y, isOn = false, isLockOn = false) {
+ spawn.mapVertex(x + 65, y + 2, "70 10 -70 10 -40 -10 40 -10"); //toggle platform
+ map[map.length - 1].restitution = 0;
+ map[map.length - 1].friction = 1; //
+ map[map.length - 1].frictionStatic = 1;
+ const width = 120
+ const height = 15
+ body[body.length] = Bodies.rectangle(x + width / 2, y + height / 2, width, height, { friction: 0.05, frictionAir: 0.01 });
+ let flip = body[body.length - 1];
+ flip.collisionFilter.category = cat.body
+ flip.collisionFilter.mask = cat.player | cat.body
+ flip.isNotHoldable = true
+ flip.restitution = 0
+ Matter.Body.setDensity(flip, 0.003)
+ if (isOn) {
+ Matter.Body.setAngle(flip, (0.25 - 0.5) * Math.PI)
+ } else {
+ Matter.Body.setAngle(flip, (-0.25 - 0.5) * Math.PI)
+ }
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: x + 65,
+ y: y - 5
+ },
+ bodyB: flip,
+ stiffness: 1,
+ length: 0
+ });
+ Composite.add(engine.world, [cons[cons.length - 1]]);
+ Composite.add(engine.world, flip); //add to world
+ flip.classType = "body"
+ return {
+ flip: flip,
+ isOn: isOn,
+ query() {
+ const limit = {
+ right: (-0.25 - 0.5) * Math.PI,
+ left: (0.25 - 0.5) * Math.PI
+ }
+ if (flip.angle < limit.right) {
+ Matter.Body.setAngle(flip, limit.right)
+ Matter.Body.setAngularVelocity(flip, 0);
+ if (!isLockOn) this.isOn = false
+ } else if (flip.angle > limit.left) {
+ Matter.Body.setAngle(flip, limit.left)
+ Matter.Body.setAngularVelocity(flip, 0);
+ this.isOn = true
+ }
+ if (this.isOn) {
+ ctx.beginPath();
+ ctx.moveTo(flip.vertices[0].x, flip.vertices[0].y);
+ for (let j = 1; j < flip.vertices.length; j++) {
+ ctx.lineTo(flip.vertices[j].x, flip.vertices[j].y);
+ }
+ ctx.lineTo(flip.vertices[0].x, flip.vertices[0].y);
+ ctx.fillStyle = "#3df"
+ ctx.fill();
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = color.blockS;
+ ctx.stroke();
+ }
+ },
+ }
+ },
+ button(x, y, width = 126, isSpawnBase = true) {
+ if (isSpawnBase) {
+ spawn.mapVertex(x + 65, y + 2, "100 10 -100 10 -70 -10 70 -10");
+ map[map.length - 1].restitution = 0;
+ map[map.length - 1].friction = 1;
+ map[map.length - 1].frictionStatic = 1;
+ }
+ // const buttonSensor = Bodies.rectangle(x + 35, y - 1, 70, 20, {
+ // isSensor: true
+ // });
+
+ return {
+ isUp: false,
+ min: {
+ x: x + 2,
+ y: y - 11
+ },
+ max: {
+ x: x + width,
+ y: y - 10
+ },
+ width: width,
+ height: 20,
+ query() {
+ if (Matter.Query.region(body, this).length === 0 && Matter.Query.region([player], this).length === 0) {
+ this.isUp = true;
+ } else {
+ if (this.isUp === true) {
+ const list = Matter.Query.region(body, this) //are any blocks colliding with this
+ if (list.length > 0) {
+ if (list[0].bounds.max.x - list[0].bounds.min.x < 150 && list[0].bounds.max.y - list[0].bounds.min.y < 150) { //not too big of a block
+ Matter.Body.setPosition(list[0], { //teleport block to the center of the button
+ x: this.min.x + width / 2,
+ y: list[0].position.y
+ })
+ }
+ Matter.Body.setVelocity(list[0], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ this.isUp = false;
+ }
+ },
+ query() {
+ if (Matter.Query.region(body, this).length === 0 && Matter.Query.region([player], this).length === 0) {
+ this.isUp = true;
+ } else {
+ if (this.isUp === true) {
+ const list = Matter.Query.region(body, this) //are any blocks colliding with this
+ if (list.length > 0) {
+ if (list[0].bounds.max.x - list[0].bounds.min.x < 150 && list[0].bounds.max.y - list[0].bounds.min.y < 150) { //not too big of a block
+ Matter.Body.setPosition(list[0], { //teleport block to the center of the button
+ x: this.min.x + width / 2,
+ y: list[0].position.y
+ })
+ }
+ Matter.Body.setVelocity(list[0], { x: 0, y: 0 });
+ }
+ }
+ this.isUp = false;
+ }
+ },
+ draw() {
+ ctx.fillStyle = "hsl(0, 100%, 70%)"
+ if (this.isUp) {
+ ctx.fillRect(this.min.x, this.min.y - 10, this.width, 20)
+ } else {
+ ctx.fillRect(this.min.x, this.min.y - 3, this.width, 25)
+ }
+ }
+ }
+ },
+ vanish(x, y, width, height, isVertical = false, hide = {
+ x: 0,
+ y: 150
+ }) {
+ x = x + width / 2
+ y = y + height / 2
+ const vertices = [{
+ x: x,
+ y: y,
+ index: 0,
+ isInternal: false
+ }, {
+ x: x + width,
+ y: y,
+ index: 1,
+ isInternal: false
+ }, {
+ x: x + width,
+ y: y + height,
+ index: 4,
+ isInternal: false
+ }, {
+ x: x,
+ y: y + height,
+ index: 3,
+ isInternal: false
+ }]
+ const block = body[body.length] = Bodies.fromVertices(x, y, vertices, {
+ // const block = body[body.length] = Bodies.rectangle(x, y, width, height, {
+ collisionFilter: {
+ category: cat.map,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ inertia: Infinity, //prevents rotation
+ isNotHoldable: true,
+ isNonStick: true, //this keep sporangium from sticking
+ isTouched: false,
+ fadeTime: 10 + Math.ceil(0.25 * width),
+ fadeCount: null,
+ isThere: true,
+ returnTime: 120,
+ returnCount: 0,
+ shrinkVertices(size) {
+ if (isVertical) {
+ return [{
+ x: x,
+ y: y * size,
+ index: 0,
+ isInternal: false
+ }, {
+ x: x + width,
+ y: y * size,
+ index: 1,
+ isInternal: false
+ }, {
+ x: x + width,
+ y: (y + height) * size,
+ index: 4,
+ isInternal: false
+ }, {
+ x: x,
+ y: (y + height) * size,
+ index: 3,
+ isInternal: false
+ }]
+ } else {
+ return [{
+ x: x * size,
+ y: y,
+ index: 0,
+ isInternal: false
+ }, {
+ x: (x + width) * size,
+ y: y,
+ index: 1,
+ isInternal: false
+ }, {
+ x: (x + width) * size,
+ y: y + height,
+ index: 4,
+ isInternal: false
+ }, {
+ x: x * size,
+ y: y + height,
+ index: 3,
+ isInternal: false
+ }]
+ }
+ },
+ query() {
+ if (this.isThere) {
+ if (this.isTouched) {
+ if (!m.isBodiesAsleep) {
+ this.fadeCount--
+ Matter.Body.setVertices(this, this.shrinkVertices(Math.max(this.fadeCount / this.fadeTime, 0.03)))
+ }
+ if (this.fadeCount < 1) {
+ Matter.Body.setPosition(this, hide)
+ this.isThere = false
+ this.isTouched = false
+ this.collisionFilter.mask = 0 //cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ this.returnCount = this.returnTime
+ Matter.Body.setVertices(this, this.shrinkVertices(1))
+ Matter.Body.setVertices(this, vertices)
+ }
+ } else if (Matter.Query.collides(this, [player]).length) { // || (Matter.Query.collides(this, body).length)) {
+ this.isTouched = true
+ this.fadeCount = this.fadeTime;
+ }
+ } else {
+ if (!m.isBodiesAsleep) {
+ this.returnCount--
+ if (this.returnCount < 1) {
+ Matter.Body.setPosition(this, {
+ x: x,
+ y: y
+ })
+ if (Matter.Query.collides(this, [player]).length) { //|| (Matter.Query.collides(this, body).length)) {
+ Matter.Body.setPosition(this, hide)
+ this.returnCount = 15
+ } else {
+ this.isThere = true
+ this.collisionFilter.mask = cat.player | cat.mob | cat.body | cat.bullet | cat.powerUp | cat.mobBullet
+ this.fadeCount = this.fadeTime
+ //delete any overlapping blocks
+ const blocks = Matter.Query.collides(this, body)
+ for (let i = 0; i < blocks.length; i++) {
+ if (blocks[i].bodyB !== this && blocks[i].bodyB !== m.holdingTarget) { //dont' delete yourself <----- bug here maybe...
+ Matter.Composite.remove(engine.world, blocks[i].bodyB);
+ blocks[i].bodyB.isRemoveMeNow = true
+ for (let i = 1; i < body.length; i++) { //find which index in body array it is and remove from array
+ if (body[i].isRemoveMeNow) {
+ body.splice(i, 1);
+ break
+ }
+ }
+ }
+ }
+ //delete any overlapping mobs
+ // const mobsHits = Matter.Query.collides(this, mob)
+ // for (let i = 0; i < mobsHits.length; i++) {
+ // if (mobsHits[i].bodyB !== this && mobsHits[i].bodyB !== m.holdingTarget) { //dont' delete yourself <----- bug here maybe...
+ // Matter.Composite.remove(engine.world, mobsHits[i].bodyB);
+ // mobsHits[i].bodyB.isRemoveMeNow = true
+ // for (let i = 1; i < mob.length; i++) { //find which index in body array it is and remove from array
+ // if (mob[i].isRemoveMeNow) {
+ // mob.splice(i, 1);
+ // break
+ // }
+ // }
+ // }
+ // }
+ }
+ }
+ }
+ }
+ ctx.beginPath();
+ const v = this.vertices;
+ ctx.moveTo(v[0].x, v[0].y);
+ for (let i = 1; i < v.length; ++i) ctx.lineTo(v[i].x, v[i].y);
+ ctx.lineTo(v[0].x, v[0].y);
+ ctx.fillStyle = "#586370"
+ ctx.fill();
+ // const color = 220 * (1 - this.fadeCount / this.fadeTime)
+ // ctx.fillStyle = `rgb(${color},220, 200)`
+ // ctx.fillStyle = `rgba(0,220,200,${this.fadeCount/this.fadeTime+0.05})`
+ // ctx.strokeStyle = `#bff`
+ // ctx.stroke();
+ },
+ });
+ Matter.Body.setStatic(block, true); //make static
+ Composite.add(engine.world, block); //add to world
+ // who.classType = "body"
+ if (simulation.isHorizontalFlipped) x *= -1
+ return block
+ },
+ door(x, y, width, height, distance, speed = 1) {
+ x = x + width / 2
+ y = y + height / 2
+ const doorBlock = body[body.length] = Bodies.rectangle(x, y, width, height, {
+ collisionFilter: {
+ category: cat.body,//cat.map,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ inertia: Infinity, //prevents rotation
+ isNotHoldable: true,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0,
+ isClosing: false,
+ openClose() {
+ if (!m.isBodiesAsleep) {
+ if (this.isClosing) {
+ if (this.position.y < y) { //try to close
+ if ( //if clear of stuff
+ Matter.Query.collides(this, [player]).length === 0 &&
+ Matter.Query.collides(this, body).length < 2 &&
+ Matter.Query.collides(this, mob).length === 0
+ ) {
+ const position = {
+ x: this.position.x,
+ y: this.position.y + speed
+ }
+ Matter.Body.setPosition(this, position)
+ }
+ }
+ } else {
+ if (this.position.y > y - distance) { //try to open
+ const position = {
+ x: this.position.x,
+ y: this.position.y - speed
+ }
+ Matter.Body.setPosition(this, position)
+ }
+ }
+ }
+ },
+ isClosed() {
+ return this.position.y > y - 1
+ },
+ draw() {
+ ctx.fillStyle = "#666"
+ ctx.beginPath();
+ const v = this.vertices;
+ ctx.moveTo(v[0].x, v[0].y);
+ for (let i = 1; i < v.length; ++i) ctx.lineTo(v[i].x, v[i].y);
+ ctx.lineTo(v[0].x, v[0].y);
+ ctx.fill();
+ }
+ });
+ Matter.Body.setStatic(doorBlock, true); //make static
+ Composite.add(engine.world, doorBlock); //add to world
+ doorBlock.classType = "body"
+ return doorBlock
+ },
+ doorMap(x, y, width, height, distance, speed = 20, addToWorld = true) { //for doors that use line of sight
+ x = x + width / 2
+ y = y + height / 2
+ const door = map[map.length] = Bodies.rectangle(x, y, width, height, {
+ collisionFilter: {
+ category: cat.map,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet,
+ // mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ inertia: Infinity, //prevents rotation
+ isNotHoldable: true,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0,
+ isClosing: false,
+ openClose(isSetPaths = false) {
+ if (!m.isBodiesAsleep) {
+ if (this.isClosing) {
+ if (this.position.y < y) { //try to close
+ if ( //if clear of stuff
+ Matter.Query.collides(this, [player]).length === 0 &&
+ Matter.Query.collides(this, body).length < 2 &&
+ Matter.Query.collides(this, mob).length === 0
+ ) {
+ const position = {
+ x: this.position.x,
+ y: this.position.y + speed
+ }
+ Matter.Body.setPosition(this, position)
+ if (isSetPaths) {
+ simulation.draw.setPaths()
+ simulation.draw.lineOfSightPrecalculation() //required precalculation for line of sight
+ }
+ }
+ }
+ } else {
+ if (this.position.y > y - distance) { //try to open
+ const position = {
+ x: this.position.x,
+ y: this.position.y - speed
+ }
+ Matter.Body.setPosition(this, position)
+ if (isSetPaths) {
+ simulation.draw.setPaths()
+ simulation.draw.lineOfSightPrecalculation() //required precalculation for line of sight
+ }
+ }
+ }
+ }
+ },
+ isClosed() {
+ return this.position.y > y - 1
+ },
+ draw() {
+ ctx.fillStyle = "#666"
+ ctx.beginPath();
+ const v = this.vertices;
+ ctx.moveTo(v[0].x, v[0].y);
+ for (let i = 1; i < v.length; ++i) ctx.lineTo(v[i].x, v[i].y);
+ ctx.lineTo(v[0].x, v[0].y);
+ ctx.fill();
+ }
+ });
+
+ Matter.Body.setStatic(door, true); //make static
+ if (addToWorld) Composite.add(engine.world, door); //add to world
+ door.classType = "map"
+ return door
+ },
+ portal(centerA, angleA, centerB, angleB) {
+ const width = 50
+ const height = 150
+ const mapWidth = 200
+ const unitA = Matter.Vector.rotate({ x: 1, y: 0 }, angleA)
+ const unitB = Matter.Vector.rotate({ x: 1, y: 0 }, angleB)
+ draw = function () {
+ ctx.beginPath(); //portal
+ let v = this.vertices;
+ ctx.moveTo(v[0].x, v[0].y);
+ for (let i = 1; i < v.length; ++i) ctx.lineTo(v[i].x, v[i].y);
+ ctx.fillStyle = this.color
+ ctx.fill();
+ }
+ query = function (isRemoveBlocks = false) {
+ if (Matter.Query.collides(this, [player]).length === 0) { //not touching player
+ if (player.isInPortal === this) player.isInPortal = null
+ } else if (player.isInPortal !== this) { //touching player
+ if (m.buttonCD_jump === m.cycle) player.force.y = 0 // undo a jump right before entering the portal
+ m.buttonCD_jump = 0 //disable short jumps when letting go of jump key
+ player.isInPortal = this.portalPair
+ //teleport
+ if (this.portalPair.angle % (Math.PI / 2)) { //if left, right up or down
+ if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ Matter.Body.setPosition(player, this.portalPair.portal.position);
+ } else { //if at some odd angle
+ if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ Matter.Body.setPosition(player, this.portalPair.position);
+ }
+ //rotate velocity
+ let mag
+ if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up
+ mag = Math.max(10, Math.min(50, player.velocity.y * 0.8)) + 11
+ } else {
+ mag = Math.max(6, Math.min(50, Vector.magnitude(player.velocity)))
+ }
+ let v = Vector.mult(this.portalPair.unit, mag)
+ Matter.Body.setVelocity(player, v);
+ // move bots to player
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ // Matter.Body.setPosition(bullet[i], this.portalPair.portal.position);
+ Matter.Body.setPosition(bullet[i], Vector.add(this.portalPair.portal.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], { x: 0, y: 0 });
+ }
+ }
+ if (tech.isHealAttract) { //send heals to next portal
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal" && Vector.magnitudeSquared(Vector.sub(powerUp[i].position, m.pos)) < 1000000) {
+ Matter.Body.setPosition(powerUp[i], Vector.add(this.portalPair.portal.position, { x: 500 * (Math.random() - 0.5), y: 500 * (Math.random() - 0.5) }));
+ }
+ }
+ }
+ }
+ // if (body.length) {
+ for (let i = 0, len = body.length; i < len; i++) {
+ if (body[i] !== m.holdingTarget) {
+ // body[i].bounds.max.x - body[i].bounds.min.x < 100 && body[i].bounds.max.y - body[i].bounds.min.y < 100
+ if (Matter.Query.collides(this, [body[i]]).length === 0) {
+ if (body[i].isInPortal === this) body[i].isInPortal = null
+ } else if (body[i].isInPortal !== this) { //touching this portal, but for the first time
+ if (isRemoveBlocks) {
+ Matter.Composite.remove(engine.world, body[i]);
+ body.splice(i, 1);
+ break
+ }
+ body[i].isInPortal = this.portalPair
+ //teleport
+ if (this.portalPair.angle % (Math.PI / 2)) { //if left, right up or down
+ Matter.Body.setPosition(body[i], this.portalPair.portal.position);
+ } else { //if at some odd angle
+ Matter.Body.setPosition(body[i], this.portalPair.position);
+ }
+ //rotate velocity
+ let mag
+ if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up
+ mag = Math.max(10, Math.min(50, body[i].velocity.y * 0.8)) + 11
+ } else {
+ mag = Math.max(6, Math.min(50, Vector.magnitude(body[i].velocity)))
+ }
+ let v = Vector.mult(this.portalPair.unit, mag)
+ Matter.Body.setVelocity(body[i], v);
+ }
+ }
+ }
+ // }
+
+ //remove block if touching
+ // if (body.length) {
+ // touching = Matter.Query.collides(this, body)
+ // for (let i = 0; i < touching.length; i++) {
+ // if (touching[i].bodyB !== m.holdingTarget) {
+ // for (let j = 0, len = body.length; j < len; j++) {
+ // if (body[j] === touching[i].bodyB) {
+ // body.splice(j, 1);
+ // len--
+ // Matter.Composite.remove(engine.world, touching[i].bodyB);
+ // break;
+ // }
+ // }
+ // }
+ // }
+ // }
+
+ // if (touching.length !== 0 && touching[0].bodyB !== m.holdingTarget) {
+ // if (body.length) {
+ // for (let i = 0; i < body.length; i++) {
+ // if (body[i] === touching[0].bodyB) {
+ // body.splice(i, 1);
+ // break;
+ // }
+ // }
+ // }
+ // Matter.Composite.remove(engine.world, touching[0].bodyB);
+ // }
+ }
+
+ const portalA = composite[composite.length] = Bodies.rectangle(centerA.x, centerA.y, width, height, {
+ isSensor: true,
+ angle: angleA,
+ color: "hsla(197, 100%, 50%,0.7)",
+ draw: draw,
+ });
+ const portalB = composite[composite.length] = Bodies.rectangle(centerB.x, centerB.y, width, height, {
+ isSensor: true,
+ angle: angleB,
+ color: "hsla(29, 100%, 50%, 0.7)",
+ draw: draw
+ });
+ const mapA = composite[composite.length] = Bodies.rectangle(centerA.x - 0.5 * unitA.x * mapWidth, centerA.y - 0.5 * unitA.y * mapWidth, mapWidth, height + 10, {
+ collisionFilter: {
+ category: cat.map,
+ mask: cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ unit: unitA,
+ angle: angleA,
+ color: color.map,
+ draw: draw,
+ query: query,
+ lastPortalCycle: 0
+ });
+ Matter.Body.setStatic(mapA, true); //make static
+ Composite.add(engine.world, mapA); //add to world
+
+ const mapB = composite[composite.length] = Bodies.rectangle(centerB.x - 0.5 * unitB.x * mapWidth, centerB.y - 0.5 * unitB.y * mapWidth, mapWidth, height + 10, {
+ collisionFilter: {
+ category: cat.map,
+ mask: cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ unit: unitB,
+ angle: angleB,
+ color: color.map,
+ draw: draw,
+ query: query,
+ lastPortalCycle: 0,
+ });
+ Matter.Body.setStatic(mapB, true); //make static
+ Composite.add(engine.world, mapB); //add to world
+
+ mapA.portal = portalA
+ mapB.portal = portalB
+ mapA.portalPair = mapB
+ mapB.portalPair = mapA
+ return [portalA, portalB, mapA, mapB]
+ },
+ drip(x, yMin, yMax, period = 100, color = "hsla(160, 100%, 35%, 0.5)") {
+ return {
+ x: x,
+ y: yMin,
+ period: period,
+ dropCycle: 0,
+ speed: 0,
+ draw() {
+ if (!m.isBodiesAsleep) {
+ if (this.dropCycle < simulation.cycle) { //reset
+ this.dropCycle = simulation.cycle + this.period + Math.floor(40 * Math.random())
+ this.y = yMin
+ this.speed = 1
+ } else { //fall
+ this.speed += 0.35 //acceleration from gravity
+ this.y += this.speed
+ }
+ }
+ if (this.y < yMax) { //draw
+ ctx.fillStyle = color //"hsla(160, 100%, 35%,0.75)"
+ ctx.beginPath();
+ ctx.arc(this.x, this.y, 8, 0, 2 * Math.PI);
+ ctx.fill();
+ }
+ }
+ }
+ },
+ isHazardRise: false,
+ hazard(x, y, width, height, damage = 0.002) {
+ return {
+ min: { x: x, y: y },
+ max: { x: x + width, y: y + height },
+ width: width,
+ height: height,
+ maxHeight: height,
+ isOn: true,
+ opticalQuery() {
+ if (this.isOn) {
+ //draw
+ ctx.fillStyle = `hsla(0, 100%, 50%,${0.6 + 0.4 * Math.random()})`
+ ctx.fillRect(this.min.x, this.min.y, this.width, this.height)
+ //collision with player
+ if (this.height > 0 && Matter.Query.region([player], this).length && !(m.isCloak)) {
+ if (m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles;
+ m.damage(damage)
+ simulation.drawList.push({ //add dmg to draw queue
+ x: player.position.x,
+ y: player.position.y,
+ radius: damage * 1500,
+ color: simulation.mobDmgColor,
+ time: 20
+ });
+ }
+ }
+ }
+ },
+ query() {
+ if (this.isOn) {
+ ctx.fillStyle = "hsla(160, 100%, 35%,0.75)"
+ const offset = 5 * Math.sin(simulation.cycle * 0.015)
+ ctx.fillRect(this.min.x, this.min.y + offset, this.width, this.height - offset)
+
+ if (this.height > 0 && Matter.Query.region([player], this).length) {
+ if (m.immuneCycle < m.cycle) {
+ const DRAIN = 0.004 * (tech.isRadioactiveResistance ? 0.25 : 1)
+ if (m.energy > DRAIN) {
+ m.energy -= DRAIN
+ if (tech.isEnergyHealth && m.energy < 0) m.death()
+ } else {
+ m.damage(damage * (tech.isRadioactiveResistance ? 0.25 : 1))
+
+ }
+ }
+ //float
+ if (player.velocity.y > 5) player.force.y -= 0.95 * player.mass * simulation.g
+ const slowY = (player.velocity.y > 0) ? Math.max(0.8, 1 - 0.002 * player.velocity.y * player.velocity.y) : Math.max(0.98, 1 - 0.001 * Math.abs(player.velocity.y)) //down : up
+ Matter.Body.setVelocity(player, {
+ x: Math.max(0.95, 1 - 0.036 * Math.abs(player.velocity.x)) * player.velocity.x,
+ y: slowY * player.velocity.y
+ });
+ //undo 1/2 of gravity
+ player.force.y -= 0.5 * player.mass * simulation.g;
+
+ }
+ //float power ups
+ powerUpCollide = Matter.Query.region(powerUp, this)
+ for (let i = 0, len = powerUpCollide.length; i < len; i++) {
+ const diameter = 2 * powerUpCollide[i].size
+ const buoyancy = 1 - 0.2 * Math.max(0, Math.min(diameter, this.min.y - powerUpCollide[i].position.y + powerUpCollide[i].size)) / diameter
+ powerUpCollide[i].force.y -= buoyancy * 1.24 * powerUpCollide[i].mass * simulation.g;
+ Matter.Body.setVelocity(powerUpCollide[i], {
+ x: powerUpCollide[i].velocity.x,
+ y: 0.97 * powerUpCollide[i].velocity.y
+ });
+ }
+ }
+ },
+ // draw() {
+ // if (this.isOn) {
+ // ctx.fillStyle = color
+ // ctx.fillRect(this.min.x, this.min.y, this.width, this.height)
+ // }
+ // },
+ levelRise(growRate = 1) {
+ if (this.height < this.maxHeight && !m.isBodiesAsleep) {
+ this.height += growRate
+ this.min.y -= growRate
+ this.max.y = this.min.y + this.height
+ }
+ },
+ levelFall(fallRate = 1) {
+ if (this.height > 0 && !m.isBodiesAsleep) {
+ this.height -= fallRate
+ this.min.y += fallRate
+ this.max.y = this.min.y + this.height
+ }
+ },
+ level(isFill, growSpeed = 1) {
+ if (!m.isBodiesAsleep) {
+ if (isFill) {
+ if (this.height < this.maxHeight) {
+ this.height += growSpeed
+ this.min.y -= growSpeed
+ this.max.y = this.min.y + this.height
+ }
+ } else if (this.height > 0) {
+ this.height -= growSpeed
+ this.min.y += growSpeed
+ this.max.y = this.min.y + this.height
+ }
+ }
+ }
+ }
+ },
+ mover(x, y, width, height, VxGoal = -6, force = VxGoal > 0 ? 0.0005 : -0.0005) {
+ //VxGoal below 3 don't move well, maybe try adjusting the force
+ x = x + width / 2
+ y = y + height / 2
+ const rect = map[map.length] = Bodies.rectangle(x, y, width, height, {
+ collisionFilter: {
+ category: cat.map,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ inertia: Infinity, //prevents rotation
+ isNotHoldable: true,
+ friction: 0,
+ frictionStatic: 0,
+ restitution: 0,
+ isClosing: false,
+ isMover: true,
+ VxGoal: VxGoal,
+ force: force,
+ push() {
+ if (!m.isBodiesAsleep) {
+ const touchingPlayer = Matter.Query.collides(this, [jumpSensor])
+ if (touchingPlayer.length) {
+ m.moverX = this.VxGoal
+ if ((this.VxGoal > 0 && player.velocity.x < this.VxGoal) || (this.VxGoal < 0 && player.velocity.x > this.VxGoal)) {
+ player.force.x += this.force * player.mass
+ }
+ m.Vx = player.velocity.x - this.VxGoal
+ }
+ let pushBlock = (who) => {
+ if (!who.isMover) {
+ if ((this.VxGoal > 0 && who.velocity.x < this.VxGoal) || (this.VxGoal < 0 && who.velocity.x > this.VxGoal)) {
+ who.force.x += this.force * who.mass
+ }
+ const stoppingFriction = 0.5
+ Matter.Body.setVelocity(who, { x: this.VxGoal * (1 - stoppingFriction) + who.velocity.x * stoppingFriction, y: who.velocity.y });
+ Matter.Body.setAngularVelocity(who, who.angularVelocity * 0.9)
+ }
+ }
+ const blocks = Matter.Query.collides(this, body)
+ for (let i = 0; i < blocks.length; i++) {
+ pushBlock(blocks[i].bodyA)
+ pushBlock(blocks[i].bodyB)
+ }
+ const mobTargets = Matter.Query.collides(this, mob)
+ for (let i = 0; i < mobTargets.length; i++) {
+ pushBlock(mobTargets[i].bodyA)
+ pushBlock(mobTargets[i].bodyB)
+ }
+ let pushPowerUp = (who) => {
+ if (!who.isMover) {
+ if ((this.VxGoal > 0 && who.velocity.x < this.VxGoal) || (this.VxGoal < 0 && who.velocity.x > this.VxGoal)) {
+ who.force.x += 2 * this.force * who.mass
+ }
+ const stoppingFriction = 0.5
+ Matter.Body.setVelocity(who, { x: this.VxGoal * (1 - stoppingFriction) + who.velocity.x * stoppingFriction, y: who.velocity.y });
+ }
+ }
+ const powers = Matter.Query.collides(this, powerUp)
+ for (let i = 0; i < powers.length; i++) {
+ pushPowerUp(powers[i].bodyA)
+ pushPowerUp(powers[i].bodyB)
+ }
+ }
+ },
+ draw() {
+ ctx.beginPath();
+ const v = this.vertices;
+ ctx.moveTo(v[0].x + 2, v[0].y);
+ // for (let i = 1; i < v.length; ++i) ctx.lineTo(v[i].x, v[i].y);
+ ctx.lineTo(v[1].x - 2, v[1].y);
+ ctx.strokeStyle = "#000"
+ ctx.lineWidth = 4;
+ ctx.setLineDash([40, 40]);
+ ctx.lineDashOffset = (-simulation.cycle * this.VxGoal) % 80;
+ ctx.stroke();
+ ctx.setLineDash([0, 0]);
+ }
+ });
+ Matter.Body.setStatic(rect, true); //make static
+ return rect
+ },
+ transport(x, y, width, height, VxGoal = -6, force = VxGoal > 0 ? 0.0005 : -0.0005) {
+ //horizontal moving platform
+ //VxGoal below 3 don't move well, maybe try adjusting the force
+ x = x + width / 2
+ y = y + height / 2
+ const rect = body[body.length] = Bodies.rectangle(x, y, width, height, {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ inertia: Infinity, //prevents rotation
+ isNotHoldable: true,
+ friction: 0,
+ frictionStatic: 0,
+ restitution: 0,
+ isClosing: false,
+ isMover: true,
+ VxGoal: VxGoal,
+ force: force,
+ move() {
+ if (!m.isBodiesAsleep) {
+ Matter.Body.setPosition(this, { x: this.position.x + this.VxGoal, y: this.position.y }); //horizontal movement
+ const touchingPlayer = Matter.Query.collides(this, [jumpSensor])
+ if (touchingPlayer.length) {
+ m.moverX = this.VxGoal
+ if ((this.VxGoal > 0 && player.velocity.x < this.VxGoal) || (this.VxGoal < 0 && player.velocity.x > this.VxGoal)) {
+ player.force.x += this.force * player.mass
+ }
+ m.Vx = player.velocity.x - this.VxGoal
+ }
+ let pushBlock = (who) => {
+ if (!who.isMover) {
+ if ((this.VxGoal > 0 && who.velocity.x < this.VxGoal) || (this.VxGoal < 0 && who.velocity.x > this.VxGoal)) {
+ who.force.x += this.force * who.mass
+ }
+ const stoppingFriction = 0.5
+ Matter.Body.setVelocity(who, { x: this.VxGoal * (1 - stoppingFriction) + who.velocity.x * stoppingFriction, y: who.velocity.y });
+ Matter.Body.setAngularVelocity(who, who.angularVelocity * 0.8)
+ }
+ }
+ const blocks = Matter.Query.collides(this, body)
+ for (let i = 0; i < blocks.length; i++) {
+ pushBlock(blocks[i].bodyA)
+ pushBlock(blocks[i].bodyB)
+ }
+ }
+ },
+ draw() {
+ ctx.beginPath();
+ const v = this.vertices;
+ ctx.moveTo(v[0].x, v[0].y);
+ for (let i = 1; i < v.length; ++i) ctx.lineTo(v[i].x, v[i].y);
+ ctx.lineTo(v[0].x, v[0].y);
+ ctx.fillStyle = "#586370"
+ ctx.fill();
+ },
+ changeDirection(isRight) {
+ if (isRight) {
+ this.VxGoal = Math.abs(this.VxGoal)
+ this.force = Math.abs(this.force)
+ if (Matter.Query.collides(this, [jumpSensor]).length) player.force.x += this.trainKickPlayer * this.force * player.mass
+ } else {
+ this.VxGoal = -Math.abs(this.VxGoal)
+ this.force = -Math.abs(this.force)
+ if (Matter.Query.collides(this, [jumpSensor]).length) player.force.x += this.trainKickPlayer * this.force * player.mass
+ }
+ },
+ trainSpeed: Math.abs(VxGoal),
+ trainKickPlayer: 12 * Math.abs(force),
+ isSensing: false,
+ stops: { left: x, right: x + 1000 }, //this should probably be reset in the level code for the actual train stops
+ trainStop() {
+ if (this.isMoving) {
+ this.move();
+ //oscillate back and forth
+ if (this.position.x < this.stops.left) {//stop
+ this.VxGoal = this.trainSpeed
+ this.force = 0.0005
+ this.isMoving = false
+ this.isSensing = false
+ if (Matter.Query.collides(this, [jumpSensor]).length) player.force.x += this.trainKickPlayer * player.mass * (this.VxGoal > 0 ? 1 : -1)//give player a kick so they don't fall off
+ } else if (this.position.x > this.stops.right) {//stop
+ this.VxGoal = -this.trainSpeed
+ this.force = -0.0005
+ this.isMoving = false
+ this.isSensing = false
+ if (Matter.Query.collides(this, [jumpSensor]).length) player.force.x += this.trainKickPlayer * player.mass * (this.VxGoal > 0 ? 1 : -1)//give player a kick so they don't fall off
+ }
+ } else if (this.isSensing) {
+ if (Matter.Query.collides(this, [jumpSensor]).length) {
+ this.isMoving = true
+ this.move(); //needs to move out of the stop range
+ // if (Matter.Query.collides(this, [jumpSensor]).length) player.force.x += trainKickPlayer * player.mass * (this.VxGoal > 0 ? 1 : -1)//give player a kick so they don't fall off
+ if (Matter.Query.collides(this, [jumpSensor]).length) {
+ Matter.Body.setVelocity(player, { x: this.VxGoal, y: player.velocity.y });
+ }
+ } else if (this.position.x > this.stops.right && player.position.x < this.stops.left + 500) {//head to other stop if the player is far away
+ this.changeDirection(false) //go left
+ this.isMoving = true
+ this.move(); //needs to move out of the stop range
+ } else if (this.position.x < this.stops.left && player.position.x > this.stops.right - 500) {//head to other stop if the player is far away
+ this.changeDirection(true) //go right
+ this.isMoving = true
+ this.move(); //needs to move out of the stop range
+ }
+ } else if (!Matter.Query.collides(this, [jumpSensor]).length) {//wait until player is off the train to start sensing
+ this.isSensing = true
+ }
+ },
+ });
+ Matter.Body.setStatic(rect, true); //make static
+ Composite.add(engine.world, rect); //add to world
+ rect.classType = "body"
+ return rect
+ },
+ chain(x, y, angle = 0, isAttached = true, len = 15, radius = 20, stiffness = 1, damping = 1) {
+ const gap = 2 * radius
+ const unit = {
+ x: Math.cos(angle),
+ y: Math.sin(angle)
+ }
+ for (let i = 0; i < len; i++) {
+ body[body.length] = Bodies.polygon(x + gap * unit.x * i, y + gap * unit.y * i, 12, radius, {
+ inertia: Infinity,
+ isNotHoldable: true
+ });
+ const who = body[body.length - 1]
+ who.collisionFilter.category = cat.body;
+ who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
+ Composite.add(engine.world, who); //add to world
+ who.classType = "body"
+ }
+ for (let i = 1; i < len; i++) { //attach blocks to each other
+ consBB[consBB.length] = Constraint.create({
+ bodyA: body[body.length - i],
+ bodyB: body[body.length - i - 1],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ cons[cons.length] = Constraint.create({ //pin first block to a point in space
+ pointA: {
+ x: x,
+ y: y
+ },
+ bodyB: body[body.length - len],
+ stiffness: 1,
+ damping: damping
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ if (isAttached) {
+ cons[cons.length] = Constraint.create({ //pin last block to a point in space
+ pointA: {
+ x: x + gap * unit.x * (len - 1),
+ y: y + gap * unit.y * (len - 1)
+ },
+ bodyB: body[body.length - 1],
+ stiffness: 1,
+ damping: damping
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ }
+ },
+ //******************************************************************************************************************
+ //******************************************************************************************************************
+ //******************************************************************************************************************
+ //******************************************************************************************************************
+ template() {
+ simulation.enableConstructMode()
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 1500;
+ level.exit.y = -1875;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d8dadf";
+ // color.map = "#444" //custom map color
+
+ level.custom = () => {
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => { };
+
+ spawn.mapRect(-100, 0, 1000, 100);
+ // powerUps.spawnStartingPowerUps(1475, -1175);
+ // spawn.debris(750, -2200, 3700, 16); //16 debris per level
+ // spawn.bodyRect(1540, -1110, 300, 25, 0.9);
+ // spawn.randomSmallMob(1300, -70);
+ // spawn.randomMob(2650, -975, 0.8);
+ // spawn.randomGroup(1700, -900, 0.4);
+ // if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300);
+ // spawn.secondaryBossChance(100, -1500)
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ testing() {
+ simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode
+
+ document.body.style.backgroundColor = "#fff";
+ // color.map = "#444" //custom map color
+ // level.difficultyIncrease(14); //hard mode level 7
+ level.defaultZoom = 1500
+ simulation.zoomTransition(level.defaultZoom)
+
+ const mover = level.mover(2800, -300, 1000, 25); //x,y,width.height,VxGoal,force
+
+ const train = level.transport(2900, -500, 500, 25, 8); //x,y,width.height,VxGoal,force
+ spawn.bodyRect(1900, -550, 50, 50);
+ const button = level.button(2535, -200)
+ // spawn.bodyRect(250, -450, 50, 50); //block on button
+
+ level.custom = () => {
+
+ //oscillate back and forth
+ if (train.position.x < 2000) {
+ train.changeDirection(true) //go right
+ } else if (train.position.x > 4000) {
+ train.changeDirection(false) //go left
+ }
+ if (!button.isUp) train.move();
+
+ mover.push();
+ ctx.fillStyle = "#d4d4d4"
+ ctx.fillRect(2500, -475, 200, 300)
+
+ ctx.fillStyle = "#ddd"
+ ctx.fillRect(-150, -1000, 6875, 1000);
+ ctx.fillStyle = "rgba(0,255,255,0.1)";
+ ctx.fillRect(6400, -550, 300, 350);
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ train.draw()
+ mover.draw();
+ button.query();
+ button.draw();
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(-150, -650, 900, 250)
+ };
+ level.setPosToSpawn(0, -450); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.x = 6500;
+ level.exit.y = -230;
+
+ spawn.mapRect(-950, 0, 8200, 800); //ground
+ spawn.mapRect(-950, -1200, 800, 1400); //left wall
+ spawn.mapRect(-950, -1800, 8200, 800); //roof
+ spawn.mapRect(-250, -400, 1000, 600); // shelf
+ spawn.mapRect(-250, -1200, 1000, 550); // shelf roof
+ // for (let i = 0; i < 10; ++i) powerUps.spawn(550, -800, "ammo", false);
+
+ function blockDoor(x, y, blockSize = 58) {
+ spawn.mapRect(x, y - 290, 40, 60); // door lip
+ spawn.mapRect(x, y, 40, 50); // door lip
+ for (let i = 0; i < 4; ++i) spawn.bodyRect(x + 5, y - 260 + i * blockSize, 30, blockSize);
+ }
+
+ spawn.mapRect(2500, -1200, 200, 750); //right wall
+ spawn.mapRect(2500, -200, 200, 300); //right wall
+ spawn.mapRect(4500, -1200, 200, 650); //right wall
+ blockDoor(4585, -310)
+ spawn.mapRect(4500, -300, 200, 400); //right wall
+ spawn.mapRect(6400, -1200, 400, 750); //right wall
+ spawn.mapRect(6400, -200, 400, 300); //right wall
+ spawn.mapRect(6700, -1800, 800, 2600); //right wall
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
+ //place to hide
+ spawn.mapRect(4650, -300, 1150, 50);
+ spawn.mapRect(5750, -300, 50, 200);
+ spawn.mapRect(5575, -100, 50, 125);
+ spawn.mapRect(5300, -275, 50, 175);
+ spawn.mapRect(5050, -100, 50, 150);
+ spawn.mapRect(4850, -275, 50, 175);
+ spawn.mapRect(-950, -3250, 850, 1750);
+ //roof
+ spawn.mapRect(-175, -2975, 300, 1425);
+ spawn.mapRect(75, -2650, 325, 1150);
+ spawn.mapRect(375, -2225, 250, 650);
+ spawn.mapRect(4075, -2125, 700, 800);
+ spawn.mapRect(4450, -2950, 675, 1550);
+ spawn.mapRect(4875, -3625, 725, 2225);
+ spawn.mapRect(5525, -4350, 1725, 2925);
+ spawn.mapRect(7200, -5125, 300, 3900);
+
+
+ //???
+ // level.difficultyIncrease(3 * 4) //30 is near max on hard //60 is near max on why
+ // m.addHealth(Infinity)
+
+ // spawn.starter(1900, -500, 200) //big boy
+ // spawn.starter(1900, -500, 100) //big boy
+ // for (let i = 0; i < 10; ++i) spawn.launcher(1900, -500)
+ // spawn.suckerBoss(1900, -500)
+ // spawn.launcherBoss(3200, -500)
+ // spawn.laserTargetingBoss(1700, -500)
+ // spawn.powerUpBoss(1900, -500)
+ // spawn.powerUpBossBaby(3200, -500)
+ // spawn.dragonFlyBoss(1700, -500)
+ // spawn.streamBoss(3200, -500)
+ // spawn.pulsarBoss(1700, -500)
+ // spawn.spawnerBossCulture(3200, -500)
+ // spawn.grenadierBoss(1700, -500)
+ // spawn.growBossCulture(3200, -500)
+ // spawn.blinkBoss(1700, -500)
+ // spawn.snakeSpitBoss(3200, -500)
+ // spawn.laserBombingBoss(1700, -500)
+ // spawn.launcherBoss(3200, -500)
+ // spawn.blockBoss(1700, -500)
+ // spawn.blinkBoss(3200, -500)
+ // spawn.spiderBoss(1700, -500)
+ // spawn.tetherBoss(1700, -500) //go to actual level?
+ // spawn.revolutionBoss(1900, -500)
+ // spawn.bomberBoss(1400, -500)
+ // spawn.cellBossCulture(1600, -500)
+ // spawn.shieldingBoss(1700, -500)
+
+ // for (let i = 0; i < 10; ++i) spawn.bodyRect(1600 + 5, -500, 30, 40);
+ // for (let i = 0; i < 4; i++) spawn.starter(1900, -500)
+ // spawn.pulsar(1900, -500)
+ // spawn.shield(mob[mob.length - 1], 1900, -500, 1);
+ // mob[mob.length - 1].isShielded = true
+ // spawn.nodeGroup(1200, 0, "grenadier")
+ // spawn.blinkBoss(1200, -500)
+ // spawn.suckerBoss(2900, -500)
+ // spawn.randomMob(1600, -500)
+ },
+ null() {
+ level.levels.pop(); //remove lore level from rotation
+ // level.onLevel--
+ // console.log(level.onLevel, level.levels)
+ //start a conversation based on the number of conversations seen
+ if (localSettings.loreCount > lore.conversation.length - 1) localSettings.loreCount = lore.conversation.length - 1; //repeat final conversation if lore count is too high
+ if (!simulation.isCheating && localSettings.loreCount < lore.conversation.length) {
+ tech.isNoDraftPause = true //disable pause
+ lore.testSpeechAPI() //see if speech is working
+ lore.chapter = localSettings.loreCount //set the chapter to listen to to be the lore level (you can't use the lore level because it changes during conversations)
+ lore.sentence = 0 //what part of the conversation to start on
+ lore.conversation[lore.chapter][lore.sentence]()
+ localSettings.loreCount++ //hear the next conversation next time you win
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ }
+ // const hazardSlime = level.hazard(-1800, 150, 3600, 650, 0.004, "hsla(160, 100%, 35%,0.75)")
+ level.isHazardRise = false //this is set to true to make the slime rise up
+ const hazardSlime = level.hazard(-1800, -800, 3600, 1600, 0.004)
+ hazardSlime.height -= 950
+ hazardSlime.min.y += 950
+ hazardSlime.max.y = hazardSlime.min.y + hazardSlime.height
+ const circle = {
+ x: 0,
+ y: -500,
+ radius: 50
+ }
+ level.custom = () => {
+ //draw wide line
+ ctx.beginPath();
+ ctx.moveTo(circle.x, -800)
+ ctx.lineTo(circle.x, circle.y)
+ ctx.lineWidth = 40;
+ ctx.strokeStyle = lore.talkingColor //"#d5dddd" //"#bcc";
+ ctx.globalAlpha = 0.03;
+ ctx.stroke();
+ ctx.globalAlpha = 1;
+ //support pillar
+ ctx.fillStyle = "rgba(0,0,0,0.2)";
+ ctx.fillRect(-25, 0, 50, 1000);
+
+ //draw circles
+ ctx.beginPath();
+ ctx.arc(circle.x, circle.y, circle.radius, 0, 2 * Math.PI);
+ ctx.fillStyle = "#bcc"
+ ctx.fill();
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "#abb";
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.arc(circle.x, circle.y, circle.radius / 8, 0, 2 * Math.PI);
+ ctx.fillStyle = lore.talkingColor //"#dff"
+ ctx.fill();
+
+ // level.enter.draw();
+ };
+ let sway = {
+ x: 0,
+ y: 0
+ }
+ let phase = -Math.PI / 2
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,0,0,0.1)";
+ ctx.fillRect(-1950, -950, 3900, 1900);
+ //draw center circle lines
+ ctx.beginPath();
+ const step = Math.PI / 20
+ const horizontalStep = 85
+ if (simulation.isCheating) phase += 0.3 * Math.random() * Math.random() //(m.pos.x - circle.x) * 0.0005 //0.05 * Math.sin(simulation.cycle * 0.030)
+ // const sway = 5 * Math.cos(simulation.cycle * 0.007)
+ sway.x = sway.x * 0.995 + 0.005 * (m.pos.x - circle.x) * 0.05 //+ 0.04 * Math.cos(simulation.cycle * 0.01)
+ sway.y = 2.5 * Math.sin(simulation.cycle * 0.015)
+ for (let i = -19.5; i < 20; i++) {
+ const where = {
+ x: circle.x + circle.radius * Math.cos(i * step + phase),
+ y: circle.y + circle.radius * Math.sin(i * step + phase)
+ }
+ ctx.moveTo(where.x, where.y);
+ ctx.bezierCurveTo(sway.x * Math.abs(i) + where.x, where.y + 25 * Math.abs(i) + 60 + sway.y * Math.sqrt(Math.abs(i)),
+ sway.x * Math.abs(i) + where.x + horizontalStep * i, where.y + 25 * Math.abs(i) + 60 + sway.y * Math.sqrt(Math.abs(i)),
+ horizontalStep * i, -800);
+ }
+ ctx.lineWidth = 0.5;
+ ctx.strokeStyle = "#899";
+ ctx.stroke();
+ hazardSlime.query();
+ if (level.isHazardRise) hazardSlime.level(true)
+ //draw wires
+ // ctx.beginPath();
+ // ctx.moveTo(-500, -800);
+ // ctx.quadraticCurveTo(-800, -100, -1800, -375);
+ // ctx.moveTo(-600, -800);
+ // ctx.quadraticCurveTo(-800, -200, -1800, -325);
+ // ctx.lineWidth = 1;
+ // ctx.strokeStyle = "#9aa";
+ // ctx.stroke();
+ };
+ level.setPosToSpawn(0, -50); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 25, 100, 10);
+ level.exit.x = 0;
+ level.exit.y = 40000;
+ level.defaultZoom = 1000
+ simulation.zoomTransition(level.defaultZoom)
+ // document.body.style.backgroundColor = "#aaa";
+ document.body.style.backgroundColor = "#ddd";
+ color.map = "#586363" //808f8f"
+
+ spawn.mapRect(-3000, 800, 5000, 1200); //bottom
+ spawn.mapRect(-2000, -2000, 5000, 1200); //ceiling
+ spawn.mapRect(-3000, -2000, 1200, 3400); //left
+ spawn.mapRect(1800, -1400, 1200, 3400); //right
+
+ spawn.mapRect(-500, 0, 1000, 50); //center platform
+ spawn.mapRect(-500, -25, 25, 50); //edge shelf
+ spawn.mapRect(475, -25, 25, 50); //edge shelf
+ },
+ intro() {
+ // console.log(level.levelsCleared)
+ if (level.levelsCleared === 0) { //if this is the 1st level of the game
+ //wait to spawn power ups until unpaused
+ //power ups don't spawn in experiment mode, so they don't get removed at the start of experiment mode
+ const goal = simulation.cycle + 10
+
+ function cycle() {
+ if (simulation.cycle > goal) {
+ if (localSettings.loreCount === 6) {
+ powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2170, "field", false);
+ } else {
+ powerUps.spawnStartingPowerUps(2095 + 15 * (Math.random() - 0.5), -2070 - 125);
+ }
+ if (simulation.difficultyMode < 5) {
+ powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 25, "heal", false);
+ powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070 - 75, "heal", false);
+ powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2070, "research", false); //not on why difficulty
+ }
+ } else {
+ requestAnimationFrame(cycle);
+ }
+ }
+ requestAnimationFrame(cycle);
+
+ if (localSettings.levelsClearedLastGame < 3) {
+ if (!simulation.isCheating && !m.isShipMode && !build.isExperimentRun) {
+ spawn.wireFoot();
+ spawn.wireFootLeft();
+ spawn.wireKnee();
+ spawn.wireKneeLeft();
+ spawn.wireHead();
+ // for (let i = 0; i < 3; i++) powerUps.spawn(2095, -1220 - 50 * i, "tech", false); //unavailable tech spawns
+ // spawn.mapRect(2000, -1025, 200, 25);
+ }
+ } else if (!build.isExperimentRun) {
+ simulation.trails()
+ //bonus power ups for clearing runs in the last game
+ if (!simulation.isCheating && localSettings.levelsClearedLastGame > 1) {
+ for (let i = 0; i < localSettings.levelsClearedLastGame / 3; i++) powerUps.spawn(2095 + 2 * Math.random(), -1270 - 50 * i, "tech", false); //spawn a tech for levels cleared in last game
+ simulation.makeTextLog(`for (let i
= 0; i
< localSettings.levelsClearedLastGame
/ 3; i
++ )`);
+ simulation.makeTextLog(`{ powerUps.spawn(m.pos.x, m.pos.y, "tech")
//simulation superposition }`);
+ localSettings.levelsClearedLastGame = 0 //after getting bonus power ups reset run history
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ }
+ }
+ spawn.mapRect(2025, 0, 150, 50); //lid to floor hole
+ } else {
+ for (let i = 0; i < 60; i++) {
+ setTimeout(() => {
+ if (level.levels[level.onLevel] === "intro") spawn.sneaker(2100, -1500 - 50 * i);
+ }, 2000 + 500 * i);
+ }
+ }
+ const wires = new Path2D() //pre-draw the complex lighting path to save processing
+ wires.moveTo(-150, -275)
+ wires.lineTo(80, -275)
+ wires.lineTo(80, -1000)
+ wires.moveTo(-150, -265)
+ wires.lineTo(90, -265)
+ wires.lineTo(90, -1000)
+ wires.moveTo(-150, -255)
+ wires.lineTo(100, -255)
+ wires.lineTo(100, -1000)
+ wires.moveTo(-150, -245)
+ wires.lineTo(1145, -245)
+ wires.lineTo(1145, 0)
+ wires.moveTo(-150, -235)
+ wires.lineTo(1135, -235)
+ wires.lineTo(1135, 0)
+ wires.moveTo(-150, -225)
+ wires.lineTo(1125, -225)
+ wires.lineTo(1125, 0)
+ wires.moveTo(-150, -215)
+ wires.lineTo(460, -215)
+ wires.lineTo(460, 0)
+ wires.moveTo(-150, -205)
+ wires.lineTo(450, -205)
+ wires.lineTo(450, 0)
+ wires.moveTo(-150, -195)
+ wires.lineTo(440, -195)
+ wires.lineTo(440, 0)
+
+ wires.moveTo(1155, 0)
+ wires.lineTo(1155, -450)
+ wires.lineTo(1000, -450)
+ wires.lineTo(1000, -1000)
+ wires.moveTo(1165, 0)
+ wires.lineTo(1165, -460)
+ wires.lineTo(1010, -460)
+ wires.lineTo(1010, -1000)
+ wires.moveTo(1175, 0)
+ wires.lineTo(1175, -470)
+ wires.lineTo(1020, -470)
+ wires.lineTo(1020, -1000)
+ wires.moveTo(1185, 0)
+ wires.lineTo(1185, -480)
+ wires.lineTo(1030, -480)
+ wires.lineTo(1030, -1000)
+ wires.moveTo(1195, 0)
+ wires.lineTo(1195, -490)
+ wires.lineTo(1040, -490)
+ wires.lineTo(1040, -1000)
+
+ wires.moveTo(1625, -1000)
+ wires.lineTo(1625, 0)
+ wires.moveTo(1635, -1000)
+ wires.lineTo(1635, 0)
+ wires.moveTo(1645, -1000)
+ wires.lineTo(1645, 0)
+ wires.moveTo(1655, -1000)
+ wires.lineTo(1655, 0)
+ wires.moveTo(1665, -1000)
+ wires.lineTo(1665, 0)
+
+ wires.moveTo(1675, -465)
+ wires.lineTo(2325, -465)
+ wires.lineTo(2325, 0)
+ wires.moveTo(1675, -455)
+ wires.lineTo(2315, -455)
+ wires.lineTo(2315, 0)
+ wires.moveTo(1675, -445)
+ wires.lineTo(2305, -445)
+ wires.lineTo(2305, 0)
+ wires.moveTo(1675, -435)
+ wires.lineTo(2295, -435)
+ wires.lineTo(2295, 0)
+
+ wires.moveTo(2335, 0)
+ wires.lineTo(2335, -710)
+ wires.lineTo(2600, -710)
+ wires.moveTo(2345, 0)
+ wires.lineTo(2345, -700)
+ wires.lineTo(2600, -700)
+ wires.moveTo(2355, 0)
+ wires.lineTo(2355, -690)
+ wires.lineTo(2600, -690)
+
+ level.custom = () => {
+ //push around power ups stuck in the tube wall
+ if (!(simulation.cycle % 30)) {
+ for (let i = 0, len = powerUp.length; i < len; i++) {
+ if (powerUp[i].position.y < -1000) powerUp[i].force.x += 0.01 * (Math.random() - 0.5) * powerUp[i].mass
+ }
+ }
+ //draw binary number
+ const binary = (localSettings.runCount >>> 0).toString(2)
+ const height = 20
+ const width = 8
+ const yOff = -40 //-580
+ let xOff = -130 //2622
+ ctx.strokeStyle = "#bff"
+ ctx.lineWidth = 1.5;
+ ctx.beginPath()
+ for (let i = 0; i < binary.length; i++) {
+ if (binary[i] === "0") {
+ ctx.moveTo(xOff, yOff)
+ ctx.lineTo(xOff, yOff + height)
+ ctx.lineTo(xOff + width, yOff + height)
+ ctx.lineTo(xOff + width, yOff)
+ ctx.lineTo(xOff, yOff)
+ xOff += 10 + width
+ } else {
+ ctx.moveTo(xOff, yOff)
+ ctx.lineTo(xOff, yOff + height)
+ xOff += 10
+ }
+ }
+ ctx.stroke();
+
+ ctx.beginPath()
+ ctx.strokeStyle = "#ccc"
+ ctx.lineWidth = 5;
+ ctx.stroke(wires);
+
+ //squares that look like they keep the wires in place
+ ctx.beginPath()
+ ctx.rect(1600, -500, 90, 100)
+ ctx.rect(-55, -285, 12, 100)
+ ctx.rect(1100, -497, 8, 54)
+ ctx.rect(2285, -200, 80, 10)
+ ctx.rect(1110, -70, 100, 10)
+ ctx.fillStyle = "#ccc"
+ ctx.fill()
+
+ //power up dispenser
+ // ctx.beginPath()
+ // for (let i = 2; i < 10; i++) {
+ // ctx.moveTo(2000, -100 * i)
+ // ctx.lineTo(2080, -100 * i)
+ // }
+ // ctx.strokeStyle = "#ddd"
+ // ctx.lineWidth = 5;
+ // ctx.stroke();
+
+ // ctx.beginPath()
+ // for (let i = 2; i < 10; i++) {
+ // ctx.arc(2040, -100 * i, 30, 0, 2 * Math.PI);
+ // ctx.moveTo(2040, -100 * i)
+ // }
+ // ctx.fillStyle = "rgba(0,0,0,0.3)"
+ // ctx.fill()
+
+ // ctx.fillStyle = "rgba(240,255,255,0.5)"
+ // ctx.fillRect(2000, -1000, 80, 700)
+
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(2600, -600, 400, 300)
+
+ // level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+
+ level.customTopLayer = () => {
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(2600, -600, 400, 300)
+ //draw shade for ceiling tech
+ ctx.fillStyle = "rgba(68, 68, 68,0.95)"
+ ctx.fillRect(2030, -2800, 150, 1800);
+ ctx.fillStyle = "rgba(68, 68, 68,0.95)"
+ ctx.fillRect(2030, 0, 150, 1800);
+ };
+
+
+
+ level.setPosToSpawn(460, -100); //normal spawn
+ // level.enter.x = -1000000; //hide enter graphic for first level by moving to the far left
+ level.exit.x = 2800;
+ level.exit.y = -335;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1000 //1400 is normal
+ level.defaultZoom = 1600
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = "#e1e1e1";
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(3000, -2800, 2600, 4600); //right wall
+
+ // spawn.mapRect(-250, 0, 3600, 1800); //ground
+ spawn.mapRect(-250, 0, 2300, 1800); //split roof
+ spawn.mapRect(2150, 0, 1200, 1800); //split roof
+ spawn.mapRect(2025, -3, 25, 15); //lip on power up chamber
+ spawn.mapRect(2150, -3, 25, 15); //lip on power up chamber
+
+ // spawn.mapRect(-250, -2800, 3600, 1800); //roof
+ spawn.mapRect(-250, -2800, 2300, 1800); //split roof
+ map[map.length - 1].friction = 0
+ map[map.length - 1].frictionStatic = 0
+ spawn.mapRect(2150, -2800, 1200, 1800); //split roof
+ map[map.length - 1].friction = 0
+ map[map.length - 1].frictionStatic = 0
+ spawn.mapRect(2025, -1010, 25, 13); //lip on power up chamber
+ spawn.mapRect(2150, -1010, 25, 13); //lip on power up chamber
+
+ spawn.mapRect(2600, -300, 500, 500); //exit shelf
+ spawn.mapRect(2600, -1200, 500, 600); //exit roof
+ spawn.mapRect(-95, -1100, 80, 110); //wire source
+ spawn.mapRect(410, -10, 90, 20); //small platform for player
+
+ spawn.bodyRect(2425, -120, 70, 50);
+ spawn.bodyRect(2400, -100, 100, 60);
+ spawn.bodyRect(2500, -150, 100, 150); //exit step
+ },
+ final() {
+ // color.map = "rgba(0,0,0,0.8)"
+ const slime = level.hazard(simulation.isHorizontalFlipped ? 150 - 860 : -150, -360, 880, 259) //x, y, width, height, damage = 0.002) {
+ slime.height -= slime.maxHeight - 150 //start slime at zero
+ slime.min.y += slime.maxHeight
+ slime.max.y = slime.min.y + slime.height
+ level.custom = () => {
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ slime.query();
+ slime.levelRise(0.1)
+
+ ctx.fillStyle = "rgba(0,255,255,0.1)"
+ ctx.fillRect(5385, -550, 300, 250)
+ };
+
+ level.setPosToSpawn(0, -250); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ spawn.mapRect(5500, -330 + 20, 100, 20); //spawn this because the real exit is in the wrong spot
+ level.exit.x = 0;
+ level.exit.y = -8000;
+
+ level.defaultZoom = 2500
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#ddd";
+
+ for (let i = 0; i < 16; i++) powerUps.spawn(4600 + 40 * i, -30, "ammo");
+
+ spawn.mapRect(-1950, 0, 8200, 1800); //ground
+ spawn.mapRect(-1950, -1500, 1800, 1900); //left wall
+ spawn.mapRect(-1950, -3300, 8200, 1800); //roof
+ spawn.mapRect(-250, -200, 1000, 300); // shelf
+ spawn.mapRect(-250, -1700, 1000, 1250); // shelf roof
+ spawn.mapRect(705, -210, 25, 50);
+ spawn.mapRect(725, -220, 25, 50);
+ spawn.bodyRect(750, -125, 125, 125);
+ spawn.bodyRect(875, -50, 50, 50);
+
+ spawn.mapRect(5400, -1700, 400, 1150); //right wall
+ spawn.mapRect(5400, -300, 400, 400); //right wall
+ spawn.mapRect(5700, -3300, 1800, 5100); //right wall
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
+ spawn.mapRect(5403, -650, 400, 450); //blocking exit
+ if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { //pacifist run
+ for (let i = 0; i < 250; i++) spawn.starter(1000 + 4000 * Math.random(), -1500 * Math.random())
+ } else {
+ spawn.finalBoss(3000, -750)
+ }
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+
+ level.setPosToSpawn(0, -250);
+ level.custom = () => {
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ slime.query();
+ slime.levelRise(0.1)
+ ctx.fillStyle = "rgba(0,255,255,0.1)"
+ ctx.fillRect(-5385 - 300, -550, 300, 250)
+ };
+ }
+ if (mobs.mobDeaths < level.levelsCleared && localSettings.loreCount > 5 && !simulation.isCheating) {
+ //open door for pacifist run on final lore chapter
+ if (simulation.isHorizontalFlipped) {
+ level.exit.x = -5500 - 100;
+ } else {
+ level.exit.x = 5500;
+ }
+ level.exit.y = -330;
+ Matter.Composite.remove(engine.world, map[map.length - 1]);
+ map.splice(map.length - 1, 1);
+ simulation.draw.setPaths(); //redraw map draw path
+ level.levels.push("null")
+ }
+ },
+ gauntlet() {
+ level.custom = () => {
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,255,255,0.1)"
+ ctx.fillRect(6400, -550, 300, 350)
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(-175, -975, 900, 575)
+ };
+ level.setPosToSpawn(0, -475); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.x = 6500;
+ level.exit.y = -230;
+ level.defaultZoom = 1500
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#ddd";
+
+ // spawn.mapRect(-300, -1050, 300, 200);
+ // Matter.Body.setAngle(map[map.length - 1], -Math.PI / 4)
+
+
+ spawn.mapRect(-950, 0, 8200, 800); //ground
+ spawn.mapRect(-950, -1200, 800, 1400); //left wall
+ spawn.mapRect(-950, -1800, 8200, 800); //roof
+ spawn.mapRect(175, -700, 575, 950);
+ spawn.mapRect(-250, -425, 600, 650);
+ spawn.mapRect(-250, -1200, 1000, 250); // shelf roof
+ powerUps.spawnStartingPowerUps(600, -800);
+ spawn.blockDoor(710, -710);
+ spawn.mapRect(2500, -1200, 200, 750); //right wall
+ spawn.blockDoor(2585, -210)
+ spawn.mapRect(2500, -200, 200, 300); //right wall
+
+ spawn.mapRect(4500, -1200, 200, 750); //right wall
+ spawn.blockDoor(4585, -210)
+ spawn.mapRect(4500, -200, 200, 300); //right wall
+
+ spawn.mapRect(6400, -1200, 400, 750); //right wall
+ spawn.mapRect(6400, -200, 400, 300); //right wall
+ spawn.mapRect(6700, -1800, 800, 2600); //right wall
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
+
+
+ if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) { //pacifist run
+ // spawn.setSpawnList();
+ spawn.pickList.splice(0, 1);
+ spawn.pickList.push('starter');
+ spawn.pickList.splice(0, 1);
+ spawn.pickList.push('starter');
+ spawn.starter(1500, -200, 150 + Math.random() * 30);
+ spawn.nodeGroup(3500, -200, 'starter');
+ spawn.lineGroup(5000, -200, 'starter');
+ for (let i = 0; i < 3; ++i) {
+ if (simulation.difficulty * Math.random() > 15 * i) spawn.nodeGroup(2000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), 'starter');
+ if (simulation.difficulty * Math.random() > 10 * i) spawn.lineGroup(3500 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), 'starter');
+ if (simulation.difficulty * Math.random() > 7 * i) spawn.nodeGroup(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), 'starter');
+ }
+ } else {
+ spawn[spawn.pickList[0]](1500, -200, 150 + Math.random() * 30);
+ spawn.nodeGroup(3500, -200, spawn.allowedGroupList[Math.floor(Math.random() * spawn.allowedGroupList.length)]);
+ spawn.lineGroup(5000, -200, spawn.allowedGroupList[Math.floor(Math.random() * spawn.allowedGroupList.length)]);
+ for (let i = 0; i < 3; ++i) {
+ if (simulation.difficulty * Math.random() > 15 * i) spawn.randomGroup(2000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity);
+ if (simulation.difficulty * Math.random() > 10 * i) spawn.randomGroup(3500 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity);
+ if (simulation.difficulty * Math.random() > 7 * i) spawn.randomGroup(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity);
+ }
+ }
+ if (simulation.difficulty > 1) {
+ spawn.randomLevelBoss(5750, -600);
+ spawn.secondaryBossChance(4125, -350)
+ }
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+ level.setPosToSpawn(0, -475);
+ level.custom = () => {
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,255,255,0.1)"
+ ctx.fillRect(-6400 - 300, -550, 300, 350)
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(175 - 900, -975, 900, 575)
+ };
+ }
+ },
+ subway() {
+ // simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode
+ // level.difficultyIncrease(10 * 4);
+ // m.maxHealth = m.health = 100
+ // color.map = "#333" //custom map color
+ document.body.style.backgroundColor = "#e3e3e3"//"#e3e3e3"//color.map//"#333"//"#000"
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom)
+ level.setPosToSpawn(450 * (Math.random() < 0.5 ? 1 : -1), -300); //normal spawn
+ // spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //entrance bump disabled for performance
+ level.exit.x = 0;
+ level.exit.y = -9000;
+ // spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump disabled for performance
+
+ const stationWidth = 9000
+ let stationNumber = 0;
+ let stationCustom = () => { }
+ let stationCustomTopLayer = () => { }
+ const train = []
+ train.push(level.transport(1475, -200, 500, 25, 30))
+ train[train.length - 1].isMoving = false
+ train[train.length - 1].stops = { left: 1725, right: 7225 }
+ train.push(level.transport(-1475 - 500, -200, 500, 25, -30))
+ train[train.length - 1].isMoving = false
+ train[train.length - 1].stops = { left: -7225, right: -1725 }
+
+ const stationList = [] //use to randomize station order
+ for (let i = 1, totalNumberOfStations = 8; i < totalNumberOfStations; ++i) stationList.push(i) //!!!! update station number when you add a new station
+ shuffle(stationList);
+ stationList.splice(0, 3); //remove some stations to keep it to 4 stations
+ stationList.unshift(0) //add index zero to the front of the array
+
+ let isExitOpen = false
+ let gatesOpenRight = -1
+ let gatesOpenLeft = -1
+ const infrastructure = (x, isInProgress = true) => {
+ if (isInProgress) {
+ spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
+ function removeAll(array) {
+ for (let i = 0; i < array.length; ++i) Matter.Composite.remove(engine.world, array[i]);
+ }
+ removeAll(map);
+ map = [];
+ //remove any powerUp that is too far from player
+ for (let i = 0; i < powerUp.length; ++i) {
+ if (Vector.magnitudeSquared(Vector.sub(player.position, powerUp[i].position)) > 9000000) { //remove any powerUp farther then 3000 pixels from player
+ Matter.Composite.remove(engine.world, powerUp[i]);
+ powerUp.splice(i--, 1)
+ }
+ }
+ //remove any mob that is too far from player
+ for (let i = 0; i < mob.length; ++i) {
+ if (Vector.magnitudeSquared(Vector.sub(player.position, mob[i].position)) > 4000000) { //remove any mob farther then 2000 pixels from player
+ mob[i].removeConsBB()
+ mob[i].removeCons()
+ mob[i].leaveBody = false
+ mob[i].alive = false
+ Matter.Composite.remove(engine.world, mob[i]);
+ mob.splice(i--, 1)
+ }
+ }
+ }
+ const checkGate = (gate, gateButton) => {
+ if (gate) { //check status of buttons and gates
+ gate.isClosing = gateButton.isUp
+ gate.openClose(true);
+ if (gateButton.isUp) {
+ gateButton.query();
+ if (!gateButton.isUp) {
+ if (stationNumber > 0) {
+ if (!isExitOpen && gatesOpenRight < stationNumber) level.newLevelOrPhase() //run some new level tech effects
+ gatesOpenRight = stationNumber
+ } else if (stationNumber < 0) {
+ if (!isExitOpen && gatesOpenLeft > stationNumber) level.newLevelOrPhase() //run some new level tech effects
+ gatesOpenLeft = stationNumber
+ } else { //starting station both doors open
+ gatesOpenLeft = stationNumber
+ gatesOpenRight = stationNumber
+ }
+ if (Math.abs(stationNumber) > 0 && ((Math.abs(stationNumber) + 1) % stationList.length) === 0) {
+ simulation.makeTextLog(`exit opened`);
+ isExitOpen = true;
+ }
+ }
+ }
+ gateButton.draw();
+ }
+ }
+ const stations = [ //update totalNumberOfStations as you add more stations
+ () => { //empty starting station
+ if (isExitOpen) {
+ level.exit.x = x - 50;
+ level.exit.y = -260;
+ } else {
+ var gateButton = level.button(x - 62, -237, 125, false) //x, y, width = 126, isSpawnBase = true
+ gateButton.isUp = true
+ if (stationNumber === 0 && gatesOpenRight === -1 && gatesOpenLeft === -1) {
+ var gateR = level.doorMap(x + 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ var gateL = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ for (let i = 0; i < 10; ++i) powerUps.chooseRandomPowerUp(x + 800 * (Math.random() - 0.5), -300 - 100 * Math.random())//only spawn heal or ammo once at the first station
+ }
+ }
+
+ spawn.mapRect(x + -1400, -750, 3375, 100); //roof
+ spawn.mapRect(x + -1500, -210, 3000, 400);//station floor
+ // spawn.mapRect(x + -550, -220, 1125, 100); //floor
+ // spawn.mapRect(x + -475, -230, 975, 150);//floor
+ spawn.mapVertex(x + 0, -200, "400 0 -400 0 -300 -80 300 -80"); //hexagon but wide
+
+ // spawn.mapRect(x + -1350, -550, 50, 150);
+ // spawn.mapRect(x + 1300, -550, 50, 150);
+ stationCustom = () => { };
+ stationCustomTopLayer = () => {
+ checkGate(gateR, gateButton)
+ checkGate(gateL, gateButton)
+ };
+ },
+ () => { //portal maze
+ const buttonsCoords = [{ x: x + 50, y: -1595 }, { x: x + 637, y: -2195 }, { x: x - 1487, y: -2145 }]
+ const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
+ if (isExitOpen) {
+ level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
+ level.exit.y = buttonsCoords[buttonsCoordsIndex].y - 25;
+ } else {
+ var gateButton = level.button(buttonsCoords[buttonsCoordsIndex].x, buttonsCoords[buttonsCoordsIndex].y, 126, false) //x, y, width = 126, isSpawnBase = true
+ gateButton.isUp = true
+ if (stationNumber > gatesOpenRight) {
+ var gate = level.doorMap(x + 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ } else if (stationNumber < gatesOpenLeft) {
+ var gate = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ }
+ }
+
+ spawn.mapRect(x + -1500, -210, 3000, 400);//station floor
+ spawn.mapRect(x + -1775, -1600, 3400, 1100); //center pillar
+ spawn.mapRect(x + -4100, -3325, 8000, 700); //roof
+ spawn.mapRect(x + -4100, -3325, 325, 1500);
+ spawn.mapRect(x + 3500, -3325, 400, 1500);
+ spawn.mapRect(x + -225, -575, 450, 425); //lower portal blocks
+
+ //upper parts
+ spawn.mapRect(x + -1425, -2400, 1900, 50);
+ spawn.mapRect(x + -775, -2750, 575, 1045);
+ spawn.mapRect(x + 475, -1900, 450, 375);
+ spawn.mapRect(x + 2225, -2300, 125, 350);
+ spawn.mapRect(x + 2550, -2350, 700, 50);
+ spawn.mapRect(x + 1375, -2850, 125, 650);
+ spawn.mapRect(x + 600, -2200, 200, 195);
+ spawn.mapRect(x + -3500, -2275, 825, 75);
+ spawn.mapRect(x + -1550, -2150, 250, 250);
+ spawn.mapRect(x + -2575, -2450, 275, 345);
+
+ if (!isExitOpen) {
+ if (Math.random() < 0.5) {
+ spawn.randomMob(x + 2850, -2425, 0);
+ spawn.randomMob(x + 2275, -2425, 0);
+ spawn.randomMob(x + 2000, -2150, 0);
+ spawn.randomMob(x + 1650, -2150, 0);
+ spawn.randomMob(x + 1000, -2475, 0);
+ spawn.randomMob(x + 725, -2450, 0);
+ spawn.randomMob(x + 525, -2175, 0);
+ spawn.randomMob(x + 200, -1950, 0);
+ spawn.randomMob(x + -25, -1825, 0);
+ spawn.randomMob(x + -975, -2000, 0);
+ spawn.randomMob(x + -1500, -2225, 0);
+ spawn.randomMob(x + 1850, -2125, 0);
+ spawn.randomMob(x + 225, -1975, 0);
+ spawn.randomMob(x + 25, -1950, 0);
+ spawn.randomMob(x + 25, -1950, 0);
+ } else {
+ spawn.randomMob(x + 250, -1850, 0);
+ spawn.randomMob(x + 225, -1950, 0);
+ spawn.randomMob(x + 125, -2000, 0);
+ spawn.randomMob(x + 0, -1800, 0);
+ spawn.randomMob(x + -1725, -2300, 0);
+ spawn.randomMob(x + -2025, -2175, 0);
+ spawn.randomMob(x + -2050, -2250, 0);
+ spawn.randomMob(x + -2000, -2350, 0);
+ spawn.randomMob(x + -2950, -2400, 0);
+ spawn.randomMob(x + -2775, -2400, 0);
+ spawn.randomMob(x + -2425, -2550, 0);
+ spawn.randomMob(x + 1950, -2225, 0);
+ spawn.randomMob(x + -2700, -2100, 0);
+ spawn.randomMob(x + -1925, -2175, 0);
+ spawn.randomMob(x + -825, -2050, 0);
+ }
+ }
+
+ const portal1 = level.portal({ x: x - 250, y: -310 }, Math.PI,
+ { x: x + -3750, y: -2100 }, 0)
+ const portal2 = level.portal({ x: x + 250, y: -310 }, 0,
+ { x: x + 3475, y: -2100 }, Math.PI)
+ const portal3 = level.portal({ x: x - 800, y: -2500 }, Math.PI,
+ { x: x - 175, y: -2500 }, 0)
+ const portal4 = level.portal({ x: x + 1275, y: -1700 }, Math.PI,
+ { x: x - 1275, y: -1700 }, 0)
+ stationCustom = () => {
+ portal1[2].query()
+ portal1[3].query()
+ portal2[2].query()
+ portal2[3].query()
+ portal3[2].query()
+ portal3[3].query()
+ portal4[2].query()
+ portal4[3].query()
+ }
+ stationCustomTopLayer = () => {
+ checkGate(gate, gateButton)
+ portal1[0].draw();
+ portal1[1].draw();
+ portal1[2].draw();
+ portal1[3].draw();
+ portal2[0].draw();
+ portal2[1].draw();
+ portal2[2].draw();
+ portal2[3].draw();
+ portal3[0].draw();
+ portal3[1].draw();
+ portal3[2].draw();
+ portal3[3].draw();
+ portal4[0].draw();
+ portal4[1].draw();
+ portal4[2].draw();
+ portal4[3].draw();
+ }
+ },
+ () => { //opening and closing doors
+ const buttonsCoords = [{ x: x - 800, y: -2245 }, { x: x + 250, y: -870 }, { x: x + 1075, y: -1720 }, { x: x - 1600, y: -1995 }]
+ const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
+ if (isExitOpen) {
+ level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
+ level.exit.y = buttonsCoords[buttonsCoordsIndex].y - 25;
+ } else {
+ var gateButton = level.button(buttonsCoords[buttonsCoordsIndex].x, buttonsCoords[buttonsCoordsIndex].y, 126, false) //x, y, width = 126, isSpawnBase = true
+ gateButton.isUp = true
+ if (stationNumber > gatesOpenRight) {
+ var gate = level.doorMap(x + 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ } else if (stationNumber < gatesOpenLeft) {
+ var gate = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ }
+ }
+
+ if (!isExitOpen) {
+ if (Math.random() < 0.5) {
+ spawn.randomMob(x + 1125, -650, 0);
+ spawn.randomMob(x + 150, -950, 0);
+ spawn.randomMob(x + 100, -975, 0);
+ spawn.randomMob(x + 75, -975, 0);
+ spawn.randomMob(x + 275, -1225, 0);
+ spawn.randomMob(x + 825, -975, 0);
+ spawn.randomMob(x + -50, -1625, 0);
+ spawn.randomMob(x + -950, -1550, 0);
+ spawn.randomMob(x + -975, -1550, 0);
+ spawn.randomMob(x + -900, -2500, 0);
+ spawn.randomMob(x + -975, -2550, 0);
+ spawn.randomMob(x + 675, -1950, 0);
+ spawn.randomMob(x + 675, -2550, 0);
+ spawn.randomMob(x + 1225, -1825, 0);
+ spawn.randomMob(x + -750, -2450, 0);
+ spawn.randomMob(x + -700, -825, 0);
+ } else {
+ spawn.randomMob(x + -675, -675, 0);
+ spawn.randomMob(x + -575, -925, 0);
+ spawn.randomMob(x + -425, -1100, 0);
+ spawn.randomMob(x + -225, -1225, 0);
+ spawn.randomMob(x + -650, -1250, 0);
+ spawn.randomMob(x + -675, -775, 0);
+ spawn.randomMob(x + 75, -1000, 0);
+ spawn.randomMob(x + -1100, -1575, 0);
+ spawn.randomMob(x + -1250, -1850, 0);
+ spawn.randomMob(x + -1625, -2100, 0);
+ spawn.randomMob(x + -700, -2500, 0);
+ spawn.randomMob(x + -375, -2550, 0);
+ spawn.randomMob(x + 250, -2025, 0);
+ spawn.randomMob(x + 675, -2175, 0);
+ spawn.randomMob(x + -1000, -2000, 0);
+ spawn.randomMob(x + -1550, -2325, 0);
+ spawn.randomMob(x + -1725, -2425, 0);
+ }
+ }
+
+ spawn.mapRect(x + -1500, -210, 3000, 400);//station floor
+ spawn.mapRect(x + -2550, -3200, 425, 1375);//roof left wall
+ spawn.mapRect(x + 2125, -3175, 450, 1375);//roof right wall
+ spawn.mapRect(x + -2550, -3200, 5125, 225);//roof
+
+ spawn.mapRect(x + -1325, -550, 1375, 50);//first floor roof/ground
+ spawn.mapRect(x + 775, -550, 675, 50);
+ spawn.mapRect(x + -200, -875, 1300, 50); //2nd floor roof/ground
+ spawn.mapRect(x + -125, -1125, 50, 275);
+ spawn.mapRect(x + -125, -1150, 800, 50); //3rd floor roof/ground
+ spawn.mapRect(x + -1450, -1475, 1600, 50);
+ spawn.mapRect(x + -1325, -1725, 800, 50); //4th floor roof/ground
+ spawn.mapRect(x + 50, -1725, 1350, 50);
+ spawn.mapRect(x + -1125, -2250, 700, 50);
+
+ spawn.mapRect(x, -525, 50, 150); //door cap for ground at ground y = -210
+ const door1 = level.doorMap(x + 12, -380, 25, 170, 140, 20, false) //x, y, width, height, distance, speed = 20
+ spawn.mapRect(x - 200, -525 - 340, 50, 150); //door cap for ground at ground y = -210
+ const door2 = level.doorMap(x - 188, -380 - 340, 25, 170, 140, 20, false) //x, y, width, height, distance, speed = 20
+ spawn.mapRect(x + 100, -525 - 940, 50, 150); //door cap for ground at ground y = -210
+ const door3 = level.doorMap(x + 112, -380 - 940, 25, 170, 140, 20, false) //x, y, width, height, distance, speed = 20
+ spawn.mapRect(x + 450, -3050, 50, 775);
+ const door4 = level.doorMap(x + 462, -2300, 25, 575, 520, 30, false) //x, y, width, height, distance, speed = 20
+
+ const portal1 = level.portal({
+ x: x + 2100,
+ y: -2100
+ }, Math.PI, { //right
+ x: x + -1275,
+ y: -650
+ }, 2 * Math.PI) //right
+
+ stationCustom = () => {
+ door1.isClosing = (simulation.cycle % 240) < 120
+ door1.openClose(true);
+ door2.isClosing = (simulation.cycle % 240) > 120
+ door2.openClose(true);
+ door3.isClosing = (simulation.cycle % 240) < 120
+ door3.openClose(true);
+ door4.isClosing = (simulation.cycle % 240) > 120
+ door4.openClose(true);
+ portal1[2].query()
+ portal1[3].query()
+ }
+ stationCustomTopLayer = () => {
+ checkGate(gate, gateButton)
+ portal1[0].draw();
+ portal1[1].draw();
+ portal1[2].draw();
+ portal1[3].draw();
+ }
+ },
+ () => { //slime
+ const buttonsCoords = [{ x: x - 675, y: -895 }, { x: x - 750, y: -70 }, { x: x + 75, y: -570 },]
+ const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
+ if (isExitOpen) {
+ level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
+ level.exit.y = buttonsCoords[buttonsCoordsIndex].y - 25;
+ } else {
+ var gateButton = level.button(buttonsCoords[buttonsCoordsIndex].x, buttonsCoords[buttonsCoordsIndex].y, 126, false) //x, y, width = 126, isSpawnBase = true
+ gateButton.isUp = true
+ if (stationNumber > gatesOpenRight) {
+ var gate = level.doorMap(x + 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ } else if (stationNumber < gatesOpenLeft) {
+ var gate = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ }
+ }
+
+
+ spawn.mapRect(x + -1575, -2000, 3025, 100); //roof
+ // spawn.mapRect(x + -1575, -2200, 3025, 300); //roof
+ // spawn.mapRect(x + -1500, -210, 3000, 400);//station floor
+ spawn.mapRect(x + -1500, -210, 500, 350); //station floor left
+ spawn.mapRect(x + 1000, -210, 500, 350); //station floor right
+ spawn.mapRect(x + 900, -1250, 125, 1250);
+ spawn.mapRect(x - 1025, -1550, 125, 1625);
+ spawn.mapRect(x - 50, -1900, 100, 1500);
+ spawn.mapRect(x + -975, -1250, 200, 25);
+ spawn.mapRect(x + -950, -625, 150, 25);
+ spawn.mapRect(x - 925, -400, 250, 175);
+ spawn.mapRect(x - 725, -900, 225, 300);
+ spawn.mapRect(x + 325, -225, 325, 75);
+ spawn.mapRect(x + 400, -950, 275, 25);
+ spawn.mapRect(x + 775, -575, 200, 25);
+ spawn.mapRect(x + 0, -1225, 125, 25);
+ spawn.mapRect(x + 0, -575, 225, 175);
+ spawn.mapRect(x - 925, -75, 875, 150);
+ spawn.mapRect(x + 475, -1400, 75, 1250);
+
+ if (!isExitOpen) {
+ if (Math.random() < 0.5) {
+ spawn.randomMob(x + -850, -450, 0);
+ spawn.randomMob(x + -850, -125, 0);
+ spawn.randomMob(x + -725, -100, 0);
+ spawn.randomMob(x + 0, -100, 0);
+ spawn.randomMob(x + 800, -50, 0);
+ spawn.randomMob(x + 50, -275, 0);
+ spawn.randomMob(x + -300, -425, 0);
+ spawn.randomMob(x + -750, -475, 0);
+ spawn.randomMob(x + -850, -775, 0);
+ spawn.randomMob(x + -650, -1000, 0);
+ spawn.randomMob(x + -150, -1325, 0);
+ spawn.randomMob(x + -825, -1350, 0);
+ spawn.randomMob(x + -375, -150, 0);
+ } else {
+ spawn.randomMob(x + 350, -350, 0);
+ spawn.randomMob(x + 175, -700, 0);
+ spawn.randomMob(x + 350, -1175, 0);
+ spawn.randomMob(x + 200, -1600, 0);
+ spawn.randomMob(x + 500, -1675, 0);
+ spawn.randomMob(x + 425, -50, 0);
+ spawn.randomMob(x + 725, -75, 0);
+ spawn.randomMob(x + 650, -700, 0);
+ spawn.randomMob(x + 775, -1150, 0);
+ spawn.randomMob(x + 500, -1675, 0);
+ spawn.randomMob(x + -150, -175, 0);
+ spawn.randomMob(x + -800, -150, 0);
+ }
+ }
+
+ const boost1 = level.boost(x - 1185, -225, 1400)
+ const boost2 = level.boost(x + 1100, -225, 1100)
+ const hazard1 = level.hazard(x - 900, -1225, 1800, 1225)
+ let isSlimeRiseUp = false
+ const drip = []
+ drip.push(level.drip(x - 900 + 1800 * Math.random(), -1900, 0, 100)) // drip(x, yMin, yMax, period = 100, color = "hsla(160, 100%, 35%, 0.5)") {
+ drip.push(level.drip(x - 900 + 1800 * Math.random(), -1900, 0, 150))
+ drip.push(level.drip(x - 900 + 1800 * Math.random(), -1900, 0, 70))
+ // drip.push(level.drip(x - 900 + 1800 * Math.random(), -1900, 0, 210))
+ // drip.push(level.drip(x - 900 + 1800 * Math.random(), -1900, 0, 67))
+ stationCustom = () => {
+ for (let i = 0; i < drip.length; i++) drip[i].draw()
+ // drip1.draw();
+ // drip2.draw();
+ // drip3.draw();
+ }
+ stationCustomTopLayer = () => {
+ checkGate(gate, gateButton)
+
+ hazard1.query();
+ hazard1.level(isSlimeRiseUp, 1.5)
+ if (!(hazard1.height < hazard1.maxHeight)) {
+ isSlimeRiseUp = false
+ } else if (!(hazard1.height > 0)) {
+ isSlimeRiseUp = true
+ }
+ boost1.query();
+ boost2.query();
+ }
+ },
+ () => { //portal fling
+ const buttonsCoords = [{ x: x + 775, y: -1695 }, { x: x - 775, y: -800 }, { x: x - 375, y: -2083 },]
+ const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
+ if (isExitOpen) {
+ level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
+ level.exit.y = buttonsCoords[buttonsCoordsIndex].y - 25;
+ } else {
+ var gateButton = level.button(buttonsCoords[buttonsCoordsIndex].x, buttonsCoords[buttonsCoordsIndex].y, 126, false) //x, y, width = 126, isSpawnBase = true
+ gateButton.isUp = true
+ if (stationNumber > gatesOpenRight) {
+ var gate = level.doorMap(x + 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ } else if (stationNumber < gatesOpenLeft) {
+ var gate = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ }
+ }
+ spawn.mapRect(x + -1600, -3450, 300, 1475); //roof
+ spawn.mapRect(x + -1600, -3450, 3225, 100);
+ spawn.mapRect(x + 1300, -3450, 325, 1525);
+
+ spawn.mapVertex(x + 400, -180, "-300 0 -300 -100 300 -100 400 0");
+ spawn.mapVertex(x - 400, -180, "300 0 300 -100 -300 -100 -400 0");
+ spawn.mapRect(x + -1500, -210, 1425, 350); //station floor left
+ spawn.mapRect(x + 75, -210, 1425, 350); //station floor right
+ spawn.mapRect(x + 75, -950, 50, 450);
+ spawn.mapRect(x + 125, -700, 1225, 200);
+ spawn.mapRect(x + -1325, -1775, 775, 175);
+ spawn.mapVertex(x + 445, -800, "-200 0 -200 -300 100 -300 185 0");
+ spawn.mapVertex(x - 310, -1880, "-185 0 -100 -400 400 -400 400 0");
+ spawn.mapVertex(x + -675, -725, "325 0 250 80 -250 80 -325 0 -250 -80 250 -80");
+ spawn.mapRect(x + 625, -1700, 750, 500);
+
+ if (!isExitOpen) {
+ spawn.randomMob(x + -750, -1925, 0);
+ spawn.randomMob(x + -425, -2300, 0);
+ spawn.randomMob(x + -350, -2200, 0);
+ spawn.randomMob(x + -275, -2175, 0);
+ spawn.randomMob(x + -375, -2175, 0);
+ spawn.randomMob(x + 1075, -1850, 0);
+ spawn.randomMob(x + 925, -1775, 0);
+ spawn.randomMob(x + 1150, -1800, 0);
+ spawn.randomMob(x + 1400, -2150, 0);
+ spawn.randomMob(x + 925, -850, 0);
+ spawn.randomMob(x + 800, -800, 0);
+ spawn.randomMob(x + 875, -825, 0);
+ spawn.randomMob(x + 1050, -900, 0);
+ spawn.randomMob(x + 19050, -2925, 0);
+ spawn.randomMob(x + 17150, -3150, 0);
+ spawn.randomMob(x + 17700, -3300, 0);
+ }
+ const portal1 = level.portal({
+ x: x + 0,
+ y: -200
+ }, -Math.PI / 2, { //up
+ x: x + 200,
+ y: -900
+ }, -Math.PI / 2) //up
+ const portal2 = level.portal({
+ x: x + 1275,
+ y: -800
+ }, Math.PI, { //right
+ x: x + -1275,
+ y: -1875
+ }, 2 * Math.PI) //right
+
+ stationCustom = () => {
+ portal1[2].query(true)
+ portal1[3].query(true)
+ portal2[2].query()
+ portal2[3].query()
+ }
+ stationCustomTopLayer = () => {
+ checkGate(gate, gateButton)
+ portal1[0].draw();
+ portal1[1].draw();
+ portal1[2].draw();
+ portal1[3].draw();
+ portal2[0].draw();
+ portal2[1].draw();
+ portal2[2].draw();
+ portal2[3].draw();
+ }
+ },
+ () => { //tower levels and squares
+ const buttonsCoords = [{ x: x - 300, y: -3120 }, { x: x + 600, y: -3020 }, { x: x - 575, y: -1770 }, { x: x - 450, y: -2370 }]
+ const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
+ if (isExitOpen) {
+ level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
+ level.exit.y = buttonsCoords[buttonsCoordsIndex].y - 25;
+ } else {
+ var gateButton = level.button(buttonsCoords[buttonsCoordsIndex].x, buttonsCoords[buttonsCoordsIndex].y, 126, false) //x, y, width = 126, isSpawnBase = true
+ gateButton.isUp = true
+ if (stationNumber > gatesOpenRight) {
+ var gate = level.doorMap(x + 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ } else if (stationNumber < gatesOpenLeft) {
+ var gate = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ }
+ }
+
+ spawn.mapRect(x + -1500, -210, 3000, 400);//station floor
+ spawn.mapRect(x + -1625, -3950, 3225, 350);//roof
+ spawn.mapRect(x + 1300, -3850, 300, 2150); //roof wall
+ spawn.mapRect(x + -1625, -3950, 325, 2250); //roof wall
+ spawn.mapRect(x + -1050, -575, 1000, 75);
+ spawn.mapRect(x + 175, -575, 975, 75);
+ spawn.mapRect(x + -1050, -825, 150, 275);
+ spawn.mapRect(x + -900, -1200, 2275, 75);
+ spawn.mapRect(x + 125, -1425, 1250, 300);
+ spawn.mapRect(x + -925, -1775, 2100, 75);
+ spawn.mapRect(x + -100, -2050, 950, 350);
+ spawn.mapRect(x + -925, -2100, 100, 400);
+ spawn.mapRect(x + -700, -2375, 1225, 75);
+ spawn.mapRect(x + 650, -2375, 575, 75);
+ spawn.mapRect(x + -25, -2750, 350, 269);
+ spawn.mapRect(x + -950, -3125, 975, 75);
+ spawn.mapRect(x + 325, -3025, 900, 75);
+ spawn.bodyRect(x + -125, -1325, 225, 125, 0.3);
+ spawn.bodyRect(x + -225, -2100, 300, 50, 0.3);
+ spawn.bodyRect(x + -225, -2575, 100, 200, 0.3);
+ spawn.bodyRect(x + 850, -2575, 150, 200, 0.3);
+ spawn.bodyRect(x + 850, -1875, 75, 100, 0.3);
+ spawn.bodyRect(x + 500, -725, 175, 150, 0.3);
+ spawn.bodyRect(x + -925, -2250, 100, 150, 0.3);
+ spawn.bodyRect(x + -1050, -950, 150, 125, 0.3);
+
+ const mobPlacement = [
+ () => { //1st floor
+ spawn.randomMob(x + -775, -725, 0);
+ spawn.randomMob(x + -575, -700, 0);
+ spawn.randomMob(x + -275, -700, 0);
+ spawn.randomMob(x + -125, -650, 0);
+ spawn.randomMob(x + 250, -675, 0);
+ spawn.randomMob(x + 425, -650, 0);
+ spawn.randomMob(x + 775, -650, 0);
+ spawn.randomMob(x + 1050, -675, 0);
+ spawn.randomMob(x + 675, -950, 0);
+ spawn.randomMob(x + -625, -900, 0);
+ spawn.randomMob(x + -750, -1400, 0);
+ spawn.randomMob(x + -500, -2025, 0);
+ spawn.randomMob(x + -125, -3225, 0);
+ },
+ () => { //2nd floor
+ spawn.randomMob(x + -950, -925, 0);
+ spawn.randomMob(x + -775, -1325, 0);
+ spawn.randomMob(x + -450, -1500, 0);
+ spawn.randomMob(x + -325, -1250, 0);
+ spawn.randomMob(x + 0, -1500, 0);
+ spawn.randomMob(x + 375, -1525, 0);
+ spawn.randomMob(x + 750, -1550, 0);
+ spawn.randomMob(x + 1175, -1550, 0);
+ spawn.randomMob(x + -875, -1350, 0);
+ spawn.randomMob(x + -875, -2375, 0);
+ spawn.randomMob(x + 175, -2850, 0);
+ spawn.randomMob(x + 750, -2475, 0);
+ },
+ () => {//3rd floor
+ spawn.randomMob(x + 1075, -2000, 0);
+ spawn.randomMob(x + 725, -2125, 0);
+ spawn.randomMob(x + 350, -2125, 0);
+ spawn.randomMob(x + -325, -2000, 0);
+ spawn.randomMob(x + -675, -1875, 0);
+ spawn.randomMob(x + -725, -2200, 0);
+ spawn.randomMob(x + -675, -2575, 0);
+ spawn.randomMob(x + -425, -2675, 0);
+ spawn.randomMob(x + -50, -2875, 0);
+ spawn.randomMob(x + 425, -2725, 0);
+ spawn.randomMob(x + 1150, -2550, 0);
+ spawn.randomMob(x + 1150, -2175, 0);
+ spawn.randomMob(x + 1000, -1900, 0);
+ spawn.randomMob(x + 500, -2550, 0);
+ spawn.randomMob(x + 125, -2900, 0);
+ },
+ () => {//all floors
+ spawn.randomMob(x + 1000, -850, 0);
+ spawn.randomMob(x + 300, -850, 0);
+ spawn.randomMob(x + -450, -825, 0);
+ spawn.randomMob(x + -1025, -1125, 0);
+ spawn.randomMob(x + -750, -1375, 0);
+ spawn.randomMob(x + -225, -1375, 0);
+ spawn.randomMob(x + 625, -1525, 0);
+ spawn.randomMob(x + 1025, -1925, 0);
+ spawn.randomMob(x + -425, -2100, 0);
+ spawn.randomMob(x + -400, -2650, 0);
+ spawn.randomMob(x + 150, -3000, 0);
+ spawn.randomMob(x + 675, -3200, 0);
+ spawn.randomMob(x + -550, -3300, 0);
+
+ },
+ ]
+ if (!isExitOpen) mobPlacement[Math.floor(Math.random() * mobPlacement.length)]()//different random mob placements, with mobs clustered to surprise player
+ stationCustom = () => { }
+ stationCustomTopLayer = () => {
+ checkGate(gate, gateButton)
+ }
+ },
+ () => { //jump pads and 6 sided platforms
+ const buttonsCoords = [{ x: x + 275, y: -1817 }, { x: x + 2025, y: -1995 }, { x: x - 2025, y: -2420 }, { x: x - 2100, y: -1995 }]
+ const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
+ if (isExitOpen) {
+ level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
+ level.exit.y = buttonsCoords[buttonsCoordsIndex].y - 25;
+ } else {
+ var gateButton = level.button(buttonsCoords[buttonsCoordsIndex].x, buttonsCoords[buttonsCoordsIndex].y, 126, false) //x, y, width = 126, isSpawnBase = true
+ gateButton.isUp = true
+ if (stationNumber > gatesOpenRight) {
+ var gate = level.doorMap(x + 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ } else if (stationNumber < gatesOpenLeft) {
+ var gate = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ }
+ }
+
+ spawn.mapRect(x + -1500, -210, 3000, 400);//station floor
+ spawn.mapRect(x + -3200, -3200, 300, 1400); //roof left wall
+ spawn.mapRect(x + 2600, -3200, 300, 1400);//roof right wall
+ spawn.mapRect(x + -3175, -3200, 6175, 225);//roof
+ if (Math.random() < 0.3) spawn.mapRect(x + -1350, -550, 150, 50); //wall ledge
+ if (Math.random() < 0.3) spawn.mapRect(x + 1175, -550, 200, 50); //wall ledge
+ spawn.mapVertex(x + 600, -900, "490 0 350 80 -350 80 -490 0 -350 -80 350 -80"); //hexagon but wide
+ spawn.mapVertex(x - 600, -750, "490 0 350 80 -350 80 -490 0 -350 -80 350 -80"); //hexagon but wide
+ spawn.mapVertex(x - 100, -1850, "-100 -300 0 -350 100 -300 100 300 0 350 -100 300"); //hexagon but tall
+ spawn.mapVertex(x + -600, -2000, "-150 -450 150 -450 150 450 0 525 -150 450"); //hexagon but big and tall and flat
+ spawn.mapVertex(x + 350, -1575, "-150 0 150 0 150 450 0 525 -150 450"); //hexagon but tall and flat top
+ spawn.mapVertex(x + 850, -1575, "-150 0 150 0 150 450 0 525 -150 450"); //hexagon but tall and flat top
+ spawn.mapVertex(x + -2050, -2350, "490 0 350 80 -350 80 -490 0 -350 -80 350 -80"); //left top corner hexagon but wide
+ spawn.mapVertex(x + 1700, -2450, "-100 -300 0 -350 100 -300 100 300 0 350 -100 300"); //hexagon but tall
+
+ const mobPlacement = [
+ () => { //rightish
+ spawn.randomMob(x + 2250, -2375, 0);
+ spawn.randomMob(x + 1950, -2825, 0);
+ spawn.randomMob(x + 1275, -2775, 0);
+ spawn.randomMob(x + 1450, -2200, 0);
+ spawn.randomMob(x + 825, -1950, 0);
+ spawn.randomMob(x + 400, -1875, 0);
+ spawn.randomMob(x + -75, -2275, 0);
+ spawn.randomMob(x + -650, -2550, 0);
+ spawn.randomMob(x + 1500, -2075, 0);
+ spawn.randomMob(x + 2125, -2650, 0);
+ spawn.randomMob(x + 2075, -2250, 0);
+ spawn.randomMob(x + 1000, -2850, 0);
+ spawn.randomMob(x + 750, -950, 0);
+ spawn.randomMob(x + -750, -1125, 0);
+ spawn.randomMob(x + -1575, -2050, 0);
+ },
+ () => { //leftish
+ spawn.randomMob(x + -2225, -2125, 0);
+ spawn.randomMob(x + -2675, -2125, 0);
+ spawn.randomMob(x + -2600, -2600, 0);
+ spawn.randomMob(x + -2100, -2725, 0);
+ spawn.randomMob(x + -1425, -2600, 0);
+ spawn.randomMob(x + -1375, -2050, 0);
+ spawn.randomMob(x + -575, -2575, 0);
+ spawn.randomMob(x + -125, -2300, 0);
+ spawn.randomMob(x + 350, -1925, 0);
+ spawn.randomMob(x + -350, -1050, 0);
+ spawn.randomMob(x + -1000, -1000, 0);
+ spawn.randomMob(x + -700, -1300, 0);
+ spawn.randomMob(x + 350, -1150, 0);
+ spawn.randomMob(x + -575, -2525, 0);
+ spawn.randomMob(x + -1075, -2525, 0);
+ },
+ () => {//centerish
+ spawn.randomMob(x + 25, -2275, 0);
+ spawn.randomMob(x + 300, -1975, 0);
+ spawn.randomMob(x + 700, -1950, 0);
+ spawn.randomMob(x + 325, -1200, 0);
+ spawn.randomMob(x + -225, -950, 0);
+ spawn.randomMob(x + -925, -975, 0);
+ spawn.randomMob(x + -675, -2575, 0);
+ spawn.randomMob(x + -1425, -2175, 0);
+ spawn.randomMob(x + 1575, -2075, 0);
+ spawn.randomMob(x + 2300, -2075, 0);
+ spawn.randomMob(x + 425, -1925, 0);
+ spawn.randomMob(x + 125, -2175, 0);
+ spawn.randomMob(x + -325, -2150, 0);
+ spawn.randomMob(x + -350, -950, 0);
+ spawn.randomMob(x + 600, -325, 0);
+ spawn.randomMob(x + -600, -375, 0);
+ },
+ ]
+ if (!isExitOpen) mobPlacement[Math.floor(Math.random() * mobPlacement.length)]()//different random mob placements, with mobs clustered to surprise player
+ const boost1 = level.boost(x - 50, -225, 790)
+ const boost2 = level.boost(x + 550, -985, 900)
+ const boost3 = level.boost(x + -850, -835, 1900)
+ stationCustom = () => { }
+ stationCustomTopLayer = () => {
+ checkGate(gate, gateButton)
+ boost1.query();
+ boost2.query();
+ boost3.query();
+ }
+ },
+ () => { //crouch tunnels
+ const buttonsCoords = [{ x: x + 625, y: -1395 }, { x: x - 15, y: -1595 }, { x: x - 800, y: -1295 }]
+ const buttonsCoordsIndex = Math.floor(Math.random() * buttonsCoords.length) //pick a random element from the array
+ if (isExitOpen) {
+ level.exit.x = buttonsCoords[buttonsCoordsIndex].x;
+ level.exit.y = buttonsCoords[buttonsCoordsIndex].y - 25;
+ } else {
+ var gateButton = level.button(buttonsCoords[buttonsCoordsIndex].x, buttonsCoords[buttonsCoordsIndex].y, 126, false) //x, y, width = 126, isSpawnBase = true
+ gateButton.isUp = true
+ if (stationNumber > gatesOpenRight) {
+ var gate = level.doorMap(x + 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ } else if (stationNumber < gatesOpenLeft) {
+ var gate = level.doorMap(x - 1375, -525, 50, 375, 300, 20, false) //x, y, width, height, distance, speed = 20
+ }
+ }
+ spawn.mapRect(x + -1500, -210, 3000, 400);//station floor
+ spawn.mapRect(x + -1575, -2200, 3025, 300); //roof
+ spawn.mapRect(x + -1100, -925, 100, 425);
+ spawn.mapRect(x + -1100, -575, 375, 75);
+ spawn.mapRect(x + -925, -1300, 375, 125);
+ spawn.mapRect(x + -300, -1300, 620, 125);
+ spawn.mapRect(x + 450, -1400, 500, 225);
+ spawn.mapRect(x + 900, -550, 500, 50);
+ spawn.mapRect(x + 950, -925, 400, 270);
+ spawn.mapRect(x + 1250, -1250, 150, 75);
+ spawn.mapRect(x + -225, -525, 800, 210);
+ spawn.mapRect(x + -100, -1600, 300, 193);
+ spawn.mapRect(x + 925, -1250, 75, 75);
+ spawn.bodyRect(x + 200, -1475, 75, 175, 0.3);
+ spawn.bodyRect(x + -25, -625, 225, 100, 0.3);
+ spawn.bodyRect(x + -1000, -750, 125, 175, 0.3);
+ spawn.bodyRect(x + -625, -1450, 75, 150, 0.3);
+ spawn.bodyRect(x + -650, -300, 300, 75, 0.3);
+ if (!isExitOpen) {
+ spawn.randomMob(x + -750, -1425, 0);
+ spawn.randomMob(x + -1050, -1100, 0);
+ spawn.randomMob(x + -825, -750, 0);
+ spawn.randomMob(x + -500, -400, 0);
+ spawn.randomMob(x + 450, -650, 0);
+ spawn.randomMob(x + 0, -725, 0);
+ spawn.randomMob(x + 300, -1350, 0);
+ spawn.randomMob(x + 550, -1500, 0);
+ spawn.randomMob(x + 725, -1650, 0);
+ spawn.randomMob(x + 900, -1550, 0);
+ spawn.randomMob(x + 1100, -1300, 0);
+ spawn.randomMob(x + -1050, -1050, 0);
+ spawn.randomMob(x + -925, -350, 0);
+ spawn.randomMob(x + 75, -1750, 0);
+ spawn.randomMob(x + 1000, -375, 0);
+ }
+ stationCustom = () => { }
+ stationCustomTopLayer = () => {
+ checkGate(gate, gateButton)
+ ctx.fillStyle = "rgba(0,0,0,0.08)"
+ ctx.fillRect(x + -225, -325, 800, 125);
+ ctx.fillRect(x + -100, -1425, 300, 125);
+ ctx.fillRect(x + 950, -675, 400, 125);
+ }
+ },
+ ]
+ // stations[1]() //for testing a specific station
+ stations[stationList[Math.abs(stationNumber % stationList.length)]]() //*************** run this one when uploading
+ //add in standard station map infrastructure
+ spawn.mapRect(x + -8000, 0, 16000, 800);//tunnel floor
+ spawn.mapRect(x + 1500 - 200, -2000, 6400, 1500); //tunnel roof
+ spawn.mapRect(x + -1500 - 6400 + 200, -2000, 6400, 1500); //tunnel roof
+
+ // add debris so you can see how fast the train moves
+ const debrisCount = 4
+ const size = 18 + Math.random() * 25;
+ const wide = 6400
+ if (isInProgress) {
+ //adds new map elements to the level while the level is already running
+ for (let i = 0; i < map.length; ++i) {
+ map[i].collisionFilter.category = cat.map;
+ map[i].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(map[i], true); //make static
+ Composite.add(engine.world, map[i]); //add to world
+ }
+ simulation.draw.setPaths()
+ simulation.draw.lineOfSightPrecalculation() //required precalculation for line of sight
+
+
+ //shift trains left/right, as you move left or right a train will jump over and become the train needed at the next station
+ let repositionTrain
+ let playerOnTrain
+ if (Math.abs(train[0].position.x - m.pos.x) > Math.abs(train[1].position.x - m.pos.x)) { //figure out which train the player is farthest from and move it
+ repositionTrain = train[0]
+ playerOnTrain = train[1]
+ } else {
+ repositionTrain = train[1]
+ playerOnTrain = train[0]
+ }
+ repositionTrain.isMoving = false
+ if (repositionTrain.position.x > playerOnTrain.position.x) { //decide if the train is moving left or right
+ Matter.Body.setPosition(repositionTrain, { x: -1725 + x, y: repositionTrain.position.y });
+ repositionTrain.changeDirection(false) //go left
+ repositionTrain.stops = { right: -1725 + x, left: -7225 + x }
+ for (let i = 0; i < debrisCount; ++i) spawn.bodyRect(x + -1500 - 6400 + 200 + Math.random() * wide, -35, size * (0.6 + Math.random()), size * (0.6 + Math.random()), 1);
+ } else {
+ Matter.Body.setPosition(repositionTrain, { x: 1725 + x, y: repositionTrain.position.y });
+ repositionTrain.changeDirection(true) //go right
+ repositionTrain.stops = { left: 1725 + x, right: 7225 + x }
+ for (let i = 0; i < debrisCount; ++i) spawn.bodyRect(x + 1500 - 200 + Math.random() * wide, -35, size * (0.6 + Math.random()), size * (0.6 + Math.random()), 1);
+ }
+ } else {
+ for (let i = 0; i < debrisCount; ++i) spawn.bodyRect(x + -1500 - 6400 + 200 + Math.random() * wide, -35, size * (0.6 + Math.random()), size * (0.6 + Math.random()), 1);
+ for (let i = 0; i < debrisCount; ++i) spawn.bodyRect(x + 1500 - 200 + Math.random() * wide, -35, size * (0.6 + Math.random()), size * (0.6 + Math.random()), 1);
+ }
+ }
+ infrastructure(0, false) //if this is run before the level starts, it needs a false
+
+ level.custom = () => {
+ for (let i = 0; i < train.length; i++) train[i].trainStop()
+ ctx.fillStyle = "rgba(0,0,0,0.1)"//"#ddd"
+ ctx.fillRect(m.pos.x - 4000, m.pos.y - 4000, 8000, 8000)
+ level.exit.drawAndCheck();
+ // level.enter.draw();
+
+ //track what station the player is in
+ if (m.pos.x > 0.55 * stationWidth + stationNumber * stationWidth) {
+ stationNumber++
+ // if ((stationNumber % stationList.length) == 0) stationNumber++ //skip the stationNumber that is the modulus of the length of the stationList
+ infrastructure(stationNumber * stationWidth)
+ } else if (m.pos.x < -0.55 * stationWidth + stationNumber * stationWidth) {
+ stationNumber--
+ // if ((stationNumber % stationList.length) == 0) stationNumber--//skip the stationNumber that is the modulus of the length of the stationList
+ infrastructure(stationNumber * stationWidth)
+ }
+ stationCustom()
+ };
+ level.customTopLayer = () => {
+ for (let i = 0; i < train.length; i++) train[i].draw()
+ stationCustomTopLayer()
+ };
+ level.isProcedural = true //only used in generating text for the level builder
+ simulation.draw.lineOfSightPrecalculation() //required precalculation for line of sight
+ simulation.draw.drawMapPath = simulation.draw.drawMapSight
+ },
+ reservoir() {
+ level.exit.x = 1700;
+ level.exit.y = -4510;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25);
+ level.setPosToSpawn(-500, 850); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.defaultZoom = 2300
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d8dadf";
+ color.map = "#3d4240"
+ powerUps.spawnStartingPowerUps(-575, -2925)
+ //walls
+ spawn.mapRect(-3500, -5000, 1500, 6500);
+ spawn.mapRect(2000, -5000, 1500, 6500);
+ spawn.mapRect(-2500, 1100, 5000, 400); //slime floor
+ spawn.mapRect(-3500, -5475, 7000, 600); //top
+ spawn.mapRect(-1925, -4900, 175, 375); //pipe
+ spawn.mapRect(-1950, -4550, 225, 25); //pipe
+ //top floor exit
+ spawn.mapRect(1475, -4900, 50, 250);
+ spawn.mapRect(1400, -4475, 650, 50);
+ // ground
+ spawn.mapVertex(-687, 1060, "700 0 -700 0 -450 -300 450 -300"); //left base
+ spawn.mapVertex(863, 1060, "700 0 -700 0 -450 -300 450 -300"); //right base
+ //entrance
+ spawn.mapRect(-730, 525, 475, 50);
+ spawn.mapRect(-730, 550, 50, 150);
+ spawn.mapRect(-305, 550, 50, 500);
+ spawn.bodyRect(-717, 700, 25, 100); //door
+ spawn.bodyRect(-717, 800, 25, 100); //door
+ //1st floor //left
+ spawn.mapVertex(-1125 + 437, -50, "490 0 350 80 -350 80 -490 0 -350 -80 350 -80");
+ spawn.mapRect(-1225, -100, 1070, 100);
+ if (Math.random() < 0.33) {
+ spawn.mapVertex(-687, -1000, "-100 -300 0 -350 100 -300 100 300 0 350 -100 300");
+ } else if (Math.random() < 0.5) {
+ spawn.mapVertex(-687, -1000, "-150 -450 0 -525 150 -450 150 450 0 525 -150 450");
+ } else {
+ spawn.mapVertex(-687, -700, "-150 0 150 0 150 450 0 525 -150 450");
+ }
+ //right
+ spawn.mapVertex(425 + 437, -50, "490 0 350 80 -350 80 -490 0 -350 -80 350 -80");
+ spawn.mapRect(325, -100, 1070, 100);
+ spawn.mapRect(175, 675, 425, 25);
+ spawn.mapRect(1125, 225, 425, 25);
+ spawn.mapRect(650, 450, 425, 25);
+ if (Math.random() < 0.33) {
+ spawn.mapVertex(855, -1000, "-100 -300 0 -350 100 -300 100 300 0 350 -100 300");
+ } else if (Math.random() < 0.5) {
+ spawn.mapVertex(855, -1000, "-150 -450 0 -525 150 -450 150 450 0 525 -150 450");
+ } else {
+ spawn.mapVertex(855, -700, "-150 0 150 0 150 450 0 525 -150 450");
+ }
+ //2nd floor
+ spawn.mapVertex(-687, -1936, "-625 50 0 100 625 50 625 -50 -625 -50");
+ spawn.mapVertex(855, -1936, "-625 50 0 100 625 50 625 -50 -625 -50");
+ //2nd floor right building
+ spawn.mapRect(550, -3050, 600, 75);
+ spawn.bodyRect(-125, -2025, 475, 25);
+ spawn.mapRect(-925, -2350, 675, 50);
+ spawn.mapRect(-825, -2825, 425, 50);
+ spawn.mapRect(-450, -3125, 50, 350);
+ spawn.mapRect(-750, -3150, 350, 50);
+ spawn.mapRect(-650, -3400, 250, 300);
+ spawn.mapRect(-650, -3675, 200, 50);
+ spawn.bodyRect(-375, -2150, 100, 150, 0.2);
+ //2nd floor left pillar
+ spawn.mapRect(-1400, -2625, 325, 25);
+ spawn.mapRect(-1450, -3225, 425, 25);
+ spawn.mapRect(-1512.5, -3825, 550, 25);
+
+ spawn.randomMob(1000, -275, 0.2);
+ spawn.randomMob(950, -1725, 0.1);
+ spawn.randomMob(-725, -1775, 0.1);
+ spawn.randomMob(-200, -2075, 0);
+ spawn.randomMob(-550, -3500, -0.2);
+ spawn.randomMob(375, -2125, 0);
+ spawn.randomMob(-700, -2450, -0.1);
+ spawn.randomMob(-1175, -2775, -0.1);
+ spawn.randomMob(1025, -3200, -0.2);
+ spawn.randomMob(-525, -3750, -0.2);
+ spawn.randomMob(1350, -2075, -0.3);
+ spawn.randomMob(1775, 1000, -0.4);
+ spawn.randomSmallMob(-575, -2925);
+ spawn.randomGroup(-400, -4400, 0);
+ if (simulation.difficulty > 1) {
+ spawn.randomLevelBoss(825, -3500);
+ spawn.secondaryBossChance(75, -1350)
+ }
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ const slime = level.hazard(-2000, -5000, 4000, 6060); // hazard(x, y, width, height, damage = 0.003)
+ slime.height -= slime.maxHeight - 60 //start slime at zero
+ slime.min.y += slime.maxHeight
+ slime.max.y = slime.min.y + slime.height
+ const elevator1 = level.elevator(-1625, -90, 310, 800, -2000, 0.0025, { up: 0.1, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
+ const elevator2 = level.elevator(1175, -3050, 200, 250, -4475, 0.0025, { up: 0.12, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
+ let waterFallWidth = 0
+ let waterFallX = 0
+ let waterFallSmoothX = 0
+ let isWaterfallFilling = false
+ const riseRate = 0.30 + Math.min(1, simulation.difficulty * 0.005)
+ const spinnerArray = []
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ spawn.mapVertex(584, -2500, "0 0 300 0 150 600 0 600");
+ spawn.mapVertex(1116, -2500, "0 0 300 0 300 600 150 600");
+ spawn.bodyRect(-200, -125, 625, 25);
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+ elevator1.holdX = -elevator1.holdX // flip the elevator horizontally
+ elevator2.holdX = -elevator2.holdX // flip the elevator horizontally
+ spinnerArray.push(level.spinner(-110, -3325, 45, 600, 0.003, 0, 0, 0.01)) // spinner(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0) {
+ const boost1 = level.boost(-900, -2000, 790)
+ level.setPosToSpawn(500, 850); //normal spawn
+ level.custom = () => {
+ ctx.fillStyle = "#c0c3c9" ///!!!!!!!!!! for flipped x: newX = -oldX - width
+ ctx.fillRect(1468, -1975, 2, 1915) //elevator track
+ ctx.fillRect(-1274, -4460, 2, 1425) //elevator track
+ ctx.fillRect(1225, -3825, 25, 1850); //small pillar background
+ ctx.fillStyle = "#d0d4d6"
+ ctx.fillRect(275, -1925, 825, 2925) //large pillar background
+ ctx.fillRect(-1275, -1925, 825, 2925) //large pillar background
+ ctx.fillStyle = "#cff" //exit
+ ctx.fillRect(-2000, -4900, 525, 425)
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ boost1.query();
+ elevator1.move();
+ elevator2.move();
+ ctx.fillStyle = "#233"
+ ctx.beginPath(); //central dot on spinners
+ ctx.arc(spinnerArray[0].pointA.x, spinnerArray[0].pointA.y, 9, 0, 2 * Math.PI);
+ for (let i = 0, len = spinnerArray.length; i < len; i++) {
+ ctx.moveTo(spinnerArray[i].pointA.x, spinnerArray[i].pointA.y)
+ ctx.arc(spinnerArray[i].pointA.x, spinnerArray[i].pointA.y, 9, 0, 2 * Math.PI);
+ }
+ ctx.fill();
+ //shadow
+ ctx.fillStyle = "rgba(0,10,30,0.1)"
+ ctx.fillRect(-1150, -3000, 600, 1025);
+ ctx.fillRect(450, -3100, 300, 275);
+ ctx.fillRect(450, -3625, 200, 225);
+ ctx.fillRect(400, -2775, 425, 450);
+ ctx.fillRect(250, -2300, 675, 300);
+ slime.query();
+ if (isWaterfallFilling) {
+ if (slime.height < 5500) {
+ //draw slime fill
+ ctx.fillStyle = `hsla(160, 100%, 43%,${0.3 + 0.07 * Math.random()})`
+ ctx.fillRect(waterFallX, -5050, waterFallWidth, 6175 - slime.height)
+ if (!m.isBodiesAsleep) {
+ waterFallWidth = 0.98 * waterFallWidth + 4.7 * Math.random()
+ waterFallSmoothX = 0.98 * waterFallSmoothX + 3.5 * Math.random()
+ waterFallX = 1857 - waterFallSmoothX
+ ctx.fillRect(waterFallX + waterFallWidth * Math.random(), -5050, 4, 6175 - slime.height)
+ //push player down if they go under waterfall
+ if (player.position.x > waterFallX && player.position.x < waterFallX + waterFallWidth && player.position.y < slime.height) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 2
+ });
+ }
+ }
+ slime.levelRise(riseRate)
+ }
+ } else if (Vector.magnitudeSquared(Vector.sub(player.position, level.enter)) > 100000) {
+ isWaterfallFilling = true
+ }
+ };
+ } else { //not flipped
+ spawn.mapVertex(1116, -2500, "0 0 300 0 150 600 0 600");
+ spawn.mapVertex(584, -2500, "0 0 300 0 300 600 150 600");
+ if (Math.random() < 0.1) {
+ spinnerArray.push(level.spinner(65, -300, 40, 450, 0.003, Math.PI / 2))
+ } else if (Math.random() < 0.25) {
+ spinnerArray.push(level.spinner(65, -500, 40, 500, 0.003, 0, 0, -0.015)) // spinner(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0) {
+ const r = 250
+ const hexagon = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 ${r * Math.cos(2.0944)} ${r * Math.sin(2.0944)} ${r * Math.cos(1.0472)} ${r * Math.sin(1.0472)} `
+ Matter.Body.setVertices(spinnerArray[spinnerArray.length - 1].bodyB, Vertices.fromPath(hexagon))
+ } else {
+ const W = 410;
+ const H = 30;
+ spawn.bodyRect(-120, -75, W, H, 1, spawn.propsIsNotHoldable)
+ let b = body[body.length - 1];
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: b.position.x - (W / 2) + 50 - 211,
+ y: b.position.y - 1825
+ },
+ bodyB: b,
+ pointB: {
+ x: -(W / 2) + 50,
+ y: 0
+ },
+ damping: 0.01,
+ stiffness: 0.002,
+ length: 1800
+ });
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: b.position.x + (W / 2) - 50 + 211,
+ y: b.position.y - 1825
+ },
+ bodyB: b,
+ pointB: {
+ x: (W / 2) - 50,
+ y: 0
+ },
+ damping: 0.01,
+ stiffness: 0.002,
+ length: 1800
+ });
+ Composite.add(engine.world, [cons[cons.length - 1], cons[cons.length - 2]])
+ }
+
+ spinnerArray.push(level.spinner(50, -3325, 45, 600, 0.003, 0, 0, 0.01)) // spinner(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0) {
+ if (Math.random() < 0.5) {
+ const r = 200
+ const hexagon = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 ${r * Math.cos(2.0944)} ${r * Math.sin(2.0944)} ${r * Math.cos(1.0472)} ${r * Math.sin(1.0472)} `
+ Matter.Body.setVertices(spinnerArray[spinnerArray.length - 1].bodyB, Vertices.fromPath(hexagon))
+ }
+
+ const boost1 = level.boost(800, -2000, 790)
+
+ level.custom = () => {
+ ctx.fillStyle = "#c0c3c9"
+ ctx.fillRect(-1470, -1975, 2, 1915) //elevator track
+ ctx.fillRect(1276, -4460, 2, 1425) //elevator track
+ ctx.fillRect(-1250, -3825, 25, 1850); //small pillar background
+ ctx.fillStyle = "#d0d4d6"
+ ctx.fillRect(-1100, -1925, 825, 2925) //large pillar background
+ ctx.fillRect(450, -1925, 825, 2925) //large pillar background
+ ctx.fillStyle = "#cff" //exit
+ ctx.fillRect(1475, -4900, 525, 425)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+
+ level.customTopLayer = () => {
+ boost1.query();
+ elevator1.move();
+ elevator2.move();
+
+ ctx.fillStyle = "#233"
+ ctx.beginPath(); //central dot on spinners
+ ctx.arc(spinnerArray[0].pointA.x, spinnerArray[0].pointA.y, 9, 0, 2 * Math.PI);
+ for (let i = 0, len = spinnerArray.length; i < len; i++) {
+ ctx.moveTo(spinnerArray[i].pointA.x, spinnerArray[i].pointA.y)
+ ctx.arc(spinnerArray[i].pointA.x, spinnerArray[i].pointA.y, 9, 0, 2 * Math.PI);
+ }
+ ctx.fill();
+ //shadow
+ ctx.fillStyle = "rgba(0,10,30,0.1)"
+ ctx.fillRect(550, -3000, 600, 1025);
+ ctx.fillRect(-750, -3100, 300, 275);
+ ctx.fillRect(-650, -3625, 200, 225);
+ ctx.fillRect(-825, -2775, 425, 450);
+ ctx.fillRect(-925, -2300, 675, 300);
+
+ slime.query();
+ if (isWaterfallFilling) {
+ if (slime.height < 5500) {
+ //draw slime fill
+ ctx.fillStyle = `hsla(160, 100%, 43%,${0.3 + 0.07 * Math.random()})`
+ ctx.fillRect(waterFallX, -5050, waterFallWidth, 6175 - slime.height)
+ if (!m.isBodiesAsleep) {
+ waterFallWidth = 0.98 * waterFallWidth + 4.7 * Math.random()
+ waterFallSmoothX = 0.98 * waterFallSmoothX + 3.5 * Math.random()
+ waterFallX = waterFallSmoothX - 1985
+ ctx.fillRect(waterFallX + waterFallWidth * Math.random(), -5050, 4, 6175 - slime.height)
+ //push player down if they go under waterfall
+ if (player.position.x > waterFallX && player.position.x < waterFallX + waterFallWidth && player.position.y < slime.height) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 2
+ });
+ }
+ }
+ slime.levelRise(riseRate)
+ }
+ } else if (Vector.magnitudeSquared(Vector.sub(player.position, level.enter)) > 100000) {
+ isWaterfallFilling = true
+ }
+ };
+ }
+ },
+ reactor() {
+ level.exit.x = 3500;
+ level.exit.y = -42;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25);
+ level.defaultZoom = 2000
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#c3d6df" //"#d8dadf";
+ color.map = "#303639";
+ // powerUps.spawnStartingPowerUps(1475, -1175);
+ // spawn.debris(750, -2200, 3700, 16); //16 debris per level
+
+ spawn.bodyRect(250, -70, 100, 70, 1);
+ spawn.mapRect(-425, 0, 4500, 2100);
+ spawn.mapRect(-475, -2825, 4500, 1025);
+ // spawn.mapRect(1200, -1300, 600, 800);
+ const a = 400 //side length
+ const c = 100 //corner offset
+ spawn.mapVertex(1487, -900, `${-a} ${-a + c} ${-a + c} ${-a} ${a - c} ${-a} ${a} ${-a + c} ${a} ${a - c} ${a - c} ${a} ${-a + c} ${a} ${-a} ${a - c}`); //square with edges cut off
+ //entrance
+ spawn.mapRect(-2025, -2825, 1250, 4925);
+ spawn.mapRect(-900, -2825, 1125, 1725);
+ spawn.mapRect(-900, -750, 1125, 2850);
+ spawn.mapRect(-325, -1250, 550, 300);
+ //exit
+ spawn.mapRect(3800, -2825, 1225, 4925);
+ spawn.mapRect(2750, -2150, 1325, 1775);
+ spawn.mapRect(2750, -475, 550, 300);
+ spawn.mapRect(2750, -7, 1050, 150); //exit room floor
+
+ const doorIn = level.door(-313, -950, 525, 200, 190, 2) //x, y, width, height, distance, speed = 1
+ const doorOut = level.door(2762, -175, 525, 200, 190, 2) //x, y, width, height, distance, speed = 1
+ doorIn.collisionFilter.category = cat.map;
+ doorOut.collisionFilter.category = cat.map; // to prevent boson composite from letting the player skip the level
+ // doorOut.isClosing = true
+ let isDoorsLocked = false
+ let isFightOver = false
+ let isSpawnedBoss = false
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+ level.setPosToSpawn(550, -800); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+
+ const button = level.button(-1500, 0)
+ button.isUp = true
+
+ level.custom = () => {
+ if (isDoorsLocked) {
+ if (player.position.x > 300) { //if player gets trapped inside starting room open up again
+ isDoorsLocked = false
+ doorIn.isClosing = false
+ }
+ }
+ doorIn.openClose();
+ doorOut.openClose();
+ ctx.fillStyle = "#d5ebef"
+ ctx.fillRect(-3800, -375, 1050, 375)
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ button.draw();
+ if (button.isUp) {
+ button.query();
+ } else if (!isSpawnedBoss) {
+ if (player.position.x < 0) {
+ if (!doorOut.isClosed() || !doorIn.isClosed()) {
+ doorIn.isClosing = true
+ doorOut.isClosing = true
+ //block caught in a door
+ if (Matter.Query.collides(doorOut, body).length > 1 || Matter.Query.collides(doorIn, body).length > 1) {
+ button.isUp = true
+ doorIn.isClosing = false
+ doorOut.isClosing = false
+ }
+ } else {
+ isSpawnedBoss = true
+ isDoorsLocked = true
+ for (let i = 0; i < 9; ++i) powerUps.spawn(-1800 + 550 * Math.random(), -1700, "ammo")
+ for (let i = 0; i < 3; ++i) powerUps.spawn(-1800 + 550 * Math.random(), -1700, "heal");
+ const scale = Math.pow(simulation.difficulty, 0.7) //hard around 30, why around 54
+ if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) {
+ for (let i = 0; i < 250; i++) spawn.starter(-2700 + 2400 * Math.random(), -1300 - 500 * Math.random())
+ } else {
+ if (Math.random() < 0.07 && simulation.difficulty > 35) {
+ for (let i = 0, len = scale * 0.25 / 6; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15
+ for (let i = 0, len = scale * 0.1 / 6; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false);
+ for (let i = 0, len = scale * 0.15 / 6; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false)
+ for (let i = 0, len = scale * 0.26 / 6; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false);
+ } else {
+ if (Math.random() < 0.25) {
+ for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
+ } else if (Math.random() < 0.33) {
+ for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(-1327 - 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
+ } else if (Math.random() < 0.5) {
+ for (let i = 0, len = scale * 0.15; i < len; ++i) spawn.sprayBoss(-1327 - 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
+ } else {
+ for (let i = 0, len = scale * 0.26; i < len; ++i) spawn.mineBoss(-1327 - 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
+ }
+ }
+ }
+ // spawn.secondaryBossChance(-2300, -800)
+ }
+ } else {
+ doorIn.isClosing = false
+ }
+ } else if (!isFightOver && !(simulation.cycle % 180)) {
+ let isFoundBoss = false
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].isReactorBoss) {
+ isFoundBoss = true
+ break
+ }
+ }
+ if (!isFoundBoss) {
+ isFightOver = true
+ doorIn.isClosing = false
+ doorOut.isClosing = false
+ // powerUps.spawnBossPowerUp(-3600, -100)
+ powerUps.spawn(-3650, -50, "tech")
+ powerUps.spawn(-3650, -150, "tech")
+ powerUps.spawn(-3650, -300, "tech")
+ // if (player.position.x < 2760 && player.position.x > 210) {}
+ }
+ }
+ };
+
+ level.customTopLayer = () => {
+ doorIn.draw();
+ doorOut.draw();
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(-225, -1100, 1000, 350);
+ };
+ } else {
+ level.setPosToSpawn(-550, -800); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+
+ const button = level.button(1400, 0)
+ button.isUp = true
+
+ level.custom = () => {
+ if (isDoorsLocked) {
+ if (player.position.x < -300) { //if player gets trapped inside starting room open up again
+ isDoorsLocked = false
+ doorIn.isClosing = false
+ }
+ }
+ doorIn.openClose();
+ doorOut.openClose();
+ ctx.fillStyle = "#d5ebef"
+ ctx.fillRect(2750, -375, 1050, 375)
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ button.draw();
+ if (button.isUp) {
+ button.query();
+ } else if (!isSpawnedBoss) {
+ if (player.position.x > 0) {
+ if (!doorOut.isClosed() || !doorIn.isClosed()) {
+ doorIn.isClosing = true
+ doorOut.isClosing = true
+ //block caught in a door
+ if (Matter.Query.collides(doorOut, body).length > 1 || Matter.Query.collides(doorIn, body).length > 1) {
+ button.isUp = true
+ doorIn.isClosing = false
+ doorOut.isClosing = false
+ }
+ } else {
+ isSpawnedBoss = true
+ isDoorsLocked = true
+ for (let i = 0; i < 9; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "ammo")
+ for (let i = 0; i < 3; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "heal");
+ const scale = Math.pow(simulation.difficulty, 0.7) //hard around 30, why around 54
+ if (mobs.mobDeaths < level.levelsCleared && !simulation.isCheating) {
+ for (let i = 0; i < 250; i++) spawn.starter(300 + 2400 * Math.random(), -1300 - 500 * Math.random())
+ } else {
+ if (Math.random() < 0.07 && simulation.difficulty > 35) {
+ for (let i = 0, len = scale * 0.25 / 6; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 60, false); //spawn 1-2 at difficulty 15
+ for (let i = 0, len = scale * 0.1 / 6; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false);
+ for (let i = 0, len = scale * 0.15 / 6; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false)
+ for (let i = 0, len = scale * 0.26 / 6; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false);
+ } else {
+ if (Math.random() < 0.25) {
+ for (let i = 0, len = scale * 0.25; i < len; ++i) spawn.timeBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
+ } else if (Math.random() < 0.33) {
+ for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
+ } else if (Math.random() < 0.5) {
+ for (let i = 0, len = scale * 0.15; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
+ } else {
+ for (let i = 0, len = scale * 0.26; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
+ }
+ }
+ }
+ // spawn.secondaryBossChance(2200, -800)
+ }
+ } else {
+ doorIn.isClosing = false
+ }
+ } else if (!isFightOver && !(simulation.cycle % 180)) {
+ let isFoundBoss = false
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].isBoss) {
+ isFoundBoss = true
+ break
+ }
+ }
+ if (!isFoundBoss) {
+ isFightOver = true
+ doorIn.isClosing = false
+ doorOut.isClosing = false
+ // powerUps.spawnBossPowerUp(3600, -100)
+ powerUps.spawn(3650, -50, "tech")
+ powerUps.spawn(3650, -150, "tech")
+ powerUps.spawn(3650, -300, "tech")
+ // if (player.position.x < 2760 && player.position.x > 210) {}
+ }
+ }
+ };
+
+ level.customTopLayer = () => {
+ doorIn.draw();
+ doorOut.draw();
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(-775, -1100, 1000, 350);
+ };
+ }
+
+ // if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300);
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ factory() {
+ // simulation.enableConstructMode() //remove this!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ // level.difficultyIncrease(10 * 4) //30 is near max on hard //60 is near max on why
+
+ level.setPosToSpawn(2235, -1375); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance
+ level.exit.x = 7875;
+ level.exit.y = -2480;
+
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit
+ level.defaultZoom = 1500
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d0d2d4s";
+ // color.map = "#262a2f"
+ let isPowerLeft = true
+ const movers = []
+ //left side
+ movers.push(level.mover(125, -140, 925, 35, -5))
+ movers.push(level.mover(1100, -437, 1100, 35, -5))
+ movers.push(level.mover(2000, -600, 850, 35, -5))
+ //right side
+ const moveSpeedStopGo = 8
+ movers.push(level.mover(2700, -200, 3600, 35, 0))
+ movers.push(level.mover(7175, -215, 2275, 50, 3))
+ movers.push(level.mover(6475, -215, 275, 100, -3))
+ movers.push(level.mover(6725, -500, 500, 375, 3))
+ movers.push(level.mover(7675, -725, 500, 410, 0))
+ movers.push(level.mover(6775, -1075, 375, 50, 0))
+ movers.push(level.mover(5525, -1075, 450, 50, 0))
+ movers.push(level.mover(6775, -2100, 375, 50, 0))
+ movers.push(level.mover(5450, -1900, 525, 50, 0))
+
+ function setMoverDirection(VxGoal) {
+ for (let i = 7; i < movers.length; i++) movers[i].VxGoal = VxGoal
+ }
+ setMoverDirection(0)
+
+ const buttonRight = level.button(7735, -1825)
+ buttonRight.isUp = true
+ const buttonLeft = level.button(5275, -1900)
+
+ const lasers = []
+ const laserX = 3390 //3882 - 1130 / 2
+ const laserGap = 1295 //1130
+ lasers.push(level.hazard(laserX, -500, 6, 300, 0.4))
+ lasers.push(level.hazard(laserX + laserGap, -500, 6, 300, 0.4))
+ lasers.push(level.hazard(laserX + laserGap * 2, -500, 6, 300, 0.4))
+ for (let i = 0; i < lasers.length; i++) {
+ lasers[i].isOn = false;
+ spawn.mapRect(lasers[i].min.x - 55, -550, 110, 50);
+ spawn.mapRect(lasers[i].min.x - 10, -500, 25, 20);
+ }
+ const button1 = level.button(2235, -200)
+ button1.isUp = true
+ let bonusAmmoCount = 0
+ level.custom = () => {
+ if (isPowerLeft) {
+ if (!(simulation.cycle % 90)) spawn.bodyRect(2730, -1600, 50, 50);
+ } else {
+ // for (let i = 0; i < trains.length; i++) {
+ // //oscillate back and forth
+ // if (trains[i].position.x < 5275) {
+ // trains[i].changeDirection(true) //go right
+ // } else if (trains[i].position.x > 7875) {
+ // trains[i].changeDirection(false) //go left
+ // }
+ // trains[i].move();
+ // }
+
+ const rate = 160 //multiples of 32!
+ if ((simulation.cycle % rate) === 80) {
+ for (let i = 0; i < lasers.length; i++) lasers[i].isOn = false;
+ movers[3].VxGoal = moveSpeedStopGo;
+ movers[3].force = 0.0005
+ movers[2].VxGoal = moveSpeedStopGo;
+ movers[2].force = 0.0005
+ } else if ((simulation.cycle % rate) === 0) {
+ movers[3].VxGoal = 0;
+ movers[3].force = 0
+ movers[2].VxGoal = 0;
+ movers[2].force = 0
+ spawn.bodyRect(2730, -1600, 50, 50);
+ if ((simulation.cycle % (rate * 3)) === 0) {
+ if (bonusAmmoCount < 3 && Math.random() < 0.5) { //some extra ammo because of all the extra mobs that don't drop ammo
+ bonusAmmoCount++
+ powerUps.spawn(2760, -1550, Math.random() < 0.5 ? "heal" : "ammo", false);
+ }
+
+ for (let i = 0; i < lasers.length; i++) lasers[i].isOn = true;
+ const block2Mob = (laserIndex) => { //convert block into mob
+ const laserHit = Matter.Query.ray(body, lasers[laserIndex].min, lasers[laserIndex].max) //check for collisions with 3rd laser
+ if (laserHit.length) {
+ for (let i = 0; i < body.length; i++) {
+ if (laserHit[0].body.id === body[i].id) { //need to find the block id so it can be removed
+ const list = ["flutter", "flutter", "flutter", "hopper", "slasher", "slasher", "slasher", "stabber", "springer", "striker", "sneaker", "launcher", "launcherOne", "exploder", "sucker", "spinner", "grower", "beamer", "spawner", "ghoster"]
+ const pick = list[Math.floor(Math.random() * list.length)]
+ spawn[pick](lasers[laserIndex].max.x, lasers[laserIndex].max.y - 20);
+ const who = mob[mob.length - 1]
+ Matter.Body.setVelocity(who, { x: (8 + 5 * Math.random()), y: -(14 + 10 * Math.random()) });
+ who.locatePlayer()
+ who.leaveBody = false;
+ who.isDropPowerUp = false
+ //remove block
+ Matter.Composite.remove(engine.world, body[i]);
+ body.splice(i, 1);
+ break
+ }
+ }
+ }
+ }
+ if (mob.length < 100 && !m.isBodiesAsleep) {
+ block2Mob(0)
+ block2Mob(1)
+ block2Mob(2)
+ }
+ }
+ }
+ }
+ if (buttonLeft.isUp) {
+ buttonLeft.query();
+ if (!buttonLeft.isUp) {
+ setMoverDirection(7)
+ buttonRight.isUp = true //flip the other button up
+ }
+ } else if (buttonRight.isUp) {
+ buttonRight.query();
+ if (!buttonRight.isUp) {
+ setMoverDirection(-7)
+ //check for blocks and remove them
+ const list = Matter.Query.region(body, buttonLeft) //are any blocks colliding with this
+ buttonLeft.isUp = true //flip the other button up
+ if (list.length > 0) {
+ list[0].isRemoveMeNow = true
+ for (let i = 1; i < body.length; i++) { //find which index in body array it is and remove from array
+ if (body[i].isRemoveMeNow) {
+ Matter.Composite.remove(engine.world, list[0]);
+ body.splice(i, 1);
+ break
+ }
+ }
+ }
+ }
+ }
+
+ if (button1.isUp) {
+ button1.query();
+ if (!button1.isUp) {
+ isPowerLeft = false
+ for (let i = 0; i < 3; i++) {
+ movers[i].VxGoal = 0;
+ movers[i].force = movers[i].VxGoal > 0 ? 0.0005 : -0.0005
+ }
+ powerUps.spawnStartingPowerUps(2760, -1550);
+ spawn.randomMob(2700, -350, 0.2);
+ spawn.randomMob(6975, -650, 0.2);
+ spawn.randomMob(6550, -325, 0.3);
+ spawn.randomMob(7350, -350, 0.3);
+ spawn.randomMob(7925, -975, 0.5);
+ spawn.randomMob(7950, -1725, 0.5);
+ spawn.randomMob(7000, -1375, 0.3);
+ spawn.randomMob(5700, -1350, 0.5);
+ spawn.randomMob(5250, -1575, 0.5);
+ spawn.randomMob(6325, -75, 0.3);
+ spawn.randomMob(7900, -1925, 0.1);
+ spawn.randomMob(5300, -1975, 0.3);
+ spawn.randomMob(7875, -1900, 0.3);
+ spawn.randomMob(5325, -1975, 0.4);
+
+ spawn.randomGroup(3900, -725, 0.4);
+ if (simulation.difficulty > 1) spawn.randomLevelBoss(6501, -1771);
+ spawn.secondaryBossChance(6063, -661)
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ }
+ }
+ buttonRight.draw();
+ buttonLeft.draw();
+ button1.draw();
+ for (let i = 0; i < movers.length; i++) movers[i].push();
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(6937, -2075, 50, 1775); //6937, -1050, 50, 675);
+ ctx.fillStyle = "rgba(0,255,255,0.15)" // ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(7675, -2875, 500, 425); //exit room
+ };
+ level.customTopLayer = () => {
+ if (isPowerLeft) {
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+ ctx.fillRect(2400, -1650, 7050, 2750) //right side
+ ctx.fillRect(4950, -3075, 3225, 1425);
+ ctx.beginPath()
+ ctx.moveTo(2407, -576);
+ ctx.lineTo(2000, -573)
+ ctx.lineTo(1950, -439)
+ ctx.lineTo(1100, -432)
+ ctx.lineTo(1020, -143)
+ ctx.lineTo(125, -137)
+ ctx.lineTo(-109, 300)
+ ctx.lineTo(-125, 1089)
+ ctx.lineTo(2372, 1081)
+ ctx.lineTo(2452, 65)
+ ctx.fill();
+ } else {
+ // for (let i = 0; i < trains.length; i++) trains[i].draw()
+ ctx.beginPath()
+ ctx.moveTo(2526, -589);
+ ctx.lineTo(2531, -597)
+ ctx.lineTo(2506, -594)
+ ctx.lineTo(2850, -600)
+ ctx.lineTo(2890, -193)
+ ctx.lineTo(6300, -200)
+ ctx.lineTo(6618, 857)
+ ctx.lineTo(6622, 1100)
+ ctx.lineTo(2521, 1100)
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+ ctx.fill();
+ ctx.fillRect(-100, -1650, 2625, 2750) //left side
+ for (let i = 0; i < lasers.length; i++) lasers[i].opticalQuery()
+ }
+ ctx.fillStyle = "rgba(0,0,0,0.07)"
+ ctx.fillRect(7675, -2200, 1775, 2025);
+ ctx.fillRect(4950, -2075, 500, 1000);
+ ctx.fillRect(2050, -1650, 350, 325) //entrance room
+ for (let i = 0; i < movers.length; i++) movers[i].draw();
+ };
+ spawn.mapRect(-1550, -3050, 1450, 4150); //left wall
+ spawn.mapRect(-1550, -3050, 6525, 1400); //ceiling
+ spawn.mapRect(-1550, -3050, 6525, 1400);
+ spawn.mapRect(3000, -1700, 1975, 675); //ceiling center
+
+ spawn.mapRect(3800, -4000, 5650, 950);
+ spawn.mapRect(3800, -4000, 1175, 2975);
+ spawn.mapRect(8175, -4000, 1275, 3685); //right wall
+ spawn.mapRect(8175, -200, 1275, 1300); //right wall
+
+ spawn.mapRect(75, 0, 6275, 1100); //ground
+ spawn.mapRect(6475, -200, 2750, 1300);
+ spawn.mapRect(4975, -1087, 550, 62);
+ spawn.mapRect(4975, -1100, 500, 75);
+
+ spawn.mapRect(7875, -1100, 175, 25); //right 3 hop stairs
+ spawn.mapRect(8075, -1450, 200, 25);
+ spawn.mapRect(7675, -1825, 375, 25);
+ spawn.mapRect(7675, -1800, 250, 725);
+
+ spawn.mapRect(5125, -1275, 200, 25); //left 3 hop stairs
+ spawn.mapRect(4900, -1575, 175, 25);
+ spawn.mapRect(5125, -1900, 325, 25);
+ spawn.mapRect(5225, -1875, 225, 625);
+ spawn.mapRect(4950, -3075, 500, 1000);
+
+ //exit
+ spawn.mapRect(7675, -2450, 525, 250);
+ spawn.mapRect(7675, -3050, 550, 175);
+ spawn.mapRect(7675, -2925, 50, 175);
+
+ spawn.mapRect(1925, -1325, 550, 50); //entrance
+ spawn.mapRect(2050, -1675, 50, 175); //entrance
+ spawn.mapRect(1700, -200, 750, 275); //button shelf
+ if (Math.random() < 0.5) { //left side
+ spawn.mapRect(625, -1100, 425, 300);
+ spawn.mapRect(1375, -1100, 425, 300);
+ spawn.mapRect(1750, -835, 100, 35);
+ spawn.mapRect(-200, -525, 150, 35);
+ } else {
+ spawn.mapRect(800, -1125, 925, 400);
+ spawn.mapRect(75, -775, 400, 50);
+ spawn.mapRect(1700, -760, 75, 35);
+ spawn.mapRect(-200, -425, 150, 35);
+ }
+ spawn.mapRect(2400, -600, 125, 675);
+ spawn.mapRect(2400, -1750, 125, 1050);
+ spawn.mapRect(2700, -1700, 125, 85);
+
+ spawn.randomMob(350, -325, 0.5);
+ spawn.randomMob(875, -375, 0.5);
+ spawn.randomMob(1250, -575, 0.5);
+ spawn.randomMob(1550, -600, 0.5);
+ spawn.randomSmallMob(1250, -175);
+ spawn.randomSmallMob(1500, -229);
+ spawn.randomSmallMob(1850, -300);
+ powerUps.spawn(5200, -1300, "ammo");
+ },
+ labs() {
+ level.isProcedural = true //used in generating text for the level builder
+ level.defaultZoom = 1700
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d9d9de" //"#d3d3db" //"#dcdcdf";
+ let isDoorLeft, isDoorRight, x, y
+ doCustom = []
+ doCustomTopLayer = []
+ offset = { x: 0, y: 0 }
+ const mobSpawnChance = 0 // Math.random() < chance + 0.07 * simulation.difficulty
+ enterOptions = [
+ (x = offset.x, y = offset.y) => { //lasers
+ level.setPosToSpawn(x + 1750, y - 800);
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ spawn.mapRect(x + 1450, y - 1350, 50, 450); //entrance left wall
+ spawn.bodyRect(x + 1460, y - 900, 30, 150); //entrance door
+ spawn.mapRect(x + 1600, y - 350, 500, 100); //toggle shelf
+ const toggle = level.toggle(x + 1650, y - 350, true) //(x,y,isOn,isLockOn = true/false)
+ let hazard1
+ if (Math.random() > 0.5) {
+ spawn.mapRect(x + 550, y - 750, 1500, 50); //entrance shelf
+ hazard1 = level.hazard(x + 850, y - 920, 600, 10, 0.4) //laser
+ spawn.mapRect(x + 860, y - 925, 10, 20); //laser nose
+ spawn.mapRect(x + 660, y - 975, 200, 120); //laser body
+ } else {
+ spawn.mapRect(x + 1350, y - 750, 700, 50); //entrance shelf
+ hazard1 = level.hazard(x + 1040, y - 660, 1000, 10, 0.4) //laser
+ spawn.mapRect(x + 1050, y - 665, 10, 20); //laser nose
+ spawn.mapRect(x + 650, y - 705, 400, 100); //laser body
+ }
+ const hazard2 = level.hazard(x, y - 330, 450, 10, 0.4) //laser
+ spawn.mapRect(x + 440, y - 335, 10, 20); //laser nose
+ spawn.mapRect(x + 450, y - 375, 400, 100); //laser body
+ //exit hazards
+ const Xoffset = Math.floor(400 * Math.random())
+ const hazard3 = level.hazard(x + Xoffset, y - 1300, 10, 1300, 0.4) //laser
+ spawn.mapRect(x + Xoffset - 5, y - 1310, 20, 20); //laser nose
+ const Xoffset2 = 1650 + Math.floor(300 * Math.random())
+ const hazard4 = level.hazard(x + Xoffset2, y - 240, 10, 250, 0.4) //laser
+ spawn.mapRect(x + Xoffset2 - 5, y - 250, 20, 20); //laser nose
+ spawn.randomMob(x + 150, y + -1100, mobSpawnChance);
+ spawn.randomMob(x + 175, y + -775, mobSpawnChance);
+ spawn.randomMob(x + 150, y + -350, mobSpawnChance);
+ spawn.randomMob(x + 150, y + -75, mobSpawnChance);
+ spawn.randomMob(x + 650, y + -125, mobSpawnChance);
+ spawn.randomMob(x + 1200, y + -75, mobSpawnChance);
+ // let isSpawnedMobs = false
+ doCustomTopLayer.push(
+ () => {
+ toggle.query();
+ hazard1.isOn = toggle.isOn
+ hazard2.isOn = toggle.isOn
+ hazard3.isOn = toggle.isOn
+ hazard4.isOn = toggle.isOn
+ if ((simulation.cycle % 120) > 60) {
+ hazard1.opticalQuery();
+ hazard2.opticalQuery();
+ } else {
+ hazard3.opticalQuery();
+ hazard4.opticalQuery();
+ }
+ // if (!isSpawnedMobs && !toggle.isOn) {
+ // isSpawnedMobs = true
+ // spawn.randomMob(x + 150, y + -1100, mobSpawnChance);
+ // spawn.randomMob(x + 175, y + -775, mobSpawnChance);
+ // spawn.randomMob(x + 150, y + -350, mobSpawnChance);
+ // spawn.randomMob(x + 150, y + -75, mobSpawnChance);
+ // spawn.randomMob(x + 650, y + -125, mobSpawnChance);
+ // spawn.randomMob(x + 1200, y + -75, mobSpawnChance);
+ // }
+ }
+ )
+ },
+ ]
+ exitOptions = [
+ (x = offset.x, y = offset.y) => {
+ level.exit.x = x + 1725;
+ level.exit.y = y - 980;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+ spawn.mapRect(x + 1500, y - 950, 500, 25); //exit platform
+ spawn.mapRect(x + 1550, y - 1300, 25, 175); //exit side wall
+ spawn.mapVertex(x + 1300, y - 125, "-400 0 -250 -400 250 -400 400 0");
+
+ spawn.bodyRect(x + 1075, y - 475, 125, 125, 0.25);
+ spawn.bodyRect(x + 500, y - 100, 125, 100, 0.25);
+ spawn.bodyRect(x + 200, y - 150, 100, 150, 0.25);
+ spawn.bodyRect(x + 1075, y - 1075, 100, 125, 0.25);
+ const density = 0.0015 //+ (simulation.difficultyMode < 5 ? 0.0035 : 0)
+ const angle = Math.PI / 2
+ const variance = 0 //Math.PI
+ const frictionAir = 0.03
+ const angularVelocity = 0 //0.01
+ const spinVariance = 0 //0.02
+ balance1 = level.spinner(x + 200, y - 500, 30, 400, density, angle + variance * (Math.random() - 0.5), frictionAir, angularVelocity + spinVariance * (Math.random() - 0.5)) // spinner(x, y, width, height, density = 0.001, angle=0,frictionAir=0.001,angularVelocity=0) {
+ balance2 = level.spinner(x + 200, y - 950, 30, 400, density, angle + variance * (Math.random() - 0.5), frictionAir, angularVelocity + spinVariance * (Math.random() - 0.5))
+ balance3 = level.spinner(x + 650, y - 750, 30, 400, density, angle + variance * (Math.random() - 0.5), frictionAir, angularVelocity + spinVariance * (Math.random() - 0.5))
+ // balance4 = level.spinner(x + 750, y - 1050, 25, 350, density, angle + variance * (Math.random() - 0.5), frictionAir, angularVelocity + spinVariance * (Math.random() - 0.5))
+ balance4 = level.spinner(x + 1250, y - 1000, 30, 400, density, angle + variance * (Math.random() - 0.5), frictionAir, angularVelocity + spinVariance * (Math.random() - 0.5))
+
+ let isInRoom = false
+ doCustom.push(
+ () => {
+ if (!isInRoom && m.pos.x > x - 100 && m.pos.x < x + 2700 && m.pos.y > y - 1300 && m.pos.y < y) { //check if player is in this room and run code once
+ isInRoom = true
+ spawn.randomMob(x + 1175, y - 725, mobSpawnChance);
+ spawn.randomMob(x + 1450, y - 725, mobSpawnChance);
+ spawn.randomMob(x + 425, y - 100, mobSpawnChance);
+ spawn.randomMob(x + 1700, y - 300, mobSpawnChance);
+ spawn.randomMob(x + 1300, y - 375, mobSpawnChance);
+ }
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(x + 1550, y - 1300, 450, 350)
+ }
+ )
+ doCustomTopLayer.push(
+ () => {
+ ctx.fillStyle = "#233"
+ ctx.beginPath();
+ ctx.arc(balance1.pointA.x, balance1.pointA.y, 9, 0, 2 * Math.PI);
+ ctx.moveTo(balance2.pointA.x, balance2.pointA.y)
+ ctx.arc(balance2.pointA.x, balance2.pointA.y, 9, 0, 2 * Math.PI);
+ ctx.moveTo(balance3.pointA.x, balance3.pointA.y)
+ ctx.arc(balance3.pointA.x, balance3.pointA.y, 9, 0, 2 * Math.PI);
+ ctx.moveTo(balance4.pointA.x, balance4.pointA.y)
+ ctx.arc(balance4.pointA.x, balance4.pointA.y, 9, 0, 2 * Math.PI);
+ ctx.fill();
+ }
+ )
+ },
+ (x = offset.x, y = offset.y) => {
+ level.exit.x = x + 1750;
+ level.exit.y = y - 980;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+ spawn.mapRect(x + 1550, y - 950, 500, 25); //exit platform
+ spawn.mapRect(x + 1600, y - 1300, 25, 175); //exit side wall
+ spawn.bodyRect(x + 1275, y - 475, 125, 125, 0.25);
+ spawn.bodyRect(x + 500, y - 100, 125, 100, 0.25);
+ spawn.bodyRect(x + 800, y - 150, 100, 150, 0.25);
+ spawn.bodyRect(x + 875, y + -50, 50, 50);
+ spawn.bodyRect(x + 1025, y + -50, 50, 50);
+
+ if (Math.random() > 0.5) {
+ const density = 0.0012 //+ (simulation.difficultyMode < 5 ? 0.003 : 0)
+ const angle = Math.PI / 2
+ const variance = 0.2 //Math.PI
+ const frictionAir = 0.015
+ const height = 35
+ balance1 = level.spinner(x + 1300, y - 425, height, 410, density, angle + variance * (Math.random() - 0.5), frictionAir) // spinner(x, y, width, height, density = 0.001, angle=0,frictionAir=0.001,angularVelocity=0) {
+ balance3 = level.spinner(x + 750, y - 650, height, 410, density, angle + variance * (Math.random() - 0.5), frictionAir)
+ balance2 = level.spinner(x + 300, y - 425, height, 410, density, angle + variance * (Math.random() - 0.5), frictionAir)
+ balance4 = level.spinner(x + 1250, y - 950, 50, 550, density, angle, 0.1)
+ const rotatingBlock = body[body.length - 1]
+ doCustom.push(
+ () => {
+ if (!isInRoom && m.pos.x > x - 100 && m.pos.x < x + 2700 && m.pos.y > y - 1300 && m.pos.y < y) { //check if player is in this room and run code once
+ isInRoom = true
+ spawn.randomMob(x + 1175, y - 725, mobSpawnChance);
+ spawn.randomMob(x + 1450, y - 725, mobSpawnChance);
+ spawn.randomMob(x + 425, y - 100, mobSpawnChance);
+ spawn.randomMob(x + 1200, y - 125, mobSpawnChance);
+ spawn.randomMob(x + 1300, y - 375, mobSpawnChance);
+ }
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(x + 1600, y - 1300, 400, 350)
+ rotatingBlock.torque += rotatingBlock.inertia * 0.000005
+ }
+ )
+ } else {
+ const density = 0.001 //+ (simulation.difficultyMode < 5 ? 0.003 : 0)
+ const angle = Math.PI / 2
+ const variance = Math.PI
+ const frictionAir = 0.015
+ const width = 200
+ const height = 200
+ const spinVariance = 0.05
+ balance1 = level.spinner(x + 175, y - 300, height, width, density, angle + variance * (Math.random() - 0.5), frictionAir, spinVariance * (Math.random() - 0.5)) // spinner(x, y, width, height, density = 0.001, angle=0,frictionAir=0.001,angularVelocity=0) {
+ balance2 = level.spinner(x + 500, y - 525, height, width, density, angle + variance * (Math.random() - 0.5), frictionAir, spinVariance * (Math.random() - 0.5))
+ balance3 = level.spinner(x + 850, y - 700, height, width, density, angle + variance * (Math.random() - 0.5), frictionAir, spinVariance * (Math.random() - 0.5))
+ balance4 = level.spinner(x + 1250, y - 850, height, width, density, angle + variance * (Math.random() - 0.5), frictionAir, spinVariance * (Math.random() - 0.5))
+ doCustom.push(
+ () => {
+ if (!isInRoom && m.pos.x > x - 100 && m.pos.x < x + 2700 && m.pos.y > y - 1300 && m.pos.y < y) { //check if player is in this room and run code once
+ isInRoom = true
+ spawn.randomMob(x + 1175, y - 725, mobSpawnChance);
+ spawn.randomMob(x + 1450, y - 725, mobSpawnChance);
+ spawn.randomMob(x + 425, y - 100, mobSpawnChance);
+ spawn.randomMob(x + 1200, y - 125, mobSpawnChance);
+ spawn.randomMob(x + 1300, y - 375, mobSpawnChance);
+ }
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(x + 1600, y - 1300, 400, 350)
+ }
+ )
+ }
+ let isInRoom = false
+ doCustomTopLayer.push(
+ () => {
+ ctx.fillStyle = "#233"
+ ctx.beginPath();
+ ctx.arc(balance1.pointA.x, balance1.pointA.y, 9, 0, 2 * Math.PI);
+ ctx.moveTo(balance2.pointA.x, balance2.pointA.y)
+ ctx.arc(balance2.pointA.x, balance2.pointA.y, 9, 0, 2 * Math.PI);
+ ctx.moveTo(balance3.pointA.x, balance3.pointA.y)
+ ctx.arc(balance3.pointA.x, balance3.pointA.y, 9, 0, 2 * Math.PI);
+ ctx.moveTo(balance4.pointA.x, balance4.pointA.y)
+ ctx.arc(balance4.pointA.x, balance4.pointA.y, 9, 0, 2 * Math.PI);
+ ctx.fill();
+ }
+ )
+ }
+ ]
+ emptyOptions = [ //nothing good here except the starting power up, and duplicated bosses
+ (x = offset.x, y = offset.y) => { //pulse
+ if (!isDoorLeft && isDoorRight) { //flipped, entering from the right
+ powerUps.spawnStartingPowerUps(x + 2000 - 1650, y + -400);
+ spawn.mapRect(x + 2000 - 1575 - 25, y + -625, 25, 375); //wall on top of wall
+ spawn.mapRect(x + 2000 - 1575 - 25, y + -1325, 25, 525); //wall on top of wall
+ spawn.mapRect(x + 2000 - 1525 - 250, y + -350, 250, 450); //wall
+ spawn.mapRect(x + 2000 - 245 - 300, y + -200, 300, 100); //gun
+ spawn.mapRect(x + 2000 - 530 - 25, y + -190, 25, 80); //gun nose
+ const button = level.button(x + 2000 - 290 - 140, y - 200)
+ button.isReadyToFire = true
+ doCustom.push(
+ () => {
+ ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)";
+ ctx.fillRect(x + 2000 - 255 - 280, y + -100, 280, 100);
+ button.query();
+ button.draw();
+ if (!button.isReadyToFire && button.isUp) {
+ button.isReadyToFire = true
+ } else if (button.isReadyToFire && !button.isUp) {
+ button.isReadyToFire = false
+ b.pulse(90, Math.PI, {
+ x: x + 2000 - 560,
+ y: y - 150
+ })
+ }
+ }
+ )
+ spawn.randomMob(x + 2000 - 1600, y + -425, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 1725, y + -1250, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 1250, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 300, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 800, y + -125, mobSpawnChance);
+ let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
+ } else {
+ powerUps.spawnStartingPowerUps(x + 1650, y + -400);
+ spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall
+ spawn.mapRect(x + 1575, y + -1325, 25, 525); //wall on top of wall
+ spawn.mapRect(x + 1525, y + -350, 250, 450); //wall
+ spawn.mapRect(x + 245, y + -200, 300, 100); //gun
+ spawn.mapRect(x + 530, y + -190, 25, 80); //gun nose
+ const button = level.button(x + 290, y - 200)
+ button.isReadyToFire = true
+
+ doCustom.push(
+ () => {
+ ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)";
+ ctx.fillRect(x + 255, y + -100, 280, 100);
+ button.query();
+ button.draw();
+ if (!button.isReadyToFire && button.isUp) {
+ button.isReadyToFire = true
+ } else if (button.isReadyToFire && !button.isUp) {
+ button.isReadyToFire = false
+ b.pulse(90, 0, { x: x + 560, y: y - 150 })
+ }
+ }
+ )
+ spawn.randomMob(x + 1600, y + -425, mobSpawnChance);
+ spawn.randomMob(x + 1725, y + -1250, mobSpawnChance);
+ spawn.randomMob(x + 1250, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 300, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 800, y + -125, mobSpawnChance);
+ let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
+ }
+ },
+ (x = offset.x, y = offset.y) => { //spawn block and fire it
+ if (!isDoorLeft && isDoorRight) {
+ powerUps.spawnStartingPowerUps(x + 1650, y + -400);
+ spawn.mapRect(x + 2000 - 1575 - 25, y + -625, 25, 375); //wall on top of wall
+ spawn.mapRect(x + 2000 - 1575 - 25, y + -1325, 25, 525); //wall on top of wall
+ spawn.mapRect(x + 2000 - 1525 - 250, y + -350, 250, 450); //wall
+ spawn.mapRect(x + 2000 - 245 - 300, y + -200, 300, 100); //gun
+ spawn.mapRect(x + 2000 - 530 - 25, y + -190, 25, 80);
+ const button = level.button(x + 2000 - 290 - 140, y - 200)
+ button.isReadyToFire = true
+ doCustom.push(
+ () => {
+ ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)";
+ ctx.fillRect(x + 2000 - 255 - 280, y + -100, 280, 100);
+ button.query();
+ button.draw();
+ if (!button.isReadyToFire && button.isUp) {
+ button.isReadyToFire = true
+ } else if (button.isReadyToFire && !button.isUp) {
+ button.isReadyToFire = false
+ fireBlock = function (xPos, yPos) {
+ const index = body.length
+ spawn.bodyRect(xPos, yPos, 35 + 50 * Math.random(), 35 + 50 * Math.random());
+ const bodyBullet = body[body.length - 1]
+ Matter.Body.setVelocity(body[index], { x: -120, y: -5 });
+ body[index].isAboutToBeRemoved = true;
+ setTimeout(() => { //remove block
+ for (let i = 0; i < body.length; i++) {
+ if (body[i] === bodyBullet) {
+ Matter.Composite.remove(engine.world, body[i]);
+ body.splice(i, 1);
+ }
+ }
+ }, 1000);
+ }
+ fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 140);
+ fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 160);
+ fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 180);
+ fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 200);
+ fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 220);
+ fireBlock(x + 2000 - 90 - 560 + 30 * Math.random(), y - 240);
+ }
+ }
+ )
+ spawn.randomMob(x + 2000 - 1600, y + -425, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 1725, y + -1250, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 1250, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 300, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 800, y + -125, mobSpawnChance);
+ let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
+ } else {
+ powerUps.spawnStartingPowerUps(x + 1650, y + -400);
+ spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall
+ spawn.mapRect(x + 1575, y + -1325, 25, 525); //wall on top of wall
+ spawn.mapRect(x + 1525, y + -350, 250, 450); //wall
+ spawn.mapRect(x + 245, y + -200, 300, 100); //gun
+ spawn.mapRect(x + 530, y + -190, 25, 80);
+ const button = level.button(x + 290, y - 200)
+ button.isReadyToFire = true
+ doCustom.push(
+ () => {
+ ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)";
+ ctx.fillRect(x + 255, y + -100, 280, 100);
+ button.query();
+ button.draw();
+ if (!button.isReadyToFire && button.isUp) {
+ button.isReadyToFire = true
+ } else if (button.isReadyToFire && !button.isUp) {
+ button.isReadyToFire = false
+ fireBlock = function (xPos, yPos) {
+ const index = body.length
+ spawn.bodyRect(xPos, yPos, 35 + 50 * Math.random(), 35 + 50 * Math.random());
+ const bodyBullet = body[body.length - 1]
+ Matter.Body.setVelocity(body[index], { x: 120, y: -5 });
+ body[index].isAboutToBeRemoved = true;
+
+ setTimeout(() => { //remove block
+ for (let i = 0; i < body.length; i++) {
+ if (body[i] === bodyBullet) {
+ Matter.Composite.remove(engine.world, body[i]);
+ body.splice(i, 1);
+ }
+ }
+ }, 1000);
+ }
+ fireBlock(x + 560 + 30 * Math.random(), y - 140);
+ fireBlock(x + 560 + 30 * Math.random(), y - 160);
+ fireBlock(x + 560 + 30 * Math.random(), y - 180);
+ fireBlock(x + 560 + 30 * Math.random(), y - 200);
+ fireBlock(x + 560 + 30 * Math.random(), y - 220);
+ fireBlock(x + 560 + 30 * Math.random(), y - 240);
+ }
+ }
+ )
+ spawn.randomMob(x + 1600, y + -425, mobSpawnChance);
+ spawn.randomMob(x + 1725, y + -1250, mobSpawnChance);
+ spawn.randomMob(x + 1250, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 300, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 800, y + -125, mobSpawnChance);
+ let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
+ }
+ },
+ (x = offset.x, y = offset.y) => { //fire an "ammo clip" of blocks
+ if (!isDoorLeft && isDoorRight) { //flipped, entering from the right
+ powerUps.spawnStartingPowerUps(x + 2000 - 1650, y + -400);
+ spawn.mapRect(x + 2000 - 1575 - 25, y + -625, 25, 375); //wall on top of wall
+ spawn.mapRect(x + 2000 - 1575 - 25, y + -1325, 25, 525); //wall on top of wall
+ spawn.mapRect(x + 2000 - 1525 - 250, y + -350, 250, 450); //wall
+ spawn.mapRect(x + 2000 - 175 - 370, y + -200, 370, 100); //gun
+ spawn.mapRect(x + 2000 - 530 - 25, y + -190, 25, 80);
+ spawn.mapRect(x + 2000 - 545 - 10, y + -770, 10, 325); //block loader for gun //walls
+ spawn.mapRect(x + 2000 - 620 - 10, y + -770, 10, 325); //walls
+ spawn.mapRect(x + 2000 + 50 - 150, y + -425, 150, 50);
+ spawn.mapRect(x + 2000 - 175 - 370, y + -650, 370, 50);
+ spawn.mapRect(x + 2000 - 540 - 95, y + -460, 95, 15); //bottom that opens and closes
+ const bulletDoor = map[map.length - 1] //keep track of this body so it can be make non-collide later
+ for (let i = 0; i < 6; i++) spawn.bodyRect(x + 2000 - 60 - 555 + Math.floor(Math.random() * 10), y + -520 - 50 * i, 50, 50); //bullets for gun
+ spawn.bodyRect(x + 2000 - 250 - 40, y + -700, 40, 50); //extra bullets
+ spawn.bodyRect(x + 2000 - 350 - 30, y + -700, 30, 35);
+ spawn.bodyRect(x + 2000 - 425 - 40, y + -700, 40, 70);
+ const button = level.button(x + 2000 - 280 - 140, y - 200) //trigger for gun
+ button.isReadyToFire = true
+ doCustom.push(
+ () => {
+ ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)";
+ ctx.fillRect(x + 2000 - 200 - 325, y + -625, 325, 650);
+ button.query();
+ button.draw();
+ if (!button.isReadyToFire && button.isUp) {
+ button.isReadyToFire = true
+ bulletDoor.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
+ } else if (button.isReadyToFire && !button.isUp) {
+ button.isReadyToFire = false
+ bulletDoor.collisionFilter.mask = 0 //cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
+ } else if (!button.isUp) {
+ const bounds = {
+ min: {
+ x: x + 2000 - 580,
+ y: y - 125
+ },
+ max: {
+ x: x + 2000 - 530,
+ y: y - 110
+ }
+ }
+ const list = Matter.Query.region(body, bounds)
+ for (let i = 0, len = list.length; i < len; i++) {
+ Matter.Body.setVelocity(list[i], {
+ x: -120,
+ y: -5
+ });
+ }
+ if (Matter.Query.region([player], bounds).length) {
+ Matter.Body.setVelocity(player, {
+ x: -100,
+ y: -5
+ });
+ }
+ ctx.fillStyle = `rgba(255,0,255,${0.2 + 0.7 * Math.random()})`
+ ctx.fillRect(bounds.min.x, y - 185, 38, 70);
+ }
+ }
+ )
+ spawn.randomMob(x + 2000 - 1600, y + -425, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 1725, y + -1250, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 1250, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 300, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 2000 - 800, y + -125, mobSpawnChance);
+ let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](x + 2000 - 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
+ } else {
+ powerUps.spawnStartingPowerUps(x + 1650, y + -400);
+ spawn.mapRect(x + 1575, y + -625, 25, 375); //wall on top of wall
+ spawn.mapRect(x + 1575, y + -1325, 25, 525); //wall on top of wall
+ spawn.mapRect(x + 1525, y + -350, 250, 450); //wall
+ spawn.mapRect(x + 175, y + -200, 370, 100); //gun
+ spawn.mapRect(x + 530, y + -190, 25, 80);
+ spawn.mapRect(x + 545, y + -770, 10, 325); //block loader for gun //walls
+ spawn.mapRect(x + 620, y + -770, 10, 325); //walls
+ spawn.mapRect(x - 50, y + -425, 150, 50);
+ spawn.mapRect(x + 175, y + -650, 370, 50);
+ spawn.mapRect(x + 540, y + -460, 95, 15); //bottom that opens and closes
+ const bulletDoor = map[map.length - 1] //keep track of this body so it can be make non-collide later
+ for (let i = 0; i < 6; i++) spawn.bodyRect(x + 555 + Math.floor(Math.random() * 10), y + -520 - 50 * i, 50, 50); //bullets for gun
+ spawn.bodyRect(x + 250, y + -700, 40, 50); //extra bullets
+ spawn.bodyRect(x + 350, y + -700, 30, 35);
+ spawn.bodyRect(x + 425, y + -700, 40, 70);
+ const button = level.button(x + 280, y - 200) //trigger for gun
+ button.isReadyToFire = true
+ doCustom.push(
+ () => {
+ ctx.fillStyle = "rgba(0,0,0,0.05)"; //"rgba(0,0,0,0.1)";
+ ctx.fillRect(x + 200, y + -625, 325, 650);
+ button.query();
+ button.draw();
+ if (!button.isReadyToFire && button.isUp) {
+ button.isReadyToFire = true
+ bulletDoor.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
+ } else if (button.isReadyToFire && !button.isUp) {
+ button.isReadyToFire = false
+ bulletDoor.collisionFilter.mask = 0 //cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
+ } else if (!button.isUp) {
+ const bounds = {
+ min: {
+ x: x + 530,
+ y: y - 125
+ },
+ max: {
+ x: x + 580,
+ y: y - 110
+ }
+ }
+ const list = Matter.Query.region(body, bounds)
+ for (let i = 0, len = list.length; i < len; i++) {
+ Matter.Body.setVelocity(list[i], {
+ x: 120,
+ y: -5
+ });
+ }
+ if (Matter.Query.region([player], bounds).length) {
+ Matter.Body.setVelocity(player, {
+ x: 100,
+ y: -5
+ });
+ }
+ ctx.fillStyle = `rgba(255,0,255,${0.2 + 0.7 * Math.random()})`
+ ctx.fillRect(bounds.min.x, y - 185, 38, 70);
+ }
+ }
+ )
+ spawn.randomMob(x + 1600, y + -425, mobSpawnChance);
+ spawn.randomMob(x + 1725, y + -1250, mobSpawnChance);
+ spawn.randomMob(x + 1250, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 300, y + -1200, mobSpawnChance);
+ spawn.randomMob(x + 800, y + -125, mobSpawnChance);
+ let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](x + 1275, y + -150, 90 + Math.random() * 40); //one extra large mob
+ }
+ }
+ ]
+ lootOptions = [ //has some power up reward //field, ammo, research, gun
+ (x = offset.x, y = offset.y) => {
+ spawn.mapRect(x + 1925, y + -325, 125, 150); //4 wall ledges
+ spawn.mapRect(x + 1925, y + -865, 125, 150); //4 wall ledges
+ spawn.mapRect(x + -50, y + -325, 125, 150); //4 wall ledges
+ spawn.mapRect(x + -50, y + -865, 125, 150); //4 wall ledges
+ spawn.mapRect(x + 1700, y + -500, 200, 25);
+ spawn.mapRect(x + 75, y + -500, 200, 25);
+
+ let chamberY = -650
+ if (Math.random() > 0.5) { //upper chamber
+ chamberY = -650 - 640
+ spawn.mapRect(x + 550, y + -10 - 640, 900, 25); //raised floor
+ spawn.mapRect(x + 450, y + -20 - 640, 1100, 25);
+ spawn.mapRect(x + 450, y + -675 - 640, 1100, 25); //chamber ceiling
+ powerUps.directSpawn(x + 998, y - 333 - 640, "tech", false);
+ spawn.mapVertex(x + 1000, y + -0, "575 0 -575 0 -450 -100 450 -100"); //base
+ } else { //lower chamber
+ spawn.mapRect(x + 400, y + -10, 1200, 50); //raised floor
+ spawn.mapRect(x + 450, y + -20, 1100, 50);
+ spawn.mapRect(x + 450, y + -675, 1100, 25); //chamber ceiling
+ spawn.mapRect(x + 550, y + -685, 900, 25);
+ powerUps.directSpawn(x + 998, y - 333, "tech", false);
+ }
+ const powerUp1 = powerUp[powerUp.length - 1]
+ powerUp1.holdPosition = {
+ x: powerUp1.position.x,
+ y: powerUp1.position.y
+ }
+ let isSpawnedMobs = false
+ doCustom.push(
+ () => {
+ ctx.fillStyle = "#e4e4e9" //"rgba(255,255,255,1)";
+ ctx.fillRect(x + 450, y + chamberY, 1100, 650); //chamber background
+ // if (!isInRoom && m.pos.x > x - 100 && m.pos.x < x + 2000 && m.pos.y > y - 1300 && m.pos.y < y) { //is player inside this room?
+ // isInRoom = true
+ // } else
+ if (powerUp1.velocity.y !== 0) { //don't run this code if power up is gone //hack: powerUp1.velocity.y !== 0 seems to only be true if the power up up doesn't exist and is no longer being affected by gravity
+ ctx.strokeStyle = "#f0f"
+ ctx.lineWidth = 2;
+ if (Vector.magnitudeSquared(Vector.sub(m.pos, powerUp1.position)) < 90000) { //zone radius is 300
+ //damage player and drain energy
+ if (m.immuneCycle < m.cycle) {
+ m.damage(0.01);
+ if (m.energy > 0.1) m.energy -= 0.02
+ }
+ //draw electricity going towards player
+ const unit = Vector.normalise(Vector.sub(m.pos, powerUp1.position))
+ let xElec = powerUp1.position.x + 40 * unit.x;
+ let yElec = powerUp1.position.y + 40 * unit.y;
+ ctx.beginPath();
+ ctx.moveTo(xElec, yElec);
+ const step = 40
+ for (let i = 0; i < 6; i++) {
+ xElec += step * (unit.x + 1.5 * (Math.random() - 0.5))
+ yElec += step * (unit.y + 1.5 * (Math.random() - 0.5))
+ ctx.lineTo(xElec, yElec);
+ }
+ } else {
+ //draw electricity going in random directions
+ const angle = Math.random() * 2 * Math.PI
+ const Dx = Math.cos(angle);
+ const Dy = Math.sin(angle);
+ let xElec = powerUp1.position.x + 40 * Dx;
+ let yElec = powerUp1.position.y + 40 * Dy;
+ ctx.beginPath();
+ ctx.moveTo(xElec, yElec);
+ const step = 40
+ for (let i = 0; i < 6; i++) {
+ xElec += step * (Dx + 1.5 * (Math.random() - 0.5))
+ yElec += step * (Dy + 1.5 * (Math.random() - 0.5))
+ ctx.lineTo(xElec, yElec);
+ }
+ }
+ ctx.lineWidth = 2 * Math.random();
+ ctx.stroke(); //draw electricity
+
+ ctx.beginPath(); //outline damage zone
+ ctx.arc(powerUp1.position.x, powerUp1.position.y, 300, 0, 2 * Math.PI);
+ ctx.stroke();
+ //float power up in the air
+ Matter.Body.setPosition(powerUp1, {
+ x: powerUp1.holdPosition.x + 4 * Math.random(), //1300 -2
+ y: powerUp1.holdPosition.y + 4 * Math.random() //335 -2
+ });
+ Matter.Body.setVelocity(powerUp1, {
+ x: 0,
+ y: 0
+ });
+ } else if (!isSpawnedMobs) {
+ isSpawnedMobs = true
+ if (chamberY === -650) { //lower chamber
+ spawn.randomMob(x + 250, y + -650, mobSpawnChance);
+ spawn.randomMob(x + 1825, y + -600, mobSpawnChance);
+ spawn.randomGroup(x + 275, y + -1050, mobSpawnChance);
+ spawn.randomGroup(x + 675, y + -975, mobSpawnChance);
+ spawn.randomGroup(x + 1225, y + -975, Infinity);
+ } else { //upper chamber
+ spawn.randomMob(x + 250, y + -650, mobSpawnChance);
+ spawn.randomMob(x + 1800, y + -625, mobSpawnChance);
+ spawn.randomGroup(x + 300, y + -300, mobSpawnChance);
+ spawn.randomGroup(x + 650, y + -275, mobSpawnChance);
+ spawn.randomGroup(x + 1125, y + -300, Infinity);
+ }
+ }
+ }
+ )
+ }
+ ]
+ upDownOptions = [ //extra tall vertical section 3000x3000 //this is where the level boss is
+ (x = offset.x, y = offset.y) => { //mover
+ const button = level.button(x + 935, y + 0)
+ button.isUp = true
+ doCustomTopLayer.push(
+ () => {
+ button.draw();
+ if (button.isUp) {
+ button.query();
+ if (!button.isUp) {
+ const mapStartingLength = map.length //track this so you know how many you added when running addMapToLevelInProgress
+ addMapToLevelInProgress = (who) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually
+ who.collisionFilter.category = cat.map;
+ who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(who, true); //make static
+ Composite.add(engine.world, who); //add to world
+ }
+ //map elements go here
+ //box around portals
+ spawn.mapRect(x + -50, y + -2700, 150, 110);
+ spawn.mapRect(x + -50, y + -2440, 150, 25);
+ spawn.mapRect(x + 1900, y + -2715, 150, 550);
+ spawn.mapRect(x + 1900, y + -2015, 150, 50);
+ spawn.mapRect(x + 1900, y + -1115, 150, 150);
+ spawn.mapRect(x + 1900, y + -815, 150, 50);
+ spawn.mapRect(x + -50, y + -340, 150, 50);
+ // spawn.mapRect(x + -50, y + -640, 150, 150);
+ spawn.mapRect(x + 1975, y - 1015, 50, 225);
+ spawn.mapRect(x + 1975, y - 2190, 50, 200);
+ spawn.mapRect(x + -25, y - 2615, 50, 200);
+ spawn.mapRect(x + -25, y - 515, 75, 200);
+
+ //ledge to get to upper left door
+ // spawn.mapRect(x + -50, y - 1400, 100, 25);
+ spawn.mapRect(x + -25, y - 1075, 250, 25);
+ spawn.mapRect(x + -50, y - 1075, 150, 590);
+
+
+ const rampSpeed = 8 //+ Math.floor(4 * Math.random())
+ const mover4 = level.mover(x, y + -2425, 1000, 50, rampSpeed)
+ const mover3 = level.mover(x + 1000, y + -2000, 1000, 50, rampSpeed)
+ const mover2 = level.mover(x + 1000, y + -800, 1000, 50, -rampSpeed)
+ const mover1 = level.mover(x, y + -325, 1000, 50, -rampSpeed)
+ const portal1 = level.portal({
+ x: x + 125,
+ y: y - 415
+ }, 2 * Math.PI, { //right
+ x: x + 125,
+ y: y - 2515
+ }, 2 * Math.PI) //right
+
+ const portal2 = level.portal({
+ x: x + 1875,
+ y: y - 890
+ }, Math.PI, { //left
+ x: x + 1875,
+ y: y - 2090
+ }, Math.PI) //left
+
+ doCustom.push(() => {
+ portal1[2].query()
+ portal1[3].query()
+ portal2[2].query()
+ portal2[3].query()
+ mover1.push();
+ mover2.push();
+ mover3.push();
+ mover4.push();
+ })
+ doCustomTopLayer.push(() => {
+ portal1[0].draw();
+ portal1[1].draw();
+ portal1[2].draw();
+ portal1[3].draw();
+ portal2[0].draw();
+ portal2[1].draw();
+ portal2[2].draw();
+ portal2[3].draw();
+ mover1.draw();
+ mover2.draw();
+ mover3.draw();
+ mover4.draw();
+ })
+ for (let i = 0, numberOfMapElementsAdded = map.length - mapStartingLength; i < numberOfMapElementsAdded; i++) addMapToLevelInProgress(map[map.length - 1 - i])
+ simulation.draw.setPaths() //update map graphics
+
+ //blocks that ride the movers and portals
+ spawn.bodyRect(x + 175, y + -2525, 50, 75);
+ spawn.bodyRect(x + 300, y + -2525, 50, 50);
+ spawn.bodyRect(x + 500, y + -2525, 80, 75);
+
+ //mobs go here
+ spawn.randomMob(x + 175, y + -125, 0);
+ spawn.randomMob(x + 1775, y + -125, 0);
+ // spawn.randomMob(x + 1750, y + -525, 0);
+ spawn.randomMob(x + 225, y + -1000, 0);
+ spawn.randomMob(x + 1675, y + -1075, 0);
+ // spawn.randomMob(x + 1575, y + -2450, 0);
+ spawn.randomMob(x + 425, y + -1850, 0);
+ spawn.randomMob(x + 1425, y + -1200, 0);
+ spawn.randomMob(x + 350, y + -1000, 0);
+ spawn.randomLevelBoss(x + 475, y + -1475);
+ spawn.secondaryBossChance(x + 1425, y + -1425);
+ }
+ }
+ }
+ )
+ },
+ (x = offset.x, y = offset.y) => { //hopBoss2
+ const button = level.button(x + 935, y + 0)
+ button.isUp = true
+ // spawn.mapVertex(x + 5, y + -1318, "0 0 0 -250 125 -250"); //left ledges
+ // spawn.mapVertex(x + 1995, y + -1318, "0 0 0 -250 -125 -250"); // right ledges
+ doCustomTopLayer.push(
+ () => {
+ button.draw();
+ if (button.isUp) {
+ button.query();
+ if (!button.isUp) {
+ const mapStartingLength = map.length //track this so you know how many you added when running addMapToLevelInProgress
+ addMapToLevelInProgress = (who) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually
+ who.collisionFilter.category = cat.map;
+ who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(who, true); //make static
+ Composite.add(engine.world, who); //add to world
+ }
+ //map elements go here
+ spawn.mapRect(x + 150, y + -1400, 750, 50);
+ spawn.mapRect(x + 1100, y + -1400, 750, 50);
+ spawn.mapRect(x + 1825, y + -1050, 200, 50);
+ spawn.mapRect(x + -25, y + -1050, 200, 50);
+ spawn.mapRect(x + 1825, y + -325, 200, 50);
+ spawn.mapRect(x + -25, y + -325, 200, 50);
+ spawn.mapRect(x + 275, y + -700, 525, 50);
+ spawn.mapRect(x + 1200, y + -700, 525, 50);
+ spawn.mapRect(x + -25, y + -1400, 125, 1125); //side walls
+ spawn.mapRect(x + 1900, y + -1400, 150, 1125);
+ spawn.mapRect(x + 1900, y + -2700, 125, 1000);
+ spawn.mapRect(x + -50, y + -2725, 150, 1025);
+ spawn.mapRect(x + -25, y + -1750, 450, 50);
+ spawn.mapRect(x + 1575, y + -1750, 450, 50);
+ spawn.mapRect(x + 525, y + -1750, 950, 50);
+ for (let i = 0, numberOfMapElementsAdded = map.length - mapStartingLength; i < numberOfMapElementsAdded; i++) addMapToLevelInProgress(map[map.length - 1 - i])
+ simulation.draw.setPaths() //update map graphics
+ //mobs go here
+ powerUps.directSpawn(x + 50, y - 1525, "ammo");
+ powerUps.directSpawn(x + 1950, y - 1525, "ammo");
+ powerUps.directSpawn(x + 1900, y - 1525, "ammo");
+ spawn.hopMomBoss(x + 800, y + -2200)
+ for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 150 + 750 * Math.random(), y + -1600)
+ for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 1100 + 750 * Math.random(), y + -1600)
+ spawn.hopper(x + 1550, y + -775);
+ spawn.hopper(x + 500, y + -775);
+ spawn.hopper(x + 1400, y + -775);
+ spawn.hopper(x + 550, y + -775);
+ spawn.hopper(x + 525, y + -1475);
+ spawn.hopper(x + 1550, y + -1500);
+ }
+ }
+ }
+ )
+ },
+ (x = offset.x, y = offset.y) => {
+ // const toggle = level.toggle(x + 950, y + 0, false, true) // toggle(x, y, isOn = false, isLockOn = false) {
+ // toggle.isAddedElements = false
+
+ const button = level.button(x + 935, y + 0)
+ button.isUp = true
+
+
+ spawn.mapVertex(x + 5, y + -1318, "0 0 0 -250 125 -250"); //left ledges
+ spawn.mapVertex(x + 1995, y + -1318, "0 0 0 -250 -125 -250"); // right ledges
+ doCustomTopLayer.push(
+ () => {
+ button.draw();
+ if (button.isUp) {
+ button.query();
+ if (!button.isUp) {
+ // toggle.isAddedElements = true //only do this once
+ addMapToLevelInProgress = (who) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually
+ who.collisionFilter.category = cat.map;
+ who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(who, true); //make static
+ Composite.add(engine.world, who); //add to world
+ }
+ let r = 150
+ let hexagon = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 ${r * Math.cos(2.0944)} ${r * Math.sin(2.0944)} ${r * Math.cos(1.0472)} ${r * Math.sin(1.0472)} `
+ //450 horizontal spread // -130-130-130 = 390 vertical
+ if (Math.random() < 0.5) {
+ spawn.mapVertex(x + 775, y + -260, hexagon);
+ spawn.mapVertex(x + 1225, y + -260, hexagon);
+
+ spawn.mapVertex(x + 550, y + -650, hexagon);
+ spawn.mapVertex(x + 1000, y + -650, hexagon);
+ spawn.mapVertex(x + 1450, y + -650, hexagon);
+
+ spawn.mapVertex(x + 325, y + -1040, hexagon);
+ spawn.mapVertex(x + 775, y + -1040, hexagon);
+ spawn.mapVertex(x + 1225, y + -1040, hexagon);
+ spawn.mapVertex(x + 1675, y + -1040, hexagon);
+
+ spawn.mapVertex(x + 550, y + -1430, hexagon);
+ spawn.mapVertex(x + 1000, y + -1430, hexagon);
+ spawn.mapVertex(x + 1450, y + -1430, hexagon);
+
+ const numberOfMapElementsAdded = 12
+ for (let i = 0; i < numberOfMapElementsAdded; i++) addMapToLevelInProgress(map[map.length - 1 - i])
+ spawn.randomMob(x + 225, y + -1775, mobSpawnChance);
+ spawn.randomMob(x + 700, y + -1750, mobSpawnChance);
+ spawn.randomMob(x + 1175, y + -1725, mobSpawnChance);
+ spawn.randomMob(x + 1700, y + -1700, mobSpawnChance);
+ spawn.randomMob(x + 1750, y + -250, mobSpawnChance);
+ spawn.randomMob(x + 125, y + -250, mobSpawnChance);
+ } else {
+ spawn.mapVertex(x + 775, y + -260, hexagon);
+ spawn.mapVertex(x + 1225, y + -260, hexagon);
+
+ spawn.mapVertex(x + 550, y + -650, hexagon);
+ spawn.mapVertex(x + 1000, y + -650, hexagon);
+ spawn.mapVertex(x + 1450, y + -650, hexagon);
+
+ spawn.mapVertex(x + 775, y + -1040, hexagon);
+ spawn.mapVertex(x + 1225, y + -1040, hexagon);
+
+ spawn.mapVertex(x + 550, y + -1430, hexagon);
+ spawn.mapVertex(x + 1000, y + -1430, hexagon);
+ spawn.mapVertex(x + 1450, y + -1430, hexagon);
+
+ spawn.mapVertex(x + 775, y + -1820, hexagon);
+ spawn.mapVertex(x + 1225, y + -1820, hexagon);
+ const numberOfMapElementsAdded = 12
+ for (let i = 0; i < numberOfMapElementsAdded; i++) addMapToLevelInProgress(map[map.length - 1 - i])
+
+ spawn.randomMob(x + 225, y + -1025, mobSpawnChance);
+ spawn.randomMob(x + 250, y + -1025, mobSpawnChance);
+ spawn.randomMob(x + 200, y + -675, mobSpawnChance);
+ spawn.randomMob(x + 225, y + -200, mobSpawnChance);
+ spawn.randomMob(x + 1750, y + -1075, mobSpawnChance);
+ spawn.randomMob(x + 1700, y + -650, mobSpawnChance);
+ spawn.randomMob(x + 1725, y + -650, mobSpawnChance);
+ spawn.randomMob(x + 1675, y + -175, mobSpawnChance);
+ }
+ simulation.draw.setPaths() //update map graphics
+ spawn.randomGroup(x + 300, y + -2200);
+ spawn.randomGroup(x + 1625, y + -2200);
+ spawn.randomLevelBoss(x + 700, y + -2300);
+ spawn.secondaryBossChance(x + 1250, y + -2300)
+ }
+ }
+ // toggle.query();
+ // if (toggle.isOn && !toggle.isAddedElements) { //this code runs once after the toggle is triggered
+
+ // }
+ }
+ )
+ },
+ (x = offset.x, y = offset.y) => {
+ // const toggle = level.toggle(x + 950, y + 0, false, true) // toggle(x, y, isOn = false, isLockOn = false) {
+ // toggle.isAddedElements = false
+ const button = level.button(x + 935, y + 0)
+ button.isUp = true
+ //left ledges
+ spawn.mapVertex(x + 5, y + -1868, "0 0 0 -250 125 -250");
+ spawn.mapVertex(x + 5, y + -1318, "0 0 0 -250 125 -250"); //door
+ spawn.mapVertex(x + 5, y + -768, "0 0 0 -250 125 -250");
+ // right ledges
+ spawn.mapVertex(x + 2000, y + -1868, "0 0 0 -250 -125 -250");
+ spawn.mapVertex(x + 2000, y + -1318, "0 0 0 -250 -125 -250"); //door
+ spawn.mapVertex(x + 2000, y + -768, "0 0 0 -250 -125 -250");
+
+ doCustomTopLayer.push(
+ () => {
+ button.draw();
+ if (button.isUp) {
+ button.query();
+ if (!button.isUp) {
+ addMapToLevelInProgress = (who) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually
+ who.collisionFilter.category = cat.map;
+ who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(who, true); //make static
+ Composite.add(engine.world, who); //add to world
+ }
+ //right side hexagons
+ let r = 300
+ let hexagon = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 ${r * Math.cos(2.0944)} ${r * Math.sin(2.0944)} ${r * Math.cos(1.0472)} ${r * Math.sin(1.0472)} `
+ spawn.mapVertex(x + 1640, y + -365, hexagon);
+ // r = 275
+ // let hexagonHalf = `${r} 0 ${r*Math.cos(5.236)} ${r*Math.sin(5.236)} ${r*Math.cos(4.189)} ${r*Math.sin(4.189)} ${-r} 0 `
+ // spawn.mapVertex(x + 2300, y + -75, hexagonHalf);
+ r = 150
+ const hexagon150 = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 ${r * Math.cos(2.0944)} ${r * Math.sin(2.0944)} ${r * Math.cos(1.0472)} ${r * Math.sin(1.0472)} `
+ // spawn.mapVertex(x + 1750, y + -550, hexagon150);
+ spawn.mapVertex(x + 1750, y + -1100, hexagon150);
+ spawn.mapVertex(x + 1750, y + -1650, hexagon150);
+ spawn.mapVertex(x + 1750, y + -2200, hexagon150);
+
+ //left side
+ r = 350
+ let hexagonHalf = `${r} 0 ${r * Math.cos(5.236)} ${r * Math.sin(5.236)} ${r * Math.cos(4.189)} ${r * Math.sin(4.189)} ${-r} 0 `
+ spawn.mapVertex(x + 425, y + -90, hexagonHalf);
+
+ spawn.mapVertex(x + 850, y + -500, hexagon150);
+ spawn.mapVertex(x + 550, y + -850, hexagon150);
+ spawn.mapVertex(x + 250, y + -1200, hexagon150);
+ spawn.mapVertex(x + 250, y + -1700, hexagon150);
+ spawn.mapVertex(x + 725, y + -1950, hexagon150);
+ spawn.mapVertex(x + 1200, y + -2200, hexagon150);
+ const numberOfMapElementsAdded = 11
+ for (let i = 0; i < numberOfMapElementsAdded; i++) addMapToLevelInProgress(map[map.length - 1 - i])
+
+ spawn.randomMob(x + 1050, y + -1500, mobSpawnChance);
+ spawn.randomMob(x + 1075, y + -1500, mobSpawnChance);
+ spawn.randomMob(x + 325, y + -550, mobSpawnChance);
+ spawn.randomMob(x + 800, y + -925, mobSpawnChance);
+ spawn.randomMob(x + 1400, y + -1250, mobSpawnChance);
+ spawn.randomMob(x + 1325, y + -1725, mobSpawnChance);
+ spawn.randomMob(x + 1350, y + -1725, mobSpawnChance);
+ spawn.randomMob(x + 575, y + -1375, mobSpawnChance);
+ spawn.randomMob(x + 225, y + -2275, mobSpawnChance);
+ spawn.randomMob(x + 875, y + -2450, mobSpawnChance);
+ spawn.randomMob(x + 1550, y + -2525, mobSpawnChance);
+ spawn.randomMob(x + 1525, y + -2525, mobSpawnChance);
+ spawn.randomLevelBoss(x + 1075, y + -1500);
+ spawn.secondaryBossChance(x + 1200, y + -1000)
+ simulation.draw.setPaths() //update map graphics
+ }
+ }
+ }
+ )
+ },
+ // (x = offset.x, y = offset.y) => {
+ // const elevator1 = level.elevator(x + 1100, y - 200, 250, 30, -2100, 0.0015) // x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }, isTeleport = false) {
+ // // const elevator1 = level.elevator(x + 175, y - 200, 250, 30, -1400, 0.001)
+ // // const elevator2 = level.elevator(x + 2175, y - 200, 250, 30, -1400, 0.001)
+
+ // spawn.mapRect(-200, -1400, 350, 50); //up left door ledge
+ // spawn.mapRect(2450, -1400, 350, 50); //up right door ledge
+
+ // spawn.mapRect(225, -450, 350, 350); //left crawl zone
+ // // spawn.mapRect(725, -175, 275, 75);
+ // spawn.mapRect(725, -225, 350, 100);
+ // spawn.mapRect(275, -750, 200, 200);
+ // spawn.mapRect(1375, -700, 500, 750); //right side big elevator wall
+ // spawn.mapRect(2375, -325, 350, 50);
+ // spawn.mapRect(1800, -500, 250, 50);
+
+ // //up high elevator
+ // spawn.mapRect(1375, -2100, 500, 175);
+ // spawn.mapRect(600, -2100, 475, 175);
+
+ // if (simulation.difficulty > 3) spawn.randomLevelBoss(x + 1250, y - 1400);
+ // doCustomTopLayer.push(
+ // () => {
+ // elevator1.move()
+ // }
+ // )
+ // }
+ ]
+ //pick which type of room spawns
+ enter = enterOptions[Math.floor(Math.random() * enterOptions.length)];
+ exit = exitOptions[Math.floor(Math.random() * exitOptions.length)];
+ empty = emptyOptions[Math.floor(Math.random() * emptyOptions.length)];
+ loot = lootOptions[Math.floor(Math.random() * lootOptions.length)];
+ upDown = upDownOptions[Math.floor(Math.random() * upDownOptions.length)];
+ // upDown = upDownOptions[0] //controls what level spawns for map designing building //********************************* DO !NOT! RUN THIS LINE IN THE FINAL VERSION ***************************************
+ //3x2: 4 short rooms (3000x1500), 1 double tall room (3000x3000)
+ //rooms
+ let rooms = ["exit", "loot", "enter", "empty"]
+ rooms = shuffle(rooms); //shuffles array order
+ //look... you and I both know there is a better way to do this, but it works so I'm gonna focus on other things
+ while ( //makes sure that the exit and entrance aren't both on the same floor
+ (rooms[0] === "enter" && rooms[2] === "exit") ||
+ (rooms[2] === "enter" && rooms[0] === "exit") ||
+ (rooms[1] === "enter" && rooms[3] === "exit") ||
+ (rooms[3] === "enter" && rooms[1] === "exit")
+ ) rooms = shuffle(rooms); //shuffles array order
+ for (let i = 0; i < rooms.length; i++) {
+ if (rooms[i] === "enter") rooms[i] = enter
+ if (rooms[i] === "exit") rooms[i] = exit
+ if (rooms[i] === "empty") rooms[i] = empty
+ if (rooms[i] === "loot") rooms[i] = loot
+ }
+ // rooms = [enter, exit, loot, empty, ] //controls what level spawns for map designing building //********************************* DO !NOT! RUN THIS LINE IN THE FINAL VERSION ***************************************
+
+ outline = (isLower = true) => {
+ spawn.mapRect(offset.x - 100, offset.y - 1400, 2100, 100); //ceiling
+ if (isLower) spawn.mapRect(offset.x - 100, offset.y, 2200, 100); //only draw floor if on the lower level
+ if (!isDoorLeft) spawn.mapRect(offset.x - 100, offset.y - 1400, 100, 1500); //left wall
+ if (isDoorRight) { //if door only add wall on right side
+ spawn.mapRect(offset.x + 2000, offset.y - 1400, 100, 1225); //right wall
+ spawn.mapRect(offset.x + 2000, offset.y - 10, 100, 20); //right doorstep
+ const doorWidth = 15 + Math.floor(100 * Math.random() * Math.random())
+ spawn.bodyRect(offset.x + 2050 - doorWidth / 2, offset.y - 175, doorWidth, 165); //block door
+ } else {
+ spawn.mapRect(offset.x + 2000, offset.y - 1400, 100, 1500); //right wall
+ }
+ }
+ outlineUpDown = () => {
+ spawn.mapRect(offset.x - 100, offset.y + 0, 2100, 100); //floor
+ spawn.mapRect(offset.x - 100, offset.y - 2800, 2100, 100); //ceiling
+ if (!isDoorLeft) spawn.mapRect(offset.x - 100, offset.y - 2800, 100, 2900); //left wall
+ if (isDoorRight) { //if door only add wall on right side
+ //upper door
+ spawn.mapRect(offset.x + 2000, offset.y - 2800, 100, 1225); //right wall
+ spawn.mapRect(offset.x + 2000, offset.y - 1410, 100, 20); //right doorstep
+ const doorWidth = 15 + Math.floor(100 * Math.random() * Math.random())
+ spawn.bodyRect(offset.x + 2050 - doorWidth / 2, offset.y - 1575, doorWidth, 165); //block door
+ //lower door
+ spawn.mapRect(offset.x + 2000, offset.y - 1400, 100, 1225); //right wall
+ spawn.mapRect(offset.x + 2000, offset.y - 10, 100, 20); //right doorstep
+ const doorWidth2 = 15 + Math.floor(100 * Math.random() * Math.random())
+ spawn.bodyRect(offset.x + 2050 - doorWidth2 / 2, offset.y - 175, doorWidth2, 165); //block door
+ } else {
+ spawn.mapRect(offset.x + 2000, offset.y - 2800, 100, 2900); //right wall
+ }
+ }
+
+ let columns = [
+ () => {
+ offset.y = 0
+ outlineUpDown()
+ upDown()
+ },
+ () => {
+ offset.y = 0
+ outline()
+ rooms[0]()
+
+ offset.y = -1400
+ outline(false)
+ rooms[1]()
+ },
+ () => {
+ offset.y = 0
+ outline()
+ rooms[2]()
+
+ offset.y = -1400
+ outline(false)
+ rooms[3]()
+ },
+ ]
+ columns = shuffle(columns) //********************************* RUN THIS LINE IN THE FINAL VERSION ***************************************
+ for (let i = 0; i < 3; i++) {
+ if (i === 0) {
+ isDoorLeft = false
+ isDoorRight = true
+ } else if (i === 1) {
+ isDoorLeft = true
+ isDoorRight = true
+ } else {
+ isDoorLeft = true
+ isDoorRight = false
+ }
+ offset.x = i * 2100
+ columns[i]()
+ }
+ level.custom = () => {
+ for (let i = 0, len = doCustom.length; i < len; i++) doCustom[i]() //runs all the active code from each room
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ for (let i = 0, len = doCustomTopLayer.length; i < len; i++) doCustomTopLayer[i]() //runs all the active code from each room
+ };
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ pavilion() {
+ const vanish = []
+ level.exit.x = -850;
+ level.exit.y = -1485;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 25);
+ level.setPosToSpawn(-900, 225); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.defaultZoom = 1500
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#dcdcde";
+ spawn.debris(-150, -775, 1425, 3); //16 debris per level
+ spawn.debris(1525, -25, 950, 3); //16 debris per level
+ spawn.debris(-650, -2100, 575, 2); //16 debris per level
+
+ //bottom floor
+ //entrance
+ spawn.mapRect(-200, -750, 1500, 100);
+ spawn.mapRect(-575, 0, 2150, 500);
+ // spawn.mapRect(-1275, 275, 875, 225);
+ spawn.mapRect(-1275, 275, 3975, 225);
+ spawn.mapRect(-1050, 0, 325, 50);
+ spawn.mapRect(-775, 0, 50, 140);
+ vanish.push(level.vanish(-725, 13, 150, 25))
+ spawn.mapRect(-200, -750, 100, 600);
+ // spawn.mapRect(1200, -750, 100, 600);
+ vanish.push(level.vanish(-350, -225, 150, 225))
+ vanish.push(level.vanish(-350, -450, 150, 223))
+ spawn.mapRect(2475, -1800, 250, 2300);
+
+ spawn.mapRect(1200, -750, 100, 450);
+ spawn.mapRect(1200, -375, 250, 75);
+ powerUps.spawnStartingPowerUps(550, -100);
+ spawn.mapRect(125, -12, 850, 50);
+ spawn.mapRect(175, -25, 750, 50);
+ spawn.bodyRect(1350, -175, 150, 175, 0.5);
+ spawn.bodyRect(1350, -600, 125, 225, 0.2);
+
+ //middle floor
+ spawn.bodyRect(215, -1175, 100, 100, 0.3);
+ spawn.mapRect(-1300, -1800, 250, 2300);
+ // spawn.mapRect(-1300, -2075, 250, 2575);
+ if (Math.random() < 0.5) {
+ spawn.mapRect(500, -1350, 525, 425);
+ spawn.mapRect(25, -1050, 300, 198);
+ } else {
+ spawn.mapRect(500, -1350, 525, 497);
+ spawn.mapRect(25, -1050, 300, 150);
+ }
+ if (Math.random() < 0.5) {
+ vanish.push(level.vanish(400, -1600, 175, 25))
+ vanish.push(level.vanish(950, -1600, 175, 25))
+ } else {
+ vanish.push(level.vanish(550, -1575, 50, 225))
+ vanish.push(level.vanish(925, -1575, 50, 225))
+ }
+
+ // vanish.push(level.vanish(575, -1575, 375, 225))
+
+ spawn.bodyRect(225, -850, 50, 100, 0.4);
+ spawn.mapRect(600, -1800, 325, 225);
+ spawn.mapRect(1900, -1500, 325, 25);
+ spawn.bodyRect(1050, -1825, 250, 20, 0.2);
+ if (Math.random() < 0.5) {
+ vanish.push(level.vanish(1400, -1000, 200, 25))
+ vanish.push(level.vanish(1625, -1250, 200, 25))
+ } else {
+ vanish.push(level.vanish(1400, -1075, 175, 175))
+ vanish.push(level.vanish(1575, -1250, 175, 175))
+ }
+ vanish.push(level.vanish(1125, -1800, 625, 25))
+
+ // vanish.push(level.vanish(1500, -1800, 225, 25))
+ vanish.push(level.vanish(-50, -1800, 450, 25))
+
+ //exit
+ spawn.mapRect(-1050, -1450, 700, 25);
+ spawn.mapRect(-1050, -1800, 525, 25);
+ spawn.mapRect(-550, -1800, 25, 200);
+
+ spawn.randomMob(-1175, -1975, -0.4);
+ spawn.randomMob(275, -1500, -0.3);
+ spawn.randomMob(700, -1875, -0.2);
+ spawn.randomMob(2000, -800, -0.2);
+ spawn.randomMob(2600, -1850, 0);
+ spawn.randomMob(1425, -525, 0.1);
+ spawn.randomMob(2025, -1600, 0.3);
+ spawn.randomMob(1625, -1875, 0.3);
+ spawn.randomMob(-150, -1975, 0.4);
+ spawn.randomSmallMob(900, -825);
+ spawn.randomSmallMob(1050, -50);
+
+ if (simulation.difficulty > 1) {
+ spawn.randomGroup(750, -2150, -0.8)
+ spawn.randomLevelBoss(2050, -2025)
+ spawn.secondaryBossChance(100, -1500)
+ }
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+ level.setPosToSpawn(900, 225); //normal spawn
+ level.custom = () => {
+ ctx.fillStyle = "#d0d3d9"
+ ctx.fillRect(-2500, -1800, 3575, 2100);
+ ctx.fillStyle = "#c0c3c9"
+ ctx.fillRect(-2075, -1475, 25, 1800);
+ ctx.fillStyle = "#cff" //exit
+ ctx.fillRect(550, -1800, 525, 350)
+
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ //shadow
+ ctx.fillStyle = "rgba(0,10,30,0.1)"
+ ctx.fillRect(-1450, -300, 150, 325);
+ ctx.fillRect(-1300, -650, 1500, 650)
+ ctx.fillRect(725, 50, 325, 225)
+ ctx.fillRect(-325, -950, 300, 225)
+ ctx.fillRect(-1025, -1000, 525, 275);
+ ctx.fillRect(-925, -1600, 325, 275);
+ for (let i = 0, len = vanish.length; i < len; i++) vanish[i].query()
+ };
+
+ } else {
+ level.custom = () => {
+ ctx.fillStyle = "#d0d3d9"
+ ctx.fillRect(-1075, -1800, 3575, 2100);
+ ctx.fillStyle = "#c0c3c9"
+ ctx.fillRect(2050, -1475, 25, 1800);
+ ctx.fillStyle = "#cff" //exit
+ ctx.fillRect(-1050, -1800, 525, 350)
+
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ //shadow
+ ctx.fillStyle = "rgba(0,10,30,0.1)"
+ ctx.fillRect(1300, -300, 150, 325);
+ ctx.fillRect(-200, -675, 1500, 700)
+ ctx.fillRect(500, -950, 525, 225);
+ ctx.fillRect(600, -1600, 325, 275);
+ ctx.fillRect(-1050, 50, 325, 225)
+ ctx.fillRect(25, -950, 300, 225)
+ for (let i = 0, len = vanish.length; i < len; i++) vanish[i].query()
+ };
+ }
+ },
+ testChamber() {
+ level.setPosToSpawn(0, -50); //lower start
+ level.exit.y = level.enter.y - 550;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.x = level.enter.x;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+ level.defaultZoom = 2200
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d0d5d5";
+ color.map = "#444"
+ spawn.mapRect(0, -1955, 175, 30);
+ const removeIndex1 = map.length - 1 //so much work to catch blocks caught at the bottom of the vertical portals
+ spawn.mapRect(1225, -1955, 175, 30);
+ const removeIndex2 = map.length - 1 //so much work to catch blocks caught at the bottom of the vertical portals
+ let portal, portal2, portal3
+ const hazard = level.hazard((simulation.isHorizontalFlipped ? -350 - 700 : 350), -2025, 700, 10, 0.4) //laser
+ spawn.mapRect(340, -2032.5, 20, 25); //laser nose
+ const hazard2 = level.hazard((simulation.isHorizontalFlipped ? -1775 - 150 : 1775), -2550, 150, 10, 0.4) //laser
+ spawn.mapRect(1920, -2557.5, 20, 25); //laser nose
+ const button = level.button(2100, -2600)
+ const buttonDoor = level.button(600, -550)
+ const door = level.door(312, -750, 25, 190, 185)
+
+ level.custom = () => {
+ if (!(m.cycle % 60)) { //so much work to catch blocks caught at the bottom of the vertical portals
+ let touching = Matter.Query.collides(map[removeIndex1], body)
+ if (touching.length) {
+ Matter.Composite.remove(engine.world, touching[0].bodyB);
+ for (let i = 0, len = body.length; i < len; i++) {
+ if (body[i].id === touching[0].bodyB.id) {
+ body.splice(i, 1);
+ break
+ }
+ }
+ }
+ touching = Matter.Query.collides(map[removeIndex2], body)
+ if (touching.length) {
+ Matter.Composite.remove(engine.world, touching[0].bodyB);
+ for (let i = 0, len = body.length; i < len; i++) {
+ if (body[i].id === touching[0].bodyB.id) {
+ body.splice(i, 1);
+ break
+ }
+ }
+ }
+ }
+
+ buttonDoor.query();
+ buttonDoor.draw();
+ if (buttonDoor.isUp) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+
+ portal[2].query()
+ portal[3].query()
+ portal2[2].query()
+ portal2[3].query()
+ portal3[2].query()
+ portal3[3].query()
+
+ if (button.isUp) {
+ hazard.isOn = false;
+ hazard2.isOn = false;
+ } else {
+ hazard.isOn = true;
+ hazard2.isOn = true;
+ }
+ button.query();
+ button.draw();
+
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(-300, -1000, 650, 500)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ door.draw();
+ hazard.opticalQuery();
+ hazard2.opticalQuery();
+ portal[0].draw();
+ portal[1].draw();
+ portal[2].draw();
+ portal[3].draw();
+ portal2[0].draw();
+ portal2[1].draw();
+ portal2[2].draw();
+ portal2[3].draw();
+ portal3[0].draw();
+ portal3[1].draw();
+ portal3[2].draw();
+ portal3[3].draw();
+ };
+ powerUps.spawnStartingPowerUps(1875, -3075);
+
+ const powerUpPos = shuffle([{ //no debris on this level but 2 random spawn instead
+ x: -150,
+ y: -1775
+ }, {
+ x: 2400,
+ y: -2650
+ }, {
+ x: -175,
+ y: -1375
+ }, {
+ x: 1325,
+ y: -150
+ }]);
+ powerUps.chooseRandomPowerUp(powerUpPos[0].x, powerUpPos[0].y);
+ powerUps.chooseRandomPowerUp(powerUpPos[1].x, powerUpPos[1].y);
+ //outer wall
+ spawn.mapRect(2500, -3700, 1200, 3800); //right map wall
+ spawn.mapRect(-1400, -3800, 1100, 3900); //left map wall
+ spawn.mapRect(-1400, -4800, 5100, 1200); //map ceiling
+ spawn.mapRect(-1400, 0, 5100, 1200); //floor
+ //lower entrance /exit
+ spawn.mapRect(300, -375, 50, 225);
+ spawn.bodyRect(312, -150, 25, 140);
+ spawn.mapRect(300, -10, 50, 50);
+ spawn.mapVertex(1555, 0, "625 0 75 0 200 -100 500 -100"); //entrance ramp
+ //upper entrance / exit
+ spawn.mapRect(-400, -1050, 750, 50);
+ spawn.mapRect(300, -1050, 50, 300);
+ // spawn.bodyRect(312, -750, 25, 190);
+ spawn.mapRect(300, -560, 50, 50);
+ spawn.bodyRect(750, -725, 125, 125);
+ spawn.mapRect(1150, -1050, 250, 575);
+ spawn.mapRect(1725, -550, 50, 200); //walls around portal 3
+ spawn.mapRect(1925, -550, 500, 200);
+ spawn.mapRect(1750, -390, 200, 40);
+ spawn.mapRect(-400, -550, 1800, 200);
+ spawn.mapRect(-200, -1700, 150, 25); //platform above exit room
+ spawn.mapRect(-200, -1325, 350, 25);
+ //portal 3 angled
+ spawn.mapRect(2425, -450, 100, 100);
+ //portal 1 bottom
+ spawn.mapRect(2290, -12, 375, 100);
+ spawn.mapRect(2350, -24, 375, 100);
+ spawn.mapRect(2410, -36, 375, 100);
+ //portal 1 top
+ spawn.mapRect(2290, -3012, 375, 50);
+ spawn.mapRect(2350, -3024, 375, 50);
+ spawn.mapRect(2410, -3036, 375, 50);
+ spawn.mapRect(1400, -3000, 1300, 50); //floor
+ spawn.mapRect(1750, -3050, 250, 75);
+ spawn.mapRect(1400, -3625, 50, 200);
+ spawn.mapRect(350, -3625, 50, 225);
+ spawn.mapRect(350, -3260, 50, 60);
+ spawn.mapRect(200, -3250, 1240, 50);
+ spawn.mapRect(1400, -3260, 50, 310);
+ spawn.bodyRect(1412, -3425, 25, 165);
+ spawn.mapRect(-150, -2925, 150, 25);
+ //portal 2
+ spawn.mapRect(-300, -2600, 300, 675); //left platform
+ spawn.mapRect(1400, -2600, 375, 675); //right platform
+ spawn.mapRect(1925, -2600, 775, 675); //far right platform
+ spawn.bodyRect(2130, -2660, 50, 50); //button's block
+ spawn.mapRect(150, -2100, 200, 175);
+ spawn.mapRect(1050, -2100, 200, 175);
+ //mobs
+ spawn.randomMob(1075, -3500, -0.3);
+ spawn.randomMob(2175, -700, -0.2);
+ spawn.randomMob(-75, -850, -0.1);
+ spawn.randomMob(550, -3400, 0);
+ spawn.randomMob(0, -1175, 0.5);
+ spawn.randomMob(-75, -1150, 0.5);
+ spawn.randomMob(1075, -625, 0.5);
+ spawn.randomMob(800, -3400, -0.3);
+ spawn.randomMob(1225, -3375, -0.2);
+ spawn.randomMob(1200, -1125, -0.1);
+ spawn.randomMob(2050, -950, 0.5);
+ if (simulation.difficulty > 40) {
+ spawn.randomMob(2300, -2775, -0.5);
+ spawn.randomMob(600, -925, -0.5);
+ spawn.randomMob(1550, -2750, -0.5);
+ spawn.randomMob(1350, -1150, -0.5);
+ spawn.randomMob(-75, -1475, 0);
+ spawn.randomGroup(600, -2600, 0);
+ }
+ if (simulation.difficulty > 1) {
+ if (Math.random() < 0.5) {
+ spawn.randomLevelBoss(700, -1550);
+ } else {
+ spawn.randomLevelBoss(675, -2775); //["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "shieldingBoss", "pulsarBoss", "grenadierBoss"]
+ }
+ }
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ spawn.secondaryBossChance(1925, -1250)
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+ // level.setPosToSpawn(0, -50); //-x // no need since 0
+ button.min.x = -button.min.x - 126 // flip the button horizontally
+ button.max.x = -button.max.x + 126 // flip the button horizontally
+ buttonDoor.min.x = -buttonDoor.min.x - 126 // flip the button horizontally
+ buttonDoor.max.x = -buttonDoor.max.x + 126 // flip the button horizontally
+
+ //this makes the hazard draw, but not collide for reasons I don't understand
+ //so don't use it, instead just call the hazard differently based on this flip flag
+ // hazard.min.x = -hazard.min.x - hazard.width //-x-width
+ // hazard.max.x = -hazard.max.x - hazard.width //-x-width
+ // hazard2.min.x = -hazard2.min.x - hazard2.width //-x-width
+ // hazard2.max.x = -hazard2.max.x - hazard2.width //-x-width
+ portal = level.portal({
+ x: -2475,
+ y: -140
+ }, 2 * Math.PI, { //right
+ x: -2475,
+ y: -3140
+ }, 2 * Math.PI) //right
+
+ portal2 = level.portal({
+ x: -75,
+ y: -2150
+ }, -Math.PI / 2, { //up
+ x: -1325,
+ y: -2150
+ }, -Math.PI / 2) //up
+
+ portal3 = level.portal({
+ x: -1850,
+ y: -585
+ }, -Math.PI / 2, { //up
+ x: -2425,
+ y: -600
+ }, -1 * Math.PI / 3) //up left
+
+ // level.custom = () => { };
+ // level.customTopLayer = () => {};
+
+ } else {
+ portal = level.portal({
+ x: 2475,
+ y: -140
+ }, Math.PI, { //left
+ x: 2475,
+ y: -3140
+ }, Math.PI) //left
+ portal2 = level.portal({
+ x: 75,
+ y: -2150
+ }, -Math.PI / 2, { //up
+ x: 1325,
+ y: -2150
+ }, -Math.PI / 2) //up
+ portal3 = level.portal({
+ x: 1850,
+ y: -585
+ }, -Math.PI / 2, { //up
+ x: 2425,
+ y: -600
+ }, -2 * Math.PI / 3) //up left
+ }
+
+ },
+ lock() {
+ level.setPosToSpawn(0, -65); //lower start
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.y = 2010;
+ level.exit.x = 2625;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+ level.defaultZoom = 2200
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "hsl(138, 5%, 82%)";
+ color.map = "#444"
+ powerUps.spawnStartingPowerUps(1768, 870); //on left side
+ const portal = level.portal({ x: 1070, y: -1485 }, -0.9, { x: 475, y: 50 }, -Math.PI / 2)
+ const doorCenterRight = level.door(2787, 775, 25, 225, 195, 5) //x, y, width, height, distance, speed = 1
+ const doorCenterLeft = level.door(2537, 775, 25, 225, 195, 5)
+ const doorButtonRight = level.door(4462, 1010, 25, 225, 195, 5)
+ const doorLeft = level.door(2538, 1825, 25, 225, 195, 5)
+ const buttonLeft = level.button(4565, 1235)
+ const buttonRight = level.button(4142, -355)
+ // spawn.mapRect(4000, -350, 700, 125); //button platform
+ spawn.mapRect(4000, -350, 600, 75);
+ buttonLeft.isUp = true
+ buttonRight.isUp = true
+ const hazardSlimeLeft = level.hazard(900, -300, 1638, 2450) //hazard(x, y, width, height, damage = 0.002) {
+ const hazardSlimeRight = level.hazard(2812, -300, 1650, 2450) //hazard(x, y, width, height, damage = 0.002) {
+ //set slime to empty
+ // hazardSlimeLeft.height -= hazardSlimeLeft.maxHeight //start slime at zero
+ // hazardSlimeLeft.min.y += hazardSlimeLeft.maxHeight
+ // hazardSlimeLeft.max.y = hazardSlimeLeft.min.y + hazardSlimeLeft.height
+ // hazardSlimeRight.height -= hazardSlimeRight.maxHeight //start slime at zero
+ // hazardSlimeRight.min.y += hazardSlimeRight.maxHeight
+ // hazardSlimeRight.max.y = hazardSlimeRight.min.y + hazardSlimeRight.height
+ const balance = []
+ level.custom = () => {
+ ctx.fillStyle = "hsl(175, 35%, 76%)" //exit
+ ctx.fillRect(2537, 1775, 275, 275)
+ level.exit.drawAndCheck();
+ level.enter.draw();
+
+ doorButtonRight.isClosing = hazardSlimeRight.min.y < 1275
+ doorCenterRight.isClosing = hazardSlimeRight.min.y < 1000
+ doorCenterLeft.isClosing = hazardSlimeLeft.min.y < 1000
+ doorLeft.isClosing = hazardSlimeLeft.min.y < 2050
+ doorButtonRight.openClose();
+ doorCenterRight.openClose();
+ doorCenterLeft.openClose();
+ doorLeft.openClose();
+ if (buttonRight.isUp) {
+ buttonRight.query();
+ if (!buttonRight.isUp) spawnRightMobs()
+ }
+ if (buttonLeft.isUp) {
+ buttonLeft.query();
+ if (!buttonLeft.isUp) spawnLeftMobs()
+ }
+ buttonRight.draw();
+ buttonLeft.draw();
+ if (hazardSlimeLeft.min.y < 2050) {
+ const drainRate = Math.min(Math.max(0.25, 4 - hazardSlimeLeft.min.y / 500), 4)
+ hazardSlimeLeft.level(buttonLeft.isUp, drainRate)
+ }
+ if (hazardSlimeRight.min.y < 2050) {
+ const drainRate = Math.min(Math.max(0.25, 4 - hazardSlimeRight.min.y / 500), 4)
+ hazardSlimeRight.level(buttonRight.isUp, drainRate)
+ }
+ portal[2].query()
+ portal[3].query()
+ };
+ level.customTopLayer = () => {
+ doorButtonRight.draw();
+ doorCenterRight.draw();
+ doorCenterLeft.draw();
+ doorLeft.draw();
+ hazardSlimeLeft.query();
+ hazardSlimeRight.query();
+ portal[0].draw();
+ portal[1].draw();
+ portal[2].draw();
+ portal[3].draw();
+ ctx.fillStyle = color.map //below portal
+ ctx.fillRect(375, 150, 200, 2525);
+ ctx.fillStyle = "rgba(0,0,0,0.1)" //shadows
+ ctx.fillRect(-250, -1550, 1250, 1575);
+ ctx.fillRect(2537, -350, 275, 2425);
+ ctx.fillStyle = "rgba(0,0,0,0.05)" //exit
+ ctx.fillRect(-175, -300, 375, 300)
+ ctx.fillRect(4460, 950, 350, 325);
+ ctx.fillStyle = "#233" //balances center dot
+ ctx.beginPath();
+ for (let i = 0; i < balance.length; i++) {
+ ctx.arc(balance[i].center.x, balance[i].center.y, 9, 0, 2 * Math.PI);
+ }
+ ctx.fill();
+ // for (let i = 0, len = vanish.length; i < len; i++) vanish[i].query()
+ };
+ //entrance and outer walls
+ spawn.mapRect(-1400, 0, 1800, 2675);
+ spawn.mapRect(-1400, -1025, 1225, 1500);
+ spawn.mapRect(-325, -15, 525, 225);
+ spawn.mapRect(150, -350, 50, 175);
+
+ spawn.mapRect(-1400, -3525, 1600, 3225);
+ spawn.mapRect(550, 0, 450, 2675);
+
+ spawn.mapRect(550, -1550, 450, 125);
+ spawn.mapRect(150, -1550, 250, 125);
+ spawn.mapRect(750, -1425, 1100, 175);
+ spawn.mapRect(750, -1400, 250, 825);
+ spawn.mapRect(750, -350, 250, 575);
+ spawn.mapRect(625, 2100, 4300, 575); //floor
+ spawn.mapRect(-1400, -4425, 7250, 1000); //ceiling
+ // const vanish = []
+ // vanish.push(level.vanish(400, -1512, 150, 50))
+ // vanish.push(level.vanish(825, -625, 100, 325))
+
+ //left button room (on the far right in the
+ spawn.mapRect(4450, -3525, 1400, 4500);
+ spawn.mapRect(4450, 1235, 1400, 1440);
+ spawn.mapRect(4775, 750, 1075, 825);
+ spawn.mapRect(4450, 950, 50, 75);
+
+
+ //other ideas for left and right alternate setups
+ //just a floor covered with boosts
+ //something focused on funnel shapes
+ //several rooms with tunnels connecting them
+ //spinners
+
+ //right side
+ if (Math.random() < 1) {
+ spawn.mapVertex(3350, 350, "-100 0 100 0 100 700 0 750 -100 700");
+ balance.push(level.rotor(3463, 150, 300, 25, 0.001, 0)) //balance(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0, rotationForce = 0.0005) {
+ balance.push(level.rotor(3463, 500, 300, 25, 0.001, 0))
+ spawn.mapVertex(3875, 350, "-100 0 100 0 100 700 0 750 -100 700");
+
+ spawn.mapVertex(2900, 1743, "-100 0 70 0 100 30 100 1000 -100 1000");
+ spawn.mapVertex(3025, 1811, "-150 0 120 0 150 30 150 600 -150 600");
+ spawn.mapVertex(3200, 2079, "-150 0 120 0 150 30 150 600 -150 600");
+ spawn.mapVertex(4425, 1743, "-150 30 -120 0 150 0 150 1000 -150 1000");
+ spawn.mapVertex(4250, 1811, "-150 30 -120 0 150 0 150 600 -150 600");
+ spawn.mapVertex(4075, 2079, "-150 30 -120 0 150 0 150 600 -150 600");
+
+ //escape ledge when drowning
+ spawn.mapRect(2750, 525, 100, 25);
+ spawn.mapRect(2750, 125, 100, 25);
+ spawn.mapRect(4425, 800, 75, 25);
+ spawn.mapRect(4425, 325, 75, 25);
+ // spawn.mapRect(4425, -100, 75, 25);
+ // spawn.mapRect(4425, -550, 75, 25);
+ // spawn.mapRect(4425, -1000, 75, 25);
+
+
+ // if (Math.random() < 0.5) {
+ // spawn.mapRect(2775, 525, 100, 25);
+ // spawn.mapRect(3200, 75, 125, 25);
+ // } else {
+ // spawn.mapRect(4400, 800, 100, 25);
+ // spawn.mapRect(3925, 400, 100, 25);
+ // }
+ }
+ //left side
+ if (Math.random() < 1) {
+ // spawn.mapVertex(2325, 1325, "-150 0 150 0 150 150 0 225 -150 150");
+ spawn.mapVertex(1285, 1275, "-150 0 150 0 150 150 0 225 -150 150");
+ spawn.mapVertex(1033, 1750, "0 200 200 200 300 50 300 -50 200 -200 0 -200");
+ spawn.mapVertex(1575, 1750, "0 200 -200 200 -300 50 -300 -50 -200 -200 0 -200 100 -50 100 50"); //larger "0 400 -250 400 -400 100 -400 -100 -250 -400 0 -400"
+
+ spawn.mapVertex(1287, 2185, "-100 30 -80 0 80 0 100 30 100 300 -100 300");
+ spawn.mapVertex(2050, 2050, "-150 30 -120 0 120 0 150 30 150 300 -150 300");
+
+ // spawn.mapRect(1700, 1550, 275, 25);
+ // spawn.mapRect(2175, 1275, 325, 25);
+ spawn.mapRect(1600, 950, 375, 25);
+
+ spawn.mapRect(1025, -50, 50, 25);
+ spawn.mapRect(1025, 275, 175, 25);
+ spawn.mapRect(1025, 600, 325, 25);
+ spawn.mapRect(2450, -50, 50, 25);
+ spawn.mapRect(2325, 275, 175, 25);
+ spawn.mapRect(2175, 600, 325, 25);
+ // spawn.mapVertex(3400, 1250, "-100 -300 0 -350 100 -300 100 300 0 350 -100 300");
+ }
+
+ //left button room in center divider
+ spawn.mapRect(2525, -350, 300, 1100);
+ spawn.mapRect(2525, 975, 300, 800);
+ spawn.mapRect(2775, 650, 50, 125);
+ spawn.mapRect(2525, 650, 50, 125);
+
+ //exit room
+ spawn.mapRect(2475, 2040, 350, 200);
+ spawn.mapRect(2800, 1750, 25, 325);
+ spawn.mapRect(2525, 1750, 50, 75);
+
+ //safety edge blocks //maybe remove?
+ // spawn.mapRect(2525, -375, 25, 50);
+ // spawn.mapRect(2800, -375, 25, 50);
+ // spawn.mapRect(1825, -1450, 25, 50);
+ // spawn.mapRect(4000, -375, 25, 50);
+
+ //blocks
+ spawn.bodyRect(150, -175, 50, 165, 0.2); //block at entrance
+ spawn.bodyRect(1275, 825, 100, 100, 0.2);
+ spawn.bodyRect(2600, -425, 150, 50, 0.2);
+ spawn.bodyRect(3900, -150, 50, 100, 0.2);
+ spawn.bodyRect(3350, 1950, 75, 100, 0.2);
+ spawn.bodyRect(3850, 1975, 75, 75, 0.2);
+ spawn.bodyRect(1600, 1950, 75, 100, 0.2);
+ spawn.bodyRect(725, -1650, 150, 100, 0.2);
+ spawn.bodyRect(800, -1700, 75, 50, 0.2);
+
+ const spawnRightMobs = () => {
+ spawn.randomMob(4200, 100, 1);
+ spawn.randomMob(4200, 600, 1);
+ spawn.randomMob(2975, 625, 0.5);
+ spawn.randomMob(3050, 100, 0.5);
+ spawn.randomMob(3400, -100, 0.4);
+ spawn.randomMob(3825, -100, 0.4);
+ spawn.randomMob(3625, 1950, 0.4);
+ spawn.randomMob(3275, 1650, 0.4);
+ spawn.randomMob(3075, 1375, 0.3);
+ spawn.randomMob(4000, 1650, 0.1);
+ spawn.randomMob(4100, 1425, 0);
+ spawn.randomGroup(3025, 325, 1);
+ if (simulation.difficulty > 1) spawn.secondaryBossChance(3520, 1169)
+ }
+
+ const spawnLeftMobs = () => {
+ spawn.randomMob(2375, 1900, 1);
+ spawn.randomMob(1825, 1325, 0.5);
+ spawn.randomMob(2250, 1050, 0.5);
+ spawn.randomMob(1675, 825, 0.4);
+ spawn.randomMob(1250, 575, 0.4);
+ spawn.randomMob(2400, 575, 0.4);
+ spawn.randomMob(1250, 1575, 0.3);
+ spawn.randomMob(1075, -100, 0.3);
+ spawn.randomMob(2450, -100, 0.2);
+ spawn.randomGroup(1350, -775, 1);
+ if (simulation.difficulty > 1) spawn.randomLevelBoss(1491, 495);
+ }
+ spawn.randomMob(2650, -750, 0.4);
+ spawn.randomMob(300, -1725, 0.4);
+ spawn.randomMob(750, -1775, 0.4);
+ spawn.randomMob(550, -2225, 0.4);
+ spawn.randomMob(2700, -475, 0.4);
+ spawn.randomMob(2375, -200, 0.2);
+ spawn.randomMob(3350, -225, 0.3);
+
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ sewers() {
+ const button1 = level.button(6600, 2675)
+ // const hazard = level.hazard(4550, 2750, 4550, 150)
+ const hazard = level.hazard(simulation.isHorizontalFlipped ? -4550 - 4550 : 4550, 2750, 4550, 150)
+ let balance1, balance2, balance3, balance4, rotor
+
+ const drip1 = level.drip(6100, 1900, 2900, 100) // drip(x, yMin, yMax, period = 100, color = "hsla(160, 100%, 35%, 0.5)") {
+ const drip2 = level.drip(7300, 1900, 2900, 150)
+ const drip3 = level.drip(8750, 1900, 2900, 70)
+ level.custom = () => {
+ drip1.draw();
+ drip2.draw();
+ drip3.draw();
+ button1.query();
+ button1.draw();
+ ctx.fillStyle = "hsl(175, 15%, 76%)"
+ ctx.fillRect(9100, 2200, 800, 400)
+ ctx.fillStyle = "rgba(0,0,0,0.03)" //shadows
+ ctx.fillRect(6250, 2025, 700, 650)
+ ctx.fillRect(8000, 2025, 600, 575)
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ rotor.rotate();
+
+ ctx.fillStyle = "#233"
+ ctx.beginPath();
+ ctx.arc(balance1.center.x, balance1.center.y, 9, 0, 2 * Math.PI);
+ ctx.moveTo(balance2.center.x, balance2.center.y)
+ ctx.arc(balance2.center.x, balance2.center.y, 9, 0, 2 * Math.PI);
+ ctx.moveTo(balance3.center.x, balance3.center.y)
+ ctx.arc(balance3.center.x, balance3.center.y, 9, 0, 2 * Math.PI);
+ ctx.moveTo(balance4.center.x, balance4.center.y)
+ ctx.arc(balance4.center.x, balance4.center.y, 9, 0, 2 * Math.PI);
+ ctx.moveTo(balance5.center.x, balance5.center.y)
+ ctx.arc(balance5.center.x, balance5.center.y, 9, 0, 2 * Math.PI);
+ ctx.moveTo(rotor.center.x, rotor.center.y)
+ ctx.arc(rotor.center.x, rotor.center.y, 9, 0, 2 * Math.PI);
+ ctx.fill();
+ hazard.query();
+ hazard.level(button1.isUp)
+ };
+
+ level.setPosToSpawn(0, -50); //normal spawn
+
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.x = 9700;
+ level.exit.y = 2560;
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "hsl(138, 3%, 74%)";
+ color.map = "#3d4240"
+ powerUps.spawnStartingPowerUps(3475, 1775);
+ spawn.debris(4575, 2550, 1600, 9); //16 debris per level
+ spawn.debris(7000, 2550, 2000, 7); //16 debris per level
+
+ spawn.mapRect(-500, -600, 200, 800); //left entrance wall
+ spawn.mapRect(-400, -600, 3550, 200); //ceiling
+ spawn.mapRect(-400, 0, 3000, 200); //floor
+ // spawn.mapRect(300, -500, 50, 400); //right entrance wall
+ // spawn.bodyRect(312, -100, 25, 100);
+ spawn.bodyRect(1450, -300, 150, 50);
+
+ const xPos = shuffle([600, 1250, 2000]);
+ spawn.mapRect(xPos[0], -200, 300, 100);
+ spawn.mapRect(xPos[1], -250, 300, 300);
+ spawn.mapRect(xPos[2], -150, 300, 200);
+
+ spawn.bodyRect(3100, 410, 75, 100);
+ spawn.bodyRect(2450, -25, 250, 25);
+
+ spawn.mapRect(3050, -600, 200, 800); //right down tube wall
+ spawn.mapRect(3100, 0, 1200, 200); //tube right exit ceiling
+ spawn.mapRect(4200, 0, 200, 1900);
+ spawn.mapVertex(3500, 1000, "-500 -500 -400 -600 400 -600 500 -500 500 500 400 600 -400 600 -500 500");
+ spawn.mapVertex(3600, 1940, "-400 -40 -350 -90 350 -90 400 -40 400 40 350 90 -350 90 -400 40");
+ spawn.mapRect(3925, 2288, 310, 50);
+ spawn.mapRect(3980, 2276, 200, 50);
+
+ spawn.mapRect(2625, 2288, 650, 50);
+ spawn.mapRect(2700, 2276, 500, 50);
+
+ spawn.mapRect(2400, 0, 200, 1925); //left down tube wall
+ spawn.mapRect(600, 2300, 3750, 200);
+ spawn.bodyRect(3800, 275, 125, 125);
+
+ spawn.mapRect(4200, 1700, 5000, 200);
+ spawn.mapRect(4150, 2300, 200, 400);
+
+ spawn.mapRect(600, 1700, 2000, 200); //bottom left room ceiling
+ spawn.mapRect(500, 1700, 200, 800); //left wall
+ spawn.mapRect(675, 1875, 325, 150, 0.5);
+
+ spawn.mapRect(4450, 2900, 4900, 200); //boss room floor
+ spawn.mapRect(4150, 2600, 400, 500);
+ spawn.mapRect(6250, 2675, 700, 325);
+ spawn.mapRect(8000, 2600, 600, 400);
+ spawn.bodyRect(5875, 2725, 200, 200);
+ spawn.bodyRect(6800, 2490, 50, 50);
+ spawn.bodyRect(6800, 2540, 50, 50);
+ spawn.bodyRect(6800, 2590, 50, 50);
+ spawn.bodyRect(8225, 2225, 100, 100);
+ spawn.mapRect(6250, 1875, 700, 150);
+ spawn.mapRect(8000, 1875, 600, 150);
+
+ spawn.mapRect(9100, 1700, 900, 500); //exit
+ spawn.mapRect(9100, 2600, 900, 500);
+ spawn.mapRect(9900, 1700, 200, 1400); //back wall
+ // spawn.mapRect(9300, 2150, 50, 250);
+ spawn.mapRect(9300, 2590, 650, 25);
+ spawn.mapRect(9700, 2580, 100, 50);
+
+
+ spawn.randomGroup(1300, 2100, 0.1);
+ spawn.randomMob(8300, 2100, 0.1);
+ spawn.randomSmallMob(2575, -75, 0.1); //entrance
+ spawn.randomMob(8125, 2450, 0.1);
+ spawn.randomSmallMob(3200, 250, 0.1);
+ spawn.randomMob(2425, 2150, 0.1);
+ spawn.randomSmallMob(3500, 250, 0.2);
+ spawn.randomMob(3800, 2175, 0.2);
+ spawn.randomSmallMob(2500, -275, 0.2); //entrance
+ spawn.randomMob(4450, 2500, 0.2);
+ spawn.randomMob(6350, 2525, 0.2);
+ spawn.randomGroup(9200, 2400, 0.3);
+ spawn.randomSmallMob(1900, -250, 0.3); //entrance
+ spawn.randomMob(1500, 2100, 0.4);
+ spawn.randomSmallMob(1700, -150, 0.4); //entrance
+ spawn.randomMob(8800, 2725, 0.5);
+ spawn.randomMob(7300, 2200, 0.5);
+ spawn.randomMob(2075, 2025, 0.5);
+ spawn.randomMob(3475, 2175, 0.5);
+ spawn.randomMob(8900, 2825, 0.5);
+ spawn.randomMob(9600, 2425, 0.9);
+ spawn.randomMob(3600, 1725, 0.9);
+ spawn.randomMob(4100, 1225, 0.9);
+ spawn.randomMob(2825, 400, 0.9);
+ if (simulation.difficulty > 1) spawn.randomLevelBoss(6000, 2300, ["dragonFlyBoss", "beetleBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "blinkBoss", "streamBoss", "historyBoss", "orbitalBoss", "grenadierBoss", "blockBoss", "revolutionBoss", "slashBoss"]);
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ spawn.secondaryBossChance(7725, 2275)
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+ // rotor(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0, rotationForce = 0.0005) {
+ // rotor = level.rotor(-5100, 2475, 0.001) //rotates other direction because flipped
+ rotor = level.rotor(-5600, 2390, 850, 50, 0.001, 0, 0.01, 0, 0.001) //balance(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0, rotationForce = 0.0005) {
+ balance1 = level.rotor(-300 - 25, -395, 25, 390, 0.001) //entrance
+ balance2 = level.rotor(-2605 - 390, 500, 390, 25, 0.001) //falling
+ balance3 = level.rotor(-2608 - 584, 1900, 584, 25, 0.001) //falling
+ balance4 = level.rotor(-9300 - 25, 2205, 25, 380, 0.001) //exit
+ balance5 = level.rotor(-2605 - 390, 1100, 390, 25, 0.001) //falling
+ // boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100
+ // boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100
+ // level.setPosToSpawn(300, -700); //-x // no need since 0
+ button1.min.x = -button1.min.x - 126 // flip the button horizontally
+ button1.max.x = -button1.max.x + 126 // flip the button horizontally
+ drip1.x *= -1
+ drip2.x *= -1
+ drip3.x *= -1
+ level.custom = () => {
+ drip1.draw();
+ drip2.draw();
+ drip3.draw();
+
+ button1.query();
+ button1.draw();
+ rotor.rotate();
+
+ ctx.fillStyle = "hsl(175, 15%, 76%)"
+ ctx.fillRect(-9900, 2200, 800, 400)
+ ctx.fillStyle = "rgba(0,0,0,0.03)" //shadows
+ ctx.fillRect(-6950, 2025, 700, 650)
+ ctx.fillRect(-8600, 2025, 600, 575)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ // level.customTopLayer = () => {};
+ } else {
+ // rotor = level.rotor(5100, 2475, -0.001)
+ rotor = level.rotor(4700, 2390, 850, 50, 0.001, 0, 0.01, 0, -0.001) //balance(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0, rotationForce = 0.0005) {
+ balance1 = level.rotor(300, -395, 25, 390, 0.001) //entrance
+ balance2 = level.rotor(2605, 500, 390, 25, 0.001) //falling
+ balance3 = level.rotor(2608, 1900, 584, 25, 0.001) //falling
+ balance4 = level.rotor(9300, 2205, 25, 380, 0.001) //exit
+ balance5 = level.rotor(2605, 1100, 390, 25, 0.001) //falling
+ }
+
+ },
+ satellite() {
+ const boost1 = level.boost(5825, 235, 1400)
+ const elevator = level.elevator(4210, -1265, 380, 50, -3450) //, 0.003, { up: 0.01, down: 0.2 }
+ level.custom = () => {
+ boost1.query();
+
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(-250, -750, 420, 450)
+ ctx.fillStyle = "#d0d4d6"
+ ctx.fillRect(-300, -1900, 500, 1100)
+ ctx.fillRect(900, -2450, 450, 2050)
+ ctx.fillRect(2000, -2800, 450, 2500)
+ ctx.fillRect(3125, -3100, 450, 3300)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,20,40,0.25)"
+ ctx.fillRect(-250, -400, 1800, 775)
+ ctx.fillRect(1800, -275, 850, 775)
+ ctx.fillRect(5200, 125, 450, 200)
+ ctx.fillStyle = "rgba(0,20,40,0.1)"
+ ctx.fillRect(4000, -1200, 1050, 1500)
+ ctx.fillRect(4100, -3450, 600, 2250)
+ elevator.move()
+ };
+
+ level.setPosToSpawn(-100, 210); //normal spawn
+ spawn.mapRect(-150, 240, 100, 30);
+ level.exit.x = -100;
+ level.exit.y = -425;
+ spawn.mapRect(level.exit.x, level.exit.y + 15, 100, 50); //exit bump
+
+ level.defaultZoom = 1700 // 4500 // 1400
+ simulation.zoomTransition(level.defaultZoom)
+
+ powerUps.spawnStartingPowerUps(4900, -500); //1 per level
+ spawn.debris(1000, 20, 1800, 3); //16 debris per level //but less here because a few mobs die from laser
+ spawn.debris(4830, -1330, 850, 3); //16 debris per level
+ spawn.debris(3035, -3900, 1500, 3); //16 debris per level
+
+ document.body.style.backgroundColor = "#dbdcde";
+
+ //spawn start building
+ spawn.mapRect(-350, -800, 100, 1100);
+ // spawn.mapRect(-300, -10, 500, 50);
+ spawn.mapRect(150, -510, 50, 365);
+ spawn.bodyRect(170, -140, 20, 163, 1, spawn.propsFriction); //door to starting room
+ spawn.mapVertex(175, 200, "625 0 300 0 425 -300 500 -300"); //entrance ramp
+ // spawn.mapRect(-300, 0, 1000, 300); //ground
+ spawn.mapRect(-350, 250, 6350, 300); //deeper ground
+ spawn.bodyRect(2100, 50, 80, 80);
+ spawn.bodyRect(2000, 50, 60, 60);
+ // spawn.bodyRect(1650, 50, 300, 200);
+ // spawn.mapRect(1800, Math.floor(Math.random() * 200), 850, 300); //stops above body from moving to right
+ spawn.mapVertex(2225, 250, "575 0 -575 0 -450 -100 450 -100"); //base
+
+ //exit building
+ // spawn.mapRect(-100, -410, 100, 30);
+ spawn.mapRect(-350, -850, 550, 100);
+ spawn.mapRect(150, -800, 50, 110);
+ spawn.bodyRect(170, -690, 14, 180, 1, spawn.propsFriction); //door to exit room
+ spawn.mapRect(-300, -400, 500, 150); //far left starting ceiling
+
+ //tall platform above exit
+ spawn.mapRect(-500, -1900, 400, 50); //super high shade
+ spawn.mapRect(0, -1900, 400, 50); //super high shade
+ spawn.mapRect(-150, -1350, 200, 25); //super high shade
+ spawn.bodyRect(140, -2100, 150, 200); //shield from laser
+
+ //tall platform
+ spawn.mapVertex(1125, -450, "325 0 250 80 -250 80 -325 0 -250 -80 250 -80"); //base
+ spawn.mapRect(150, -500, 1410, 100); //far left starting ceiling
+ spawn.mapRect(625, -2450, 1000, 50); //super high shade
+ spawn.bodyRect(1300, -3600, 150, 150); //shield from laser
+ //tall platform
+ spawn.mapVertex(2225, -250, "325 0 250 80 -250 80 -325 0 -250 -80 250 -80"); //base
+ spawn.mapRect(1725, -2800, 1000, 50); //super high shade
+ spawn.mapRect(1790, -300, 870, 100); //far left starting ceiling
+ spawn.bodyRect(2400, -2950, 150, 150); //shield from laser
+
+ //tall platform
+ spawn.mapVertex(3350, 175, "425 0 -425 0 -275 -300 275 -300"); //base
+ spawn.bodyRect(3350, -150, 200, 120);
+ spawn.mapRect(2850, -3150, 1000, 50); //super high shade
+ spawn.bodyRect(3675, -3470, 525, 20); //plank
+ spawn.bodyRect(3600, -3450, 200, 300); //plank support block
+
+ //far right structure
+ spawn.mapRect(5200, -725, 100, 870);
+ spawn.mapRect(5300, -1075, 350, 1220);
+
+ //structure bellow tall stairs
+ spawn.mapRect(3900, -300, 450, 50);
+ spawn.mapRect(4675, -375, 450, 50);
+
+ // spawn.mapRect(4000, -1300, 1050, 100);
+ spawn.mapRect(4000, -1300, 200, 100);
+ spawn.mapRect(4600, -1300, 450, 100);
+
+ //steep stairs
+ spawn.mapRect(4100, -2250, 100, 650);
+ spawn.mapRect(4100, -3450, 100, 850); //left top shelf
+ spawn.mapRect(4600, -3450, 100, 1850);
+
+ spawn.randomSmallMob(4400, -3500);
+ spawn.randomSmallMob(4800, -800);
+ spawn.randomMob(800, -2600);
+ spawn.randomMob(700, -600, 0.3);
+ spawn.randomMob(3100, -3600, 0.3);
+ spawn.randomMob(3300, -1000, 0.3);
+ spawn.randomMob(4200, -250, 0.3);
+ spawn.randomMob(4900, -1500, 0.3);
+ spawn.randomMob(3800, 175, 0.4);
+ spawn.randomMob(5750, 125, 0.4);
+ spawn.randomMob(5900, -1500, 0.4);
+ spawn.randomMob(4700, -800, 0.4);
+ spawn.randomMob(1400, 200, 0.3);
+ spawn.randomMob(2850, 175, 0.4);
+ spawn.randomMob(2000, -2800, 0.4);
+ spawn.randomMob(2400, -400, 0.4);
+ spawn.randomMob(4475, -3550, 0.3);
+ spawn.randomGroup(5000, -2150, 1);
+ spawn.randomGroup(3700, -4100, 0.3);
+ spawn.randomGroup(2700, -1600, 0.1);
+ spawn.randomGroup(1600, -100, 0);
+ spawn.randomGroup(5000, -3900, -0.3);
+ if (simulation.difficulty > 1) {
+ if (Math.random() < 0.25) {
+ spawn.randomLevelBoss(2800, -1400);
+ } else if (Math.random() < 0.25) {
+ spawn.laserBoss(2900 + 300 * Math.random(), -2950 + 150 * Math.random());
+ } else if (Math.random() < 0.33) {
+ spawn.laserBoss(1800 + 250 * Math.random(), -2600 + 150 * Math.random());
+ } else if (Math.random() < 0.5) {
+ spawn.laserBoss(3500 + 250 * Math.random(), -2600 + 1000 * Math.random());
+ } else {
+ spawn.laserBoss(600 + 200 * Math.random(), -2150 + 250 * Math.random());
+ }
+ }
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ spawn.secondaryBossChance(3950, -850)
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+ boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100
+ boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100
+ level.setPosToSpawn(100, 210); //-x
+ elevator.holdX = -elevator.holdX // flip the elevator horizontally
+ level.custom = () => {
+ boost1.query();
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(250 - 420, -750, 420, 450)
+ ctx.fillStyle = "#d0d4d6"
+ ctx.fillRect(300 - 500, -1900, 500, 1100)
+ ctx.fillRect(-900 - 450, -2450, 450, 2050)
+ ctx.fillRect(-2000 - 450, -2800, 450, 2500)
+ ctx.fillRect(-3125 - 450, -3100, 450, 3300)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ elevator.move()
+ ctx.fillStyle = "rgba(0,20,40,0.25)"
+ ctx.fillRect(250 - 1800, -400, 1800, 775)
+ ctx.fillRect(-1800 - 850, -275, 850, 775)
+ ctx.fillRect(-5200 - 450, 125, 450, 200)
+ ctx.fillStyle = "rgba(0,20,40,0.1)"
+ ctx.fillRect(-4000 - 1050, -1200, 1050, 1500)
+ ctx.fillRect(-4100 - 600, -3450, 600, 2250)
+ };
+ }
+ },
+ rooftops() {
+ const elevator = level.elevator(1450, -990, 235, 45, -2000)
+ const boost1 = level.boost(4950, 0, 1100)
+
+ level.custom = () => {
+ boost1.query();
+ elevator.move();
+ elevator.drawTrack();
+
+ ctx.fillStyle = "#d4f4f4"
+ if (isBackwards) {
+ ctx.fillRect(-650, -2300, 440, 300)
+ } else {
+ ctx.fillRect(3460, -700, 1090, 800)
+ }
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(710, -2225, 580, 225)
+ ctx.fillRect(3510, -1550, 330, 300)
+ ctx.fillRect(1735, -900, 1515, 1900)
+ ctx.fillRect(1735, -1550, 1405, 550)
+ ctx.fillRect(1860, -1950, 630, 350)
+ ctx.fillRect(-700, -1950, 2100, 2950)
+ ctx.fillRect(3400, 100, 2150, 900)
+ ctx.fillRect(4550, -725, 900, 725)
+ ctx.fillRect(3460, -1250, 1080, 550)
+ if (isBackwards) {
+ ctx.fillRect(3460, -700, 1090, 800)
+ } else {
+ ctx.fillRect(-650, -2300, 440, 300)
+ }
+ };
+
+ level.defaultZoom = 1700
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#dcdcde";
+
+ let isBackwards = false
+ if (Math.random() < 0.75) {
+ //normal direction start in top left
+ level.setPosToSpawn(-450, -2060);
+ level.exit.x = 3600;
+ level.exit.y = -300;
+ spawn.mapRect(3600, -285, 100, 50); //ground bump wall
+ //mobs that spawn in exit room
+ spawn.bodyRect(4850, -750, 300, 25, 0.6); //
+ spawn.randomSmallMob(4100, -100);
+ spawn.randomSmallMob(4600, -100);
+ spawn.randomMob(3765, -450, 0.3);
+ } else {
+ isBackwards = true
+ //reverse direction, start in bottom right
+ level.setPosToSpawn(3650, -325);
+ level.exit.x = -550;
+ level.exit.y = -2030;
+ spawn.mapRect(-550, -2015, 100, 50); //ground bump wall
+ }
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+
+ spawn.debris(1650, -1800, 3800, 16); //16 debris per level
+ powerUps.spawnStartingPowerUps(2450, -1675);
+
+ //spawn.mapRect(-700, 0, 6250, 100); //ground
+ spawn.mapRect(3400, 0, 2150, 100); //ground
+ spawn.mapRect(-700, -2000, 2125, 50); //Top left ledge
+ spawn.bodyRect(1300, -2125, 50, 125, 0.8);
+ spawn.bodyRect(1307, -2225, 50, 100, 0.8);
+ spawn.mapRect(-700, -2350, 50, 400); //far left starting left wall
+ spawn.mapRect(-700, -2010, 500, 50); //far left starting ground
+ spawn.mapRect(-700, -2350, 500, 50); //far left starting ceiling
+ spawn.mapRect(-250, -2350, 50, 200); //far left starting right part of wall
+ spawn.bodyRect(-240, -2150, 30, 36); //door to starting room
+ spawn.bodyRect(-240, -2115, 30, 36); //door to starting room
+ spawn.bodyRect(-240, -2080, 30, 35); //door to starting room
+ spawn.bodyRect(-240, -2045, 30, 35); //door to starting room
+ spawn.mapRect(1850, -2000, 650, 50);
+ spawn.bodyRect(200, -2150, 80, 220, 0.8);
+ spawn.mapRect(700, -2275, 600, 50);
+ spawn.mapRect(1000, -1350, 410, 50);
+ spawn.bodyRect(1050, -2350, 30, 30, 0.8);
+ // spawn.bodyRect(1625, -1100, 100, 75);
+ // spawn.bodyRect(1350, -1025, 400, 25); // ground plank
+ spawn.mapRect(-725, -1000, 2150, 100); //lower left ledge
+ spawn.bodyRect(350, -1100, 200, 100, 0.8);
+ spawn.bodyRect(370, -1200, 100, 100, 0.8);
+ spawn.bodyRect(360, -1300, 100, 100, 0.8);
+ spawn.bodyRect(950, -1050, 300, 50, 0.8);
+ spawn.bodyRect(-575, -1150, 125, 150, 0.8);
+ spawn.mapRect(1710, -1000, 1565, 100); //middle ledge
+ spawn.mapRect(3400, -1000, 75, 25);
+ spawn.bodyRect(2600, -1950, 100, 250, 0.8);
+ spawn.bodyRect(2700, -1125, 125, 125, 0.8);
+ spawn.bodyRect(2710, -1250, 125, 125, 0.8);
+ spawn.bodyRect(2705, -1350, 75, 100, 0.8);
+ spawn.mapRect(3500, -1600, 350, 50);
+ spawn.mapRect(1725, -1600, 1435, 50);
+ spawn.bodyRect(3100, -1015, 375, 15);
+ spawn.bodyRect(3500, -850, 75, 125, 0.8);
+ spawn.mapRect(3450, -1000, 50, 580); //left building wall
+ spawn.bodyRect(3460, -420, 30, 144);
+ spawn.mapRect(5450, -775, 100, 875); //right building wall
+ spawn.bodyRect(3925, -1400, 100, 150, 0.8);
+ spawn.mapRect(3450, -1250, 1090, 50);
+ // spawn.mapRect(3450, -1225, 50, 75);
+ spawn.mapRect(4500, -1250, 50, 415);
+ spawn.mapRect(3450, -725, 1500, 50);
+ spawn.mapRect(5100, -725, 400, 50);
+ spawn.mapRect(4500, -735, 50, 635);
+ spawn.bodyRect(4500, -100, 50, 100);
+ spawn.mapRect(4500, -885, 100, 50);
+ spawn.spawnStairs(3800, 0, 3, 150, 206); //stairs top exit
+ spawn.mapRect(3400, -275, 450, 275); //exit platform
+
+ spawn.randomSmallMob(2200, -1775);
+ spawn.randomSmallMob(4000, -825);
+ spawn.randomSmallMob(-350, -3400);
+ spawn.randomMob(4250, -1350, 0.8);
+ spawn.randomMob(2550, -1350, 0.8);
+ spawn.randomMob(1875, -1075, 0.3);
+ spawn.randomMob(1120, -1200, 0.3);
+ spawn.randomMob(3000, -1150, 0.2);
+ spawn.randomMob(3200, -1150, 0.3);
+ spawn.randomMob(3300, -1750, 0.3);
+ spawn.randomMob(3650, -1350, 0.3);
+ spawn.randomMob(3600, -1800, 0.1);
+ spawn.randomMob(5200, -100, 0.3);
+ spawn.randomMob(5275, -900, 0.2);
+ spawn.randomMob(0, -1075, 0.3);
+ spawn.randomGroup(600, -1575, 0);
+ spawn.randomGroup(2225, -1325, 0.4);
+ spawn.randomGroup(4900, -1200, 0);
+ if (simulation.difficulty > 1) spawn.randomLevelBoss(3200, -1900);
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ spawn.secondaryBossChance(2175, -2425)
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+
+ boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100
+ boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100
+ elevator.holdX = -elevator.holdX // flip the elevator horizontally
+
+ if (isBackwards) {
+ level.setPosToSpawn(-3650, -325); //-x
+ } else {
+ level.setPosToSpawn(450, -2060); //-x
+ }
+ level.custom = () => {
+ boost1.query();
+ elevator.move();
+ elevator.drawTrack();
+
+ ctx.fillStyle = "#d4f4f4"
+ if (isBackwards) {
+ ctx.fillRect(650 - 440, -2300, 440, 300)
+ } else {
+ ctx.fillRect(-3460 - 1090, -700, 1090, 800)
+ }
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(-710 - 580, -2225, 580, 225)
+ ctx.fillRect(-3510 - 330, -1550, 330, 300)
+ ctx.fillRect(-1735 - 1515, -900, 1515, 1900)
+ ctx.fillRect(-1735 - 1405, -1550, 1405, 550)
+ ctx.fillRect(-1860 - 630, -1950, 630, 350)
+ ctx.fillRect(700 - 2100, -1950, 2100, 2950)
+ ctx.fillRect(-3400 - 2150, 100, 2150, 900)
+ ctx.fillRect(-4550 - 900, -725, 900, 725)
+ ctx.fillRect(-3460 - 1080, -1250, 1080, 550)
+ if (isBackwards) {
+ ctx.fillRect(-3460 - 1090, -700, 1090, 800)
+ } else {
+ ctx.fillRect(650 - 440, -2300, 440, 300)
+ }
+ };
+ }
+ },
+ aerie() {
+ const boost1 = level.boost(-425, 100, 1400)
+ const boost2 = level.boost(5350, 275, 2850);
+
+ level.custom = () => {
+ boost1.query();
+ boost2.query();
+ if (backwards) {
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(-275, -1275, 425, 300)
+ } else {
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(3750, -3650, 550, 400)
+ }
+ ctx.fillStyle = "#c7c7ca"
+ ctx.fillRect(4200, -2200, 100, 2600)
+ // ctx.fillStyle = "#c7c7ca"
+ ctx.fillRect(-100, -1000, 1450, 1400)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ if (backwards) {
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(3750, -3650, 550, 400)
+ } else {
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(-275, -1275, 425, 300)
+ }
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(3700, -3150, 1100, 950)
+ ctx.fillRect(2000, -1110, 450, 1550)
+
+ ctx.fillStyle = "rgba(0,0,0,0.04)"
+ ctx.beginPath()
+ ctx.moveTo(-100, -900)
+ ctx.lineTo(300, -900)
+ ctx.lineTo(150, 100)
+ ctx.lineTo(-100, 100)
+
+ ctx.moveTo(600, -900)
+ ctx.lineTo(1350, -900)
+ ctx.lineTo(1350, 100)
+ ctx.lineTo(750, 100)
+ ctx.fill()
+ };
+
+ // simulation.difficulty = 4; //for testing to simulate possible mobs spawns
+ level.defaultZoom = 2100
+ simulation.zoomTransition(level.defaultZoom)
+
+ const backwards = (Math.random() < 0.25 && simulation.difficulty > 8) ? true : false;
+ if (backwards) {
+ level.setPosToSpawn(4000, -3300); //normal spawn
+ level.exit.x = -100;
+ level.exit.y = -1025;
+ } else {
+ level.setPosToSpawn(-50, -1050); //normal spawn
+ level.exit.x = 3950;
+ level.exit.y = -3275;
+ }
+
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ spawn.mapRect(level.exit.x, level.exit.y + 15, 100, 20);
+
+ powerUps.spawnStartingPowerUps(1075, -550);
+ document.body.style.backgroundColor = "#dcdcde";
+
+ // starting room
+ spawn.mapRect(-300, -1000, 600, 100);
+ spawn.mapRect(-300, -1300, 450, 50);
+ spawn.mapRect(-300, -1300, 50, 350);
+ if (!backwards) spawn.bodyRect(100, -1250, 200, 240); //remove on backwards
+ //left building
+ spawn.mapRect(-100, -975, 100, 975);
+ spawn.mapRect(-500, 100, 1950, 400);
+ spawn.mapRect(600, -1000, 750, 100);
+ spawn.mapRect(900, -500, 550, 100);
+ spawn.mapRect(1250, -975, 100, 375);
+ spawn.bodyRect(1250, -600, 100, 100, 0.7);
+ spawn.mapRect(1250, -450, 100, 450);
+ spawn.bodyRect(1250, -1225, 100, 200, 0.7); //remove on backwards
+ spawn.bodyRect(1200, -1025, 350, 35); //remove on backwards
+ //middle super tower
+ if (backwards) {
+ spawn.bodyRect(2000, -800, 700, 35);
+ } else {
+ spawn.bodyRect(1750, -800, 700, 35);
+ }
+ spawn.mapVertex(2225, -2100, "0 0 450 0 300 -2500 150 -2500")
+ spawn.mapRect(2000, -700, 450, 300);
+ spawn.bodyRect(2360, -450, 100, 300, 0.6);
+ spawn.mapRect(2000, -75, 450, 275);
+ spawn.bodyRect(2450, 150, 150, 150, 0.4);
+ spawn.mapRect(1550, 300, 4600, 200); //ground
+ // spawn.mapRect(6050, -700, 450, 1200);
+ spawn.mapRect(6050, -1060, 450, 1560);
+ spawn.mapVertex(6275, -2100, "0 0 450 0 300 -2500 150 -2500")
+
+ //right tall tower
+ spawn.mapRect(3700, -3200, 100, 800);
+ spawn.mapRect(4700, -2910, 100, 510);
+ spawn.mapRect(3700, -2600, 300, 50);
+ spawn.mapRect(4100, -2900, 900, 50);
+ spawn.mapRect(3450, -2300, 750, 100);
+ spawn.mapRect(4300, -2300, 750, 100);
+ spawn.mapRect(4150, -1600, 200, 25);
+ spawn.mapRect(4150, -700, 200, 25);
+ //exit room on top of tower
+ spawn.mapRect(3700, -3700, 600, 50);
+ spawn.mapRect(3700, -3700, 50, 500);
+ spawn.mapRect(4250, -3700, 50, 300);
+ spawn.mapRect(3700, -3250, 1100, 100);
+
+ spawn.randomGroup(350, -500, 1)
+ spawn.randomSmallMob(-225, 25);
+ spawn.randomSmallMob(2100, -900);
+
+ spawn.randomSmallMob(4000, -250);
+ spawn.randomSmallMob(4450, -3000);
+ spawn.randomSmallMob(5600, 100);
+ spawn.randomMob(4275, -2600, 0.8);
+ spawn.randomMob(1050, -700, 0.8)
+ spawn.randomMob(6050, -850, 0.7);
+ spawn.randomMob(2150, -300, 0.6)
+ spawn.randomMob(3900, -2700, 0.8);
+ spawn.randomMob(3600, -500, 0.8);
+ spawn.randomMob(3400, -200, 0.8);
+ // spawn.randomMob(1650, -1300, 0.7)
+ spawn.randomMob(425, 0, 0.7);
+ spawn.randomMob(4100, -50, 0.7);
+ spawn.randomMob(4100, -50, 0.5);
+ spawn.randomMob(1700, -50, 0.3)
+ spawn.randomMob(2350, -900, 0.3)
+ spawn.randomMob(4700, -150, 0.2);
+ spawn.randomGroup(4000, -350, 0.6);
+ spawn.randomGroup(2750, -550, 0.1);
+ spawn.randomMob(2175, -925, 0.5);
+ spawn.randomMob(2750, 100, 0.5);
+ spawn.randomMob(4250, -1725, 0.5);
+ spawn.randomMob(3575, -2425, 0.5);
+ spawn.randomMob(3975, -3900, 0.5);
+ spawn.randomMob(1725, 125, 0.5);
+ if (simulation.difficulty > 1) {
+ if (Math.random() < 0.5) {
+ spawn.randomLevelBoss(4250, -250);
+ spawn.debris(-250, 50, 1650, 2); //16 debris per level
+ spawn.debris(2475, 0, 750, 2); //16 debris per level
+ spawn.debris(3450, 0, 2000, 16); //16 debris per level
+ spawn.debris(3500, -2350, 1500, 2); //16 debris per level
+ } else {
+ powerUps.chooseRandomPowerUp(4000, 200);
+ powerUps.chooseRandomPowerUp(4000, 200);
+ //floor below right tall tower
+ spawn.bodyRect(3000, 50, 150, 250, 0.9);
+ spawn.bodyRect(4500, -500, 300, 250, 0.7);
+ spawn.bodyRect(3500, -100, 100, 150, 0.7);
+ spawn.bodyRect(4200, -500, 110, 30, 0.7);
+ spawn.bodyRect(3800, -500, 150, 130, 0.7);
+ spawn.bodyRect(4000, 50, 200, 150, 0.9);
+ spawn.bodyRect(4500, 50, 300, 200, 0.9);
+ spawn.bodyRect(4200, -350, 200, 50, 0.9);
+ spawn.bodyRect(4700, -350, 50, 200, 0.9);
+ spawn.bodyRect(4900, -100, 300, 300, 0.7);
+ spawn.suckerBoss(4500, -400);
+ }
+ }
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ spawn.secondaryBossChance(5350, -325)
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+
+ boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100
+ boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100
+ boost2.boostBounds.min.x = -boost2.boostBounds.min.x - 100
+ boost2.boostBounds.max.x = -boost2.boostBounds.max.x + 100
+
+
+ if (backwards) {
+ level.setPosToSpawn(-4000, -3300); //-x
+ } else {
+ level.setPosToSpawn(50, -1050); //-x
+ }
+ level.custom = () => {
+ boost1.query();
+ boost2.query();
+ if (backwards) {
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(275 - 425, -1275, 425, 300)
+ } else {
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(-3750 - 550, -3650, 550, 400)
+ }
+ ctx.fillStyle = "#c7c7ca"
+ ctx.fillRect(-4200 - 100, -2200, 100, 2600)
+ // ctx.fillStyle = "#c7c7ca"
+ ctx.fillRect(100 - 1450, -1000, 1450, 1400)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ if (backwards) {
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(-3750 - 550, -3650, 550, 400)
+ } else {
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(275 - 425, -1275, 425, 300)
+ }
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(-3700 - 1100, -3150, 1100, 950)
+ ctx.fillRect(-2000 - 450, -1110, 450, 1550)
+ ctx.fillStyle = "rgba(0,0,0,0.04)"
+ ctx.beginPath()
+ ctx.moveTo(100, -900)
+ ctx.lineTo(-300, -900)
+ ctx.lineTo(-150, 100)
+ ctx.lineTo(100, 100)
+ ctx.moveTo(-600, -900)
+ ctx.lineTo(-1350, -900)
+ ctx.lineTo(-1350, 100)
+ ctx.lineTo(-750, 100)
+ ctx.fill()
+ };
+ }
+ },
+ skyscrapers() {
+ const boost1 = level.boost(475, 0, 1300)
+ const boost2 = level.boost(4450, 0, 1300);
+ level.custom = () => {
+ boost1.query();
+ boost2.query();
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(1350, -2100, 400, 250)
+ ctx.fillStyle = "#d4d4d7"
+ ctx.fillRect(3350, -1300, 50, 1325)
+ ctx.fillRect(1300, -1800, 750, 1800)
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(2500, -1100, 450, 250)
+ ctx.fillRect(2400, -550, 600, 150)
+ ctx.fillRect(2550, -1650, 250, 200)
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+ ctx.fillRect(700, -110, 400, 110)
+ ctx.fillRect(3800, -110, 400, 110)
+ ctx.fillStyle = "rgba(0,0,0,0.15)"
+ ctx.fillRect(-250, -300, 450, 300)
+ };
+ level.setPosToSpawn(-50, -60); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.x = 1500;
+ level.exit.y = -1875;
+ level.defaultZoom = 2000
+ simulation.zoomTransition(level.defaultZoom)
+ powerUps.spawnStartingPowerUps(1475, -1175);
+ spawn.debris(750, -2200, 3700, 16); //16 debris per level
+ document.body.style.backgroundColor = "#dcdcde";
+
+ spawn.mapRect(-300, 0, 5100, 300); //***********ground
+ spawn.mapRect(-300, -350, 50, 400); //far left starting left wall
+ spawn.mapRect(-300, -10, 500, 50); //far left starting ground
+ spawn.mapRect(-300, -350, 500, 50); //far left starting ceiling
+ spawn.mapRect(150, -350, 50, 200); //far left starting right part of wall
+ spawn.bodyRect(170, -130, 14, 140, 1, spawn.propsFriction); //door to starting room
+ spawn.mapRect(700, -1100, 400, 990); //far left building
+ spawn.mapRect(1600, -400, 1500, 500); //long center building
+ spawn.mapRect(1345, -1100, 250, 25); //left platform
+ spawn.mapRect(1755, -1100, 250, 25); //right platform
+ spawn.mapRect(1300, -1850, 800, 50); //left higher platform
+ spawn.mapRect(1300, -2150, 50, 350); //left higher platform left edge wall
+ spawn.mapRect(1300, -2150, 450, 50); //left higher platform roof
+ spawn.mapRect(1500, -1860, 100, 50); //ground bump wall
+ spawn.mapRect(2400, -850, 600, 300); //center floating large square
+ //spawn.bodyRect(2500, -1100, 25, 250); //wall before chasers
+ spawn.mapRect(2500, -1450, 450, 350); //higher center floating large square
+ spawn.mapRect(2500, -1675, 50, 300); //left wall on higher center floating large square
+ spawn.mapRect(2500, -1700, 300, 50); //roof on higher center floating large square
+ spawn.mapRect(3275, -750, 200, 25); //ledge by far right building
+ spawn.mapRect(3275, -1300, 200, 25); //higher ledge by far right building
+ spawn.mapRect(3800, -1100, 400, 990); //far right building
+
+ spawn.bodyRect(3200, -1375, 300, 25, 0.9);
+ spawn.bodyRect(1825, -1875, 400, 25, 0.9);
+ // spawn.bodyRect(1800, -575, 250, 150, 0.8);
+ spawn.bodyRect(1800, -600, 110, 150, 0.8);
+ spawn.bodyRect(2557, -450, 35, 55, 0.7);
+ spawn.bodyRect(2957, -450, 30, 15, 0.7);
+ spawn.bodyRect(2900, -450, 60, 45, 0.7);
+ spawn.bodyRect(915, -1200, 60, 100, 0.95);
+ spawn.bodyRect(925, -1300, 50, 100, 0.95);
+ if (Math.random() < 0.9) {
+ spawn.bodyRect(2300, -1720, 400, 20);
+ spawn.bodyRect(2590, -1780, 80, 80);
+ }
+ spawn.bodyRect(2925, -1100, 25, 250, 0.8);
+ spawn.bodyRect(3325, -1550, 50, 200, 0.3);
+ if (Math.random() < 0.8) {
+ spawn.bodyRect(1400, -75, 200, 75); //block to get up ledge from ground
+ spawn.bodyRect(1525, -125, 50, 50); //block to get up ledge from ground
+ }
+ spawn.bodyRect(1025, -1110, 400, 25, 0.9); //block on far left building
+ spawn.bodyRect(1425, -1110, 115, 25, 0.9); //block on far left building
+ spawn.bodyRect(1540, -1110, 300, 25, 0.9); //block on far left building
+
+ spawn.randomMob(-100, -1300, 0.5);
+ spawn.randomSmallMob(1850, -600);
+ spawn.randomSmallMob(3200, -100);
+ spawn.randomSmallMob(4450, -100);
+ spawn.randomSmallMob(2700, -475);
+ spawn.randomMob(2650, -975, 0.8);
+ spawn.randomMob(2650, -1550, 0.8);
+ spawn.randomMob(4150, -200, 0.15);
+ spawn.randomMob(1700, -1300, 0.2);
+ spawn.randomMob(1850, -1950, 0.25);
+ spawn.randomMob(2610, -1880, 0.25);
+ spawn.randomMob(3350, -950, 0.25);
+ spawn.randomMob(1690, -2250, 0.25);
+ spawn.randomMob(2200, -600, 0.2);
+ spawn.randomMob(850, -1300, 0.25);
+ spawn.randomMob(-100, -1700, -0.2);
+ spawn.randomGroup(3700, -1500, 0.4);
+ spawn.randomGroup(1700, -900, 0.4);
+ if (simulation.difficulty > 1) spawn.randomLevelBoss(2800 + 200 * Math.random(), -2200 + 200 * Math.random());
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ spawn.secondaryBossChance(4000, -1825)
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+ boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100
+ boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100
+ boost2.boostBounds.min.x = -boost2.boostBounds.min.x - 100
+ boost2.boostBounds.max.x = -boost2.boostBounds.max.x + 100
+
+ level.setPosToSpawn(50, -60); //-x
+ level.custom = () => {
+ boost1.query();
+ boost2.query();
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(-1350 - 400, -2100, 400, 250)
+ ctx.fillStyle = "#d4d4d7"
+ ctx.fillRect(-3350 - 50, -1300, 50, 1325)
+ ctx.fillRect(-1300 - 750, -1800, 750, 1800)
+
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(-2500 - 450, -1100, 450, 250)
+ ctx.fillRect(-2400 - 600, -550, 600, 150)
+ ctx.fillRect(-2550 - 250, -1650, 250, 200)
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+ ctx.fillRect(-700 - 400, -110, 400, 110)
+ ctx.fillRect(-3800 - 400, -110, 400, 110)
+ ctx.fillStyle = "rgba(0,0,0,0.15)"
+ ctx.fillRect(250 - 450, -300, 450, 300)
+ };
+ }
+ },
+ highrise() {
+ const elevator1 = level.elevator(-790, -190, 180, 25, -1150, 0.0025, {
+ up: 0.01,
+ down: 0.2
+ }, true) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
+ elevator1.addConstraint();
+ // const button1 = level.button(-500, -200)
+ const toggle1 = level.toggle(-300, -200) //(x,y,isOn,isLockOn = true/false)
+
+ const elevator2 = level.elevator(-3630, -970, 180, 25, -1740, 0.004) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
+ elevator2.addConstraint();
+ // const button2 = level.button(-3100, -1330)
+ const toggle2 = level.toggle(-3100, -1330) //(x,y,isOn, isLockOn = true/false)
+
+
+ level.custom = () => {
+ // ctx.fillStyle = "#d0d0d2"
+ // ctx.fillRect(-2475, -2450, 25, 750)
+ // ctx.fillRect(-2975, -2750, 25, 600)
+ // ctx.fillRect(-3375, -2875, 25, 725)
+ ctx.fillStyle = "#cff" //exit
+ ctx.fillRect(-4425, -3050, 425, 275)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ // button1.draw();
+ toggle1.query();
+ if (!toggle1.isOn) {
+ if (elevator1.isOn) {
+ elevator1.isOn = false
+ elevator1.frictionAir = 0.2
+ elevator1.addConstraint();
+ }
+ } else if (!elevator1.isOn) {
+ elevator1.isOn = true
+ elevator1.isUp = false
+ elevator1.removeConstraint();
+ elevator1.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2
+ }
+ if (elevator1.isOn) {
+ elevator1.move();
+ ctx.fillStyle = "#444"
+ } else {
+ ctx.fillStyle = "#aaa"
+ }
+ ctx.fillRect(-700, -1140, 1, 975)
+
+ toggle2.query();
+ // button2.draw();
+ if (!toggle2.isOn) {
+ if (elevator2.isOn) {
+ elevator2.isOn = false
+ elevator2.frictionAir = 0.2
+ elevator2.addConstraint();
+ }
+ } else if (!elevator2.isOn) {
+ elevator2.isOn = true
+ elevator2.isUp = false
+ elevator2.removeConstraint();
+ elevator2.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2
+ }
+
+ if (elevator2.isOn) {
+ elevator2.move();
+ ctx.fillStyle = "#444"
+ } else {
+ ctx.fillStyle = "#aaa"
+ }
+ ctx.fillRect(-3540, -1720, 1, 770)
+
+ ctx.fillStyle = "rgba(64,64,64,0.97)" //hidden section
+ ctx.fillRect(-4450, -750, 800, 200)
+ ctx.fillStyle = "rgba(0,0,0,0.12)"
+ ctx.fillRect(-2500, -1975, 150, 300);
+ ctx.fillRect(-1830, -1150, 2030, 1150)
+ ctx.fillRect(-3410, -2150, 495, 1550)
+ ctx.fillRect(-2585, -1675, 420, 1125)
+ ctx.fillRect(-1650, -1575, 750, 450)
+ };
+
+ level.setPosToSpawn(-300, -700); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.x = -4275;
+ level.exit.y = -2805;
+
+ level.defaultZoom = 1500
+ simulation.zoomTransition(level.defaultZoom)
+
+ powerUps.spawnStartingPowerUps(-2550, -700);
+ document.body.style.backgroundColor = "#dcdcde" //"#fafcff";
+
+ spawn.debris(-2325, -1825, 2400); //16 debris per level
+ spawn.debris(-2625, -600, 600, 5); //16 debris per level
+ spawn.debris(-2000, -60, 1200, 5); //16 debris per level
+
+ //3 platforms that lead to exit
+ // spawn.mapRect(-3440, -2875, 155, 25);
+ // spawn.mapRect(-3025, -2775, 125, 25);
+ // spawn.mapRect(-2525, -2475, 125, 25);
+ // spawn.bodyRect(-2600, -2500, 225, 20, 0.7);
+ // spawn.bodyRect(-3350, -2900, 25, 25, 0.5);
+ // spawn.bodyRect(-3400, -2950, 50, 75, 0.5);
+
+ powerUps.spawn(-4300, -700, "heal");
+ powerUps.spawn(-4200, -700, "ammo");
+ powerUps.spawn(-4000, -700, "ammo");
+ spawn.mapRect(-4450, -1000, 100, 500);
+ spawn.bodyRect(-3300, -750, 150, 150);
+
+ //building 1
+ spawn.bodyRect(-1000, -675, 25, 25);
+ spawn.mapRect(-2225, 0, 2475, 150);
+ spawn.mapRect(175, -1000, 75, 1100);
+ spawn.mapRect(-600, -1075, 50, 475);
+ spawn.mapRect(-600, -650, 625, 50);
+ spawn.mapRect(-1300, -650, 500, 50);
+ spawn.bodyRect(-75, -300, 50, 50);
+
+ spawn.mapRect(-600, -200, 500, 250); //ledge for boarding elevator
+ spawn.bodyRect(-500, -300, 100, 100, 0.6); //a nice block near the elevator
+
+ spawn.bodyRect(-425, -1375, 400, 225);
+ spawn.mapRect(-925, -1575, 50, 475);
+ spawn.bodyRect(-1475, -1275, 250, 125);
+
+ // spawn.mapRect(-1650, -1575, 600, 50);
+ // spawn.mapRect(-1875, -1575, 850, 50);
+ spawn.mapRect(-1675, -1575, 650, 50);
+ spawn.mapRect(-600, -1150, 850, 175);
+ spawn.mapRect(-1850, -1150, 1050, 175);
+ spawn.bodyRect(-1907, -1600, 550, 25);
+ if (simulation.difficulty < 4) {
+ spawn.bodyRect(-1600, -125, 125, 125);
+ spawn.bodyRect(-1560, -200, 75, 75);
+ } else {
+ spawn.bodyRect(-1200, -125, 125, 125);
+ spawn.bodyRect(-1160, -200, 75, 75);
+ }
+ //building 2
+ spawn.mapRect(-4450, -600, 2300, 750);
+ spawn.mapRect(-2225, -450, 175, 550);
+ // spawn.mapRect(-2600, -975, 450, 50);
+ spawn.mapRect(-3425, -1325, 525, 75);
+ spawn.mapRect(-3425, -2200, 525, 50);
+ spawn.mapRect(-2600, -1700, 450, 50);
+ // spawn.mapRect(-2600, -2450, 450, 50);
+ spawn.bodyRect(-2275, -2700, 50, 60);
+
+ // spawn.bodyRect(-2560, -1925, 250, 225);
+ // spawn.mapRect(-2525, -2025, 125, 25);
+ // spawn.mapRect(-2525, -1900, 125, 225);
+ // spawn.mapRect(-2600, -1975, 250, 25);
+ spawn.mapRect(-2515, -2000, 180, 50);
+
+ spawn.bodyRect(-3410, -1425, 50, 50);
+ spawn.bodyRect(-3390, -1525, 40, 60);
+ // spawn.bodyRect(-3245, -1425, 100, 100);
+ //building 3
+ spawn.mapRect(-4450, -1750, 800, 1050);
+ // spawn.mapRect(-3850, -2000, 125, 400);
+ spawn.mapRect(-4000, -2390, 200, 800);
+ // spawn.mapRect(-4450, -2650, 475, 1000);
+ spawn.mapRect(-4450, -2775, 475, 1125);
+ spawn.bodyRect(-3715, -2050, 50, 50);
+ // spawn.bodyRect(-3570, -1800, 50, 50);
+ spawn.bodyRect(-2970, -2250, 50, 50);
+ spawn.bodyRect(-3080, -2250, 40, 40);
+ spawn.bodyRect(-3420, -650, 50, 50);
+
+ //exit
+ spawn.mapRect(-4450, -3075, 25, 300);
+ spawn.mapRect(-4450, -3075, 450, 25);
+ spawn.mapRect(-4025, -3075, 25, 100);
+ spawn.mapRect(-4275, -2785, 100, 25);
+ spawn.bodyRect(-3900, -2400, 50, 50);
+
+ //mobs
+ spawn.randomMob(-2500, -2700, 1);
+ spawn.randomMob(-3200, -750, 1);
+ spawn.randomMob(-1875, -775, 0.2);
+ spawn.randomMob(-950, -1675, 0.2);
+ spawn.randomMob(-1525, -1750, 0.2);
+ spawn.randomMob(-1375, -1400, 0.2);
+ spawn.randomMob(-1625, -1275, 0.2);
+ spawn.randomMob(-1900, -1250, 0.2);
+ spawn.randomMob(-2250, -1850, 0.2);
+ spawn.randomMob(-2475, -2200, 0.2);
+ spawn.randomMob(-3000, -1475, 0.2);
+ spawn.randomMob(-3850, -2500, 0.2);
+ spawn.randomMob(-3650, -2125, 0.2);
+ spawn.randomMob(-4010, -3200, 0.2);
+ spawn.randomMob(-3500, -1825, 0.2);
+ spawn.randomMob(-975, -100, 0);
+ spawn.randomMob(-1050, -725, 0.2);
+ spawn.randomMob(-1525, -100, 0);
+ spawn.randomMob(-525, -1700, -0.1);
+ spawn.randomMob(-125, -1500, -0.1);
+ spawn.randomMob(-325, -1900, -0.1);
+ spawn.randomMob(-550, -100, -0.1);
+ spawn.randomGroup(-3250, -2700, 0.2);
+ spawn.randomGroup(-2450, -1100, 0);
+
+ if (simulation.difficulty > 1) spawn.randomLevelBoss(-2400, -2650);
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ spawn.secondaryBossChance(-1825, -1975)
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+ // boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100
+ // boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100
+ level.setPosToSpawn(300, -700); //-x
+ elevator1.holdX = -elevator1.holdX // flip the elevator horizontally
+ elevator1.removeConstraint();
+ elevator1.addConstraint();
+ elevator2.holdX = -elevator2.holdX // flip the elevator horizontally
+ elevator2.removeConstraint();
+ elevator2.addConstraint();
+
+ level.custom = () => {
+ ctx.fillStyle = "#cff" //exit
+ ctx.fillRect(4425 - 425, -3050, 425, 275)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ toggle1.query();
+ if (!toggle1.isOn) {
+ if (elevator1.isOn) {
+ elevator1.isOn = false
+ elevator1.frictionAir = 0.2
+ elevator1.addConstraint();
+ }
+ } else if (!elevator1.isOn) {
+ elevator1.isOn = true
+ elevator1.isUp = false
+ elevator1.removeConstraint();
+ elevator1.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2
+ }
+ if (elevator1.isOn) {
+ elevator1.move();
+ ctx.fillStyle = "#444"
+ ctx.fillRect(700 - 1, -1140, 1, 975)
+ } else {
+ ctx.fillStyle = "#aaa"
+ ctx.fillRect(700 - 1, -1140, 1, 975)
+ }
+
+ toggle2.query();
+ if (!toggle2.isOn) {
+ if (elevator2.isOn) {
+ elevator2.isOn = false
+ elevator2.frictionAir = 0.2
+ elevator2.addConstraint();
+ }
+ } else if (!elevator2.isOn) {
+ elevator2.isOn = true
+ elevator2.isUp = false
+ elevator2.removeConstraint();
+ elevator2.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2
+ }
+
+ if (elevator2.isOn) {
+ elevator2.move();
+ ctx.fillStyle = "#444"
+ ctx.fillRect(3540 - 1, -1720, 1, 740)
+ } else {
+ ctx.fillStyle = "#aaa"
+ ctx.fillRect(3540 - 1, -1720, 1, 740)
+ }
+
+ ctx.fillStyle = "rgba(64,64,64,0.97)" //hidden section
+ ctx.fillRect(4450 - 800, -750, 800, 200)
+ ctx.fillStyle = "rgba(0,0,0,0.12)"
+ ctx.fillRect(2500 - 150, -1975, 150, 300);
+ ctx.fillRect(1830 - 2030, -1150, 2030, 1150)
+ ctx.fillRect(3410 - 495, -2150, 495, 1550)
+ ctx.fillRect(2585 - 420, -1675, 420, 1125)
+ ctx.fillRect(1650 - 750, -1575, 750, 450)
+ };
+ }
+ },
+ warehouse() {
+ level.custom = () => {
+ ctx.fillStyle = "#444" //light fixtures
+ ctx.fillRect(-920, -505, 40, 10)
+ ctx.fillRect(-920, 95, 40, 10)
+ ctx.fillRect(180, 95, 40, 10)
+ ctx.fillRect(-20, 695, 40, 10)
+ ctx.fillRect(-2320, 945, 40, 10)
+
+ ctx.fillStyle = "#cff" //exit
+ ctx.fillRect(300, -250, 350, 250)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+
+ const lightingPath = new Path2D() //pre-draw the complex lighting path to save processing
+ lightingPath.moveTo(-1800, -500)
+ lightingPath.lineTo(-910, -500) //3rd floor light
+ lightingPath.lineTo(-1300, 0)
+ lightingPath.lineTo(-500, 0)
+ lightingPath.lineTo(-890, -500)
+ lightingPath.lineTo(-175, -500)
+ lightingPath.lineTo(-175, -250)
+ lightingPath.lineTo(175, -250)
+ lightingPath.lineTo(175, 0)
+ lightingPath.lineTo(-910, 100) //2nd floor light left
+ lightingPath.lineTo(-1300, 600)
+ lightingPath.lineTo(-500, 600)
+ lightingPath.lineTo(-890, 100)
+ lightingPath.lineTo(190, 100) //2nd floor light right
+ lightingPath.lineTo(-200, 600)
+ lightingPath.lineTo(600, 600)
+ lightingPath.lineTo(210, 100)
+ lightingPath.lineTo(1100, 100)
+ lightingPath.lineTo(1100, 1400)
+ lightingPath.lineTo(600, 1400) //1st floor light right
+ lightingPath.lineTo(10, 700)
+ lightingPath.lineTo(-10, 700)
+ lightingPath.lineTo(-600, 1400)
+ lightingPath.lineTo(-1950, 1400) //1st floor light left
+ lightingPath.lineTo(-2290, 950)
+ lightingPath.lineTo(-2310, 950)
+ lightingPath.lineTo(-2650, 1400)
+ lightingPath.lineTo(-3025, 1400)
+ lightingPath.lineTo(-3025, 150)
+ lightingPath.lineTo(-2590, 150)
+ lightingPath.lineTo(-2600, -150)
+ lightingPath.lineTo(-1800, -150)
+ lightingPath.lineTo(-1800, -500) //top left end/start of path
+
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,0,0,0.15)"; //shadows and lights
+ ctx.fill(lightingPath);
+ };
+
+ level.setPosToSpawn(25, -55); //normal spawn
+ level.exit.x = 425;
+ level.exit.y = -30;
+
+ level.defaultZoom = 1300
+ simulation.zoomTransition(level.defaultZoom)
+
+ spawn.debris(-2250, 1330, 3000, 6); //16 debris per level
+ spawn.debris(-3000, -800, 3280, 6); //16 debris per level
+ spawn.debris(-1400, 410, 2300, 5); //16 debris per level
+ powerUps.spawnStartingPowerUps(25, 500);
+ document.body.style.backgroundColor = "#dcdcde" //"#f2f5f3";
+
+ spawn.mapRect(-1500, 0, 2750, 100);
+ spawn.mapRect(175, -270, 125, 300);
+ spawn.mapRect(-1900, -600, 1775, 100);
+ spawn.mapRect(-1900, -550, 100, 1250);
+ //house
+ spawn.mapRect(-225, -550, 100, 400);
+ spawn.mapRect(-225, -10, 400, 50);
+ spawn.mapRect(-25, -20, 100, 50);
+
+ //exit house
+ spawn.mapRect(300, -10, 350, 50);
+ spawn.mapRect(-150, -350, 800, 100);
+ spawn.mapRect(600, -275, 50, 75);
+ spawn.mapRect(425, -20, 100, 25);
+ // spawn.mapRect(-1900, 600, 2700, 100);
+ spawn.mapRect(1100, 0, 150, 1500);
+ spawn.mapRect(-3150, 1400, 4400, 100);
+ spawn.mapRect(-2375, 875, 1775, 75);
+ spawn.mapRect(-1450, 865, 75, 435);
+ spawn.mapRect(-1450, 662, 75, 100);
+ spawn.bodyRect(-1418, 773, 11, 102, 1, spawn.propsFriction); //blocking path
+ spawn.mapRect(-3150, 50, 125, 1450);
+ spawn.mapRect(-2350, 600, 3150, 100);
+ spawn.mapRect(-2125, 400, 250, 275);
+ // spawn.mapRect(-1950, -400, 100, 25);
+ spawn.mapRect(-3150, 50, 775, 100);
+ spawn.mapRect(-2600, -250, 775, 100);
+
+ let isElevators = false
+ let elevator1, elevator2, elevator3
+ if (Math.random() < 0.5) {
+ isElevators = true
+ elevator1 = level.elevator(-1780, 500, 260, 40, 7, 0.0003) // x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
+ elevator2 = level.elevator(820, 1300, 260, 40, 607, 0.0003)
+ elevator3 = level.elevator(-2850, 1250, 160, 40, 600, 0.007)
+ if (simulation.isHorizontalFlipped) {
+ spawn.mapVertex(-2900, 225, "0 0 0 -500 -500 -500")
+ } else {
+ spawn.mapVertex(-2900, 225, "0 0 0 -500 500 -500")
+ }
+ spawn.mapRect(-3050, 1175, 175, 300);
+ spawn.bodyRect(-2375, 1300, 100, 100);
+ spawn.bodyRect(-2325, 1250, 50, 50);
+ spawn.bodyRect(-2275, 1350, 125, 50);
+
+
+ level.custom = () => {
+ elevator1.move();
+ elevator1.drawTrack();
+ elevator2.move();
+ elevator2.drawTrack();
+ elevator3.move();
+ elevator3.drawTrack();
+
+ ctx.fillStyle = "#444" //light fixtures
+ ctx.fillRect(-920, -505, 40, 10)
+ ctx.fillRect(-920, 95, 40, 10)
+ ctx.fillRect(180, 95, 40, 10)
+ ctx.fillRect(-20, 695, 40, 10)
+ ctx.fillRect(-2320, 945, 40, 10)
+
+ ctx.fillStyle = "#cff" //exit
+ ctx.fillRect(300, -250, 350, 250)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ } else {
+ spawn.mapRect(-2950, 1250, 175, 250);
+ spawn.mapRect(-3050, 1100, 150, 400);
+
+ spawn.bodyRect(-1450, -125, 125, 125, 1, spawn.propsSlide); //weight
+ spawn.bodyRect(-1800, 0, 300, 100, 1, spawn.propsHoist); //hoist
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: -1650,
+ y: -500
+ },
+ bodyB: body[body.length - 1],
+ stiffness: 0.0001815,
+ length: 1
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+
+ spawn.bodyRect(600, 525, 125, 125, 1, spawn.propsSlide); //weight
+ spawn.bodyRect(800, 600, 300, 100, 1, spawn.propsHoist); //hoist
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: 950,
+ y: 100
+ },
+ bodyB: body[body.length - 1],
+ stiffness: 0.0001815,
+ length: 1
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+
+ spawn.bodyRect(-2700, 1150, 100, 160, 1, spawn.propsSlide); //weight
+ spawn.bodyRect(-2550, 1200, 150, 150, 1, spawn.propsSlide); //weight
+ spawn.bodyRect(-2763, 1300, 350, 100, 1, spawn.propsHoist); //hoist
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: -2575,
+ y: 150
+ },
+ bodyB: body[body.length - 1],
+ stiffness: 0.0004,
+ length: 566
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ }
+ //blocks
+ spawn.bodyRect(-212, -150, 30, 35, 1);
+ spawn.bodyRect(-212, -115, 30, 35, 1);
+ spawn.bodyRect(-212, -80, 30, 35, 1);
+ spawn.bodyRect(-212, -45, 30, 35, 1);
+
+ spawn.bodyRect(-750, 400, 150, 150, 0.5);
+ spawn.bodyRect(-400, 1175, 100, 250, 1); //block to get to top path on bottom level
+
+ spawn.bodyRect(-2525, -50, 145, 100, 0.5);
+ spawn.bodyRect(-2325, -300, 150, 100, 0.5);
+ spawn.bodyRect(-1275, -750, 200, 150, 0.5); //roof block
+ spawn.bodyRect(-525, -700, 125, 100, 0.5); //roof block
+
+ //mobs
+ spawn.randomSmallMob(-1125, 550);
+ spawn.randomSmallMob(-2950, -50);
+ spawn.randomMob(-2025, 175, 0.3);
+ spawn.randomMob(-2325, 450, 0.3);
+ spawn.randomMob(-2925, 675, 0.2);
+ spawn.randomMob(-2700, 300, 0.1);
+ spawn.randomMob(-2500, 300, 0.1);
+ spawn.randomMob(-2075, -425, 0.1);
+ spawn.randomMob(-1550, -725, 0.1);
+ spawn.randomMob(375, 1100, 0);
+ spawn.randomMob(-1575, 1100, 0);
+ spawn.randomSmallMob(825, 300);
+ spawn.randomMob(-800, -1750, 0);
+ spawn.randomMob(400, -750, -0.1);
+ spawn.randomMob(650, 1300, -0.1);
+ spawn.randomMob(-2450, 1050, -0.1);
+ spawn.randomMob(500, 400, -0.1);
+ spawn.randomMob(-75, -1700, -0.1);
+ spawn.randomMob(900, -800, -0.2);
+ spawn.randomGroup(-75, 1050, -0.1);
+ spawn.randomGroup(-900, 1000, 0.2);
+ spawn.randomGroup(-1300, -1100, -0.3);
+ spawn.randomSmallMob(-2325, 800);
+ spawn.randomSmallMob(-900, 825);
+
+ if (simulation.difficulty > 1) {
+ if (Math.random() < 0.80) {
+ spawn.randomLevelBoss(-800, -1300)
+ } else {
+ spawn.dragonFlyBoss(-1000 + Math.random() * 2500, -1300); //boss snake with head
+ }
+ }
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ spawn.secondaryBossChance(300, -800)
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+
+ // boost1.boostBounds.min.x = -boost1.boostBounds.min.x - 100
+ // boost1.boostBounds.max.x = -boost1.boostBounds.max.x + 100
+ level.setPosToSpawn(-25, -55); //-x
+
+ if (isElevators) {
+ elevator1.holdX = -elevator1.holdX // flip the elevator horizontally
+ elevator2.holdX = -elevator2.holdX // flip the elevator horizontally
+ elevator3.holdX = -elevator3.holdX // flip the elevator horizontally
+ level.custom = () => {
+ elevator1.move();
+ elevator1.drawTrack();
+ elevator2.move();
+ elevator2.drawTrack();
+ elevator3.move();
+ elevator3.drawTrack();
+
+ ctx.fillStyle = "#444" //light fixtures
+ ctx.fillRect(920 - 40, -505, 40, 10)
+ ctx.fillRect(920 - 40, 95, 40, 10)
+ ctx.fillRect(-180 - 40, 95, 40, 10)
+ ctx.fillRect(20 - 40, 695, 40, 10)
+ ctx.fillRect(2320 - 40, 945, 40, 10)
+
+ ctx.fillStyle = "#cff" //exit
+ ctx.fillRect(-300 - 350, -250, 350, 250)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ } else {
+ level.custom = () => {
+ ctx.fillStyle = "#444" //light fixtures
+ ctx.fillRect(920 - 40, -505, 40, 10)
+ ctx.fillRect(920 - 40, 95, 40, 10)
+ ctx.fillRect(-180 - 40, 95, 40, 10)
+ ctx.fillRect(20 - 40, 695, 40, 10)
+ ctx.fillRect(2320 - 40, 945, 40, 10)
+
+ ctx.fillStyle = "#cff" //exit
+ ctx.fillRect(-300 - 350, -250, 350, 250)
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ }
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,0,0,0.15)"; //shadows and lights
+ ctx.beginPath()
+ ctx.moveTo(1800, -500)
+ ctx.lineTo(910, -500) //3rd floor light
+ ctx.lineTo(1300, 0)
+ ctx.lineTo(500, 0)
+ ctx.lineTo(890, -500)
+ ctx.lineTo(175, -500)
+ ctx.lineTo(175, -250)
+ ctx.lineTo(-175, -250)
+ ctx.lineTo(-175, 0)
+ ctx.lineTo(910, 100) //2nd floor light left
+ ctx.lineTo(1300, 600)
+ ctx.lineTo(500, 600)
+ ctx.lineTo(890, 100)
+ ctx.lineTo(-190, 100) //2nd floor light right
+ ctx.lineTo(200, 600)
+ ctx.lineTo(-600, 600)
+ ctx.lineTo(-210, 100)
+ ctx.lineTo(-1100, 100)
+ ctx.lineTo(-1100, 1400)
+ ctx.lineTo(-600, 1400) //1st floor light right
+ ctx.lineTo(-10, 700)
+ ctx.lineTo(10, 700)
+ ctx.lineTo(600, 1400)
+ ctx.lineTo(1950, 1400) //1st floor light left
+ ctx.lineTo(2290, 950)
+ ctx.lineTo(2310, 950)
+ ctx.lineTo(2650, 1400)
+ ctx.lineTo(3025, 1400)
+ ctx.lineTo(3025, 150)
+ ctx.lineTo(2590, 150)
+ ctx.lineTo(2600, -150)
+ ctx.lineTo(1800, -150)
+ ctx.lineTo(1800, -500) //top left end/start of path
+ ctx.fill()
+ };
+ }
+ },
+ office() {
+ let button, door
+ let isReverse = false
+ if (Math.random() < 0.75) { //normal direction start in top left
+ button = level.button(525, 0)
+ door = level.door(1362, -400, 25, 400, 355, 1.5) //door(x, y, width, height, distance, speed = 1) {
+ level.setPosToSpawn(1375, -1550); //normal spawn
+ level.exit.x = 3088;
+ level.exit.y = -630;
+ } else { //reverse direction, start in bottom right
+ isReverse = true
+ button = level.button(3800, 0)
+ door = level.door(3012, -400, 25, 400, 355, 1.5)
+ level.setPosToSpawn(3137, -650); //normal spawn
+ level.exit.x = 1375;
+ level.exit.y = -1530;
+ }
+ level.custom = () => {
+ button.query();
+ button.draw();
+ if (button.isUp) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ ctx.fillStyle = "#ccc"
+ ctx.fillRect(2495, -500, 10, 525)
+ ctx.fillStyle = "#dff"
+ if (isReverse) {
+ ctx.fillRect(725, -1950, 825, 450)
+ } else {
+ ctx.fillRect(3050, -950, 625, 500)
+ }
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(3650, -1300, 1300, 1300)
+ ctx.fillRect(3000, -1000, 650, 1000)
+ ctx.fillRect(750, -1950, 800, 450)
+ ctx.fillRect(750, -1450, 650, 1450)
+ ctx.fillRect(-550, -1700, 1300, 1700)
+ // ctx.fillRect(0, 0, 0, 0)
+ door.draw();
+ };
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom)
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 50); //ground bump wall
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ document.body.style.backgroundColor = "#e0e5e0";
+
+ spawn.debris(-300, -200, 1000, 6); //ground debris //16 debris per level
+ spawn.debris(3500, -200, 800, 5); //ground debris //16 debris per level
+ spawn.debris(-300, -650, 1200, 5); //1st floor debris //16 debris per level
+ powerUps.spawnStartingPowerUps(-525, -700);
+
+ spawn.mapRect(-600, 0, 2000, 325); //ground
+ spawn.mapRect(1400, 25, 1600, 300); //ground
+ spawn.mapRect(3000, 0, 2000, 325); //ground
+ spawn.mapRect(-600, -1700, 50, 2000 - 100); //left wall
+ spawn.bodyRect(-295, -1540, 40, 40); //center block under wall
+ spawn.bodyRect(-298, -1580, 40, 40); //center block under wall
+ spawn.bodyRect(1500, -1540, 30, 30); //left of entrance
+ spawn.mapRect(1550, -2000, 50, 550); //right wall
+ // spawn.mapRect(1350, -2000 + 505, 50, 1295);
+ spawn.mapRect(1350, -1500, 50, 1125); //right wall
+ spawn.mapRect(-600, -2000 + 250, 2000 - 700, 50); //roof left
+ spawn.mapRect(-600 + 1300, -2000, 50, 300); //right roof wall
+ spawn.mapRect(-600 + 1300, -2000, 900, 50); //center wall
+
+ map[map.length] = Bodies.polygon(725, -1700, 0, 15); //circle above door
+ spawn.bodyRect(720, -1675, 15, 170, 1, spawn.propsDoor); // door
+ body[body.length - 1].isNotHoldable = true;
+ //makes door swing
+ consBB[consBB.length] = Constraint.create({
+ bodyA: body[body.length - 1],
+ pointA: {
+ x: 0,
+ y: -90
+ },
+ bodyB: map[map.length - 1],
+ stiffness: 1
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+
+ spawn.mapRect(-600 + 300, -2000 * 0.75, 1900, 50); //3rd floor
+ spawn.mapRect(-600 + 2000 * 0.7, -2000 * 0.74, 50, 375); //center wall
+ spawn.bodyRect(-600 + 2000 * 0.7, -2000 * 0.5 - 106, 50, 106); //center block under wall
+ spawn.mapRect(-600, -1000, 1100, 50); //2nd floor
+ spawn.mapRect(600, -1000, 500, 50); //2nd floor
+ spawn.spawnStairs(-600, -1000, 4, 250, 350); //stairs 2nd
+ spawn.mapRect(375, -600, 350, 150); //center table
+ spawn.mapRect(-300, -2000 * 0.25, 1690, 50); //1st floor
+ spawn.spawnStairs(-610 + 2000 - 50, -500, 4, 250, 350, true); //stairs
+ spawn.spawnStairs(-600, 0, 4, 250, 350); //stairs ground
+ spawn.bodyRect(700, -200, 100, 100); //center block under wall
+ spawn.bodyRect(700, -300, 100, 100); //center block under wall
+ spawn.bodyRect(700, -400, 100, 100); //center block under wall
+ spawn.mapRect(1390, 13, 30, 20); //step left
+ spawn.mapRect(2980, 13, 30, 20); //step right
+ spawn.bodyRect(4250, -700, 50, 100);
+ spawn.mapRect(3000, -1000, 50, 625); //left wall
+ spawn.mapRect(3000 + 2000 - 50, -1300, 50, 1100); //right wall
+ spawn.mapRect(4150, -600, 350, 150); //table
+ spawn.mapRect(3650, -1300, 50, 700); //exit wall
+ spawn.mapRect(3650, -1300, 1350, 50); //exit wall
+ spawn.bodyRect(3665, -600, 20, 100); //door
+
+ spawn.mapRect(3025, -600, 250, 125);
+ spawn.mapRect(3175, -550, 175, 75);
+ // spawn.mapVertex(3160, -525, "625 0 300 0 300 -140 500 -140"); //entrance/exit ramp
+
+ spawn.mapRect(3000, -2000 * 0.5, 700, 50); //exit roof
+ spawn.mapRect(3010, -2000 * 0.25, 1690, 50); //1st floor
+ spawn.spawnStairs(3000 + 2000 - 50, 0, 4, 250, 350, true); //stairs ground
+ spawn.randomSmallMob(4575, -560, 1);
+ spawn.randomSmallMob(1315, -880, 1);
+ spawn.randomSmallMob(800, -600);
+ spawn.randomMob(4100, -225, 0.8);
+ spawn.randomMob(-250, -700, 0.8);
+ spawn.randomMob(4500, -225, 0.15);
+ spawn.randomMob(3250, -225, 0.15);
+ spawn.randomMob(-100, -225, 0.1);
+ spawn.randomMob(1150, -225, 0.15);
+ spawn.randomMob(2000, -225, 0.15);
+ spawn.randomMob(450, -225, 0.15);
+ spawn.randomMob(100, -1200, 1);
+ spawn.randomMob(950, -1150, -0.1);
+ spawn.randomGroup(1800, -800, -0.2);
+ spawn.randomGroup(4150, -1000, 0.6);
+ if (simulation.difficulty > 1) {
+ if (Math.random() < 0.5) {
+ spawn.tetherBoss(2850, -80, { x: 2500, y: -500 })
+ } else {
+ spawn.randomLevelBoss(2200, -450)
+ }
+ }
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ spawn.secondaryBossChance(1875, -675)
+
+ if (simulation.isHorizontalFlipped) { //flip the map horizontally
+ level.flipHorizontal(); //only flips map,body,mob,powerUp,cons,consBB, exit
+ level.setPosToSpawn(50, -60);
+
+ if (!isReverse) { //normal direction start in top left
+ level.setPosToSpawn(-1375, -1550); //normal spawn //-x
+ } else { //reverse direction, start in bottom right
+ level.setPosToSpawn(-3137, -650); //normal spawn
+ }
+ button.min.x = -button.min.x - 126 // flip the button horizontally
+ button.max.x = -button.max.x + 126 // flip the button horizontally
+ level.custom = () => {
+ button.query();
+ button.draw();
+ if (button.isUp) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ ctx.fillStyle = "#ccc"
+ ctx.fillRect(-2495 - 10, -500, 10, 525)
+ ctx.fillStyle = "#dff"
+ if (isReverse) {
+ ctx.fillRect(-725 - 825, -1950, 825, 450)
+ } else {
+ ctx.fillRect(-3050 - 625, -950, 625, 500)
+ }
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(-3650 - 1300, -1300, 1300, 1300)
+ ctx.fillRect(-3000 - 650, -1000, 650, 1000)
+ ctx.fillRect(-750 - 800, -1950, 800, 450)
+ ctx.fillRect(-750 - 650, -1450, 650, 1450)
+ ctx.fillRect(550 - 1300, -1700, 1300, 1700)
+ // ctx.fillRect(0, 0, 0, 0)
+ door.draw();
+ };
+ }
+
+ },
+ stronghold() { // player made level by Francois 👑 from discord
+ simulation.makeTextLog(`
stronghold by
Francois `);
+
+ const boost1 = level.boost(1470, -250, 1080)
+ const boost2 = level.boost(-370, 0, 800)
+ const boost3 = level.boost(4865, 0, 1800)
+ level.custom = () => {
+ boost1.query();
+ boost2.query();
+ boost3.query();
+ ctx.fillStyle = "#edf9f9";
+ ctx.fillRect(-500, -1220, 550, -480);
+ ctx.fillStyle = "rgba(0,0,0,0.1)";
+ ctx.fillRect(0, -700, 1050, 700);
+ ctx.fillRect(-550, -1170, 550, 1170);
+ ctx.fillRect(1150, -1700, 250, 1700);
+ ctx.fillRect(1100, -1700, 50, 450);
+ ctx.fillRect(1050, -1200, 100, 1200);
+ ctx.fillRect(1400, -250, 200, -1500);
+ ctx.fillRect(1600, -550, 600, -1150);
+ ctx.fillRect(2530, -550, 430, -1450);
+ ctx.fillRect(3270, -1700, 80, 600);
+ ctx.fillRect(3350, -1350, 700, 230);
+ ctx.fillRect(4050, -1700, 600, 1290);
+ ctx.fillRect(3650, -110, 1000, 170);
+ ctx.fillRect(4865, -55, 100, 55);
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+
+ };
+
+ level.setPosToSpawn(1900, -40); //normal spawn
+ level.exit.x = -350;
+ level.exit.y = -1250;
+
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom)
+
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 20); //exit bump
+ spawn.debris(3800, -1480, 300, 12);
+ spawn.debris(3600, -1130, 200, 2);
+ document.body.style.backgroundColor = "#dbdcde";
+ // simulation.draw.mapFill = "#444"
+ // simulation.draw.bodyFill = "rgba(140,140,140,0.85)"
+ // simulation.draw.bodyStroke = "#222"
+
+ // __________________________________________________________________________________________________
+ // Spawn Box
+ spawn.mapRect(1600, -500, 50, 500); //Left Wall
+ spawn.mapRect(1600, -550, 1500, 50); //Roof
+ spawn.mapRect(2300, -500, 50, 300); //Right Wall
+
+ spawn.mapRect(-550, 0, 4300, 200); //ground
+ spawn.mapRect(3700, 55, 1300, 145); //2nd ground
+ spawn.mapRect(5000, 0, 50, 200); //Last small part of the ground
+ spawn.mapRect(3100, -1070, 50, 570); // vertical 2nd roof
+ spawn.mapRect(3100, -1120, 950, 50); // Horizontal 2nd Roof
+ spawn.mapRect(4050, -1750, 600, 50); // Roof after lift
+ spawn.mapRect(4600, -1700, 50, 100); // Petit retour de toit, après ascenseur
+
+ //Spawn "Upstairs"
+ spawn.mapRect(3650, -160, 400, 50); //Thin Walk
+ spawn.mapRect(4050, -410, 600, 300); //Large staircase block
+ spawn.mapRect(4600, -1120, 50, 710); //Left Wall Wall upstairs
+ spawn.mapRect(4550, -1170, 100, 50); //Bloque ascenseur
+ spawn.mapVertex(3700, 35, "0 0 450 0 300 -60 150 -60"); //first slope
+ spawn.mapVertex(4850, 35, "0 0 370 0 370 -65 150 -65"); //second slope
+
+ spawn.bodyRect(3950, -280, 170, 120); //Bloc Marche Pour Monter À Ascenseur
+ // spawn.bodyRect(-2700, 1150, 100, 160, 1, spawn.propsSlide); //weight
+ // spawn.bodyRect(-2550, 1150, 200, 100, 1, spawn.propsSlide); //weight
+ spawn.bodyRect(4050, -500, 275, 100, 1, spawn.propsSlide); //weight
+ spawn.bodyRect(4235, -500, 275, 100, 1, spawn.propsSlide); //weight
+ // spawn.bodyRect(-2775, 1300, 400, 100, 1, spawn.propsHoist); //hoist
+ spawn.bodyRect(4025, -450, 550, 100, 1, spawn.propsHoist); //hoist
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: 4325,
+ y: -1700,
+ },
+ bodyB: body[body.length - 1],
+ stiffness: 0.0002, //1217,
+ length: 200
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+
+ spawn.bodyRect(2799, -870, 310, 290); //Gros bloc angle toit
+ spawn.mapRect(4000, -1750, 50, 400); //Right Wall Cuve
+ spawn.mapRect(3400, -1400, 600, 50); // Bottom Cuve
+ spawn.mapRect(3350, -1750, 50, 400); // Left Wall Cuve
+ spawn.bodyRect(3400, -1470, 110, 70); //Moyen bloc dans la cuve
+ spawn.mapRect(3270, -1750, 80, 50); // Rebord gauche cuve
+
+ spawn.mapRect(2530, -2000, 430, 50); //First Plateforme
+ spawn.mapRect(1600, -1750, 600, 50); // Middle plateforme
+ spawn.mapRect(1100, -1750, 300, 50); //Derniere plateforme // Toit petite boite en [
+ spawn.bodyRect(1830, -1980, 190, 230); // Fat bloc plateforme middle
+ spawn.bodyRect(1380, -1770, 250, 20) // Pont last plateforme
+
+ spawn.mapRect(1000, -1250, 400, 50); //Sol de la petite boite en [
+ spawn.mapRect(1100, -1550, 50, 190); //Mur gauche petite boite en [
+ spawn.bodyRect(1100, -1380, 48, 109); //Bloc-porte petite boite en [
+
+ spawn.mapRect(-100, -750, 1100, 50); //Sol last salle
+ spawn.mapRect(1000, -1200, 50, 500) // Mur droit last salle
+ spawn.mapRect(50, -1550, 1050, 50); // Toit last salle
+ spawn.bodyRect(1, -900, 48, 150); //Bloc porte last salle
+ spawn.mapRect(0, -1170, 50, 270); //Mur gauche en bas last salle
+ spawn.bodyRect(920, -900, 120, 120); //Gros bloc last salle
+
+ spawn.mapRect(0, -1700, 50, 320); // Mur droit salle exit / Mur gauche last salle
+ spawn.mapRect(-550, -1220, 600, 50); // Sol exit room
+ spawn.mapRect(-500, -1750, 550, 50); // Toit exit room
+ spawn.mapRect(-550, -1750, 50, 530); // Mur gauche exit room
+ spawn.bodyRect(-503, -1250, 30, 30); // Petit bloc exit room
+
+ spawn.mapRect(500, -700, 100, 590); //Bloc noir un dessous last salle
+ spawn.mapRect(1350, -250, 250, 250); //Black Block left from the spawn
+
+
+ map[map.length] = Bodies.polygon(2325, -205, 0, 15); //circle above door
+ spawn.bodyRect(2325, -180, 15, 170, 1, spawn.propsDoor); // door
+ body[body.length - 1].isNotHoldable = true;
+ //makes door swing
+ consBB[consBB.length] = Constraint.create({
+ bodyA: body[body.length - 1],
+ pointA: {
+ x: 0,
+ y: -90
+ },
+ bodyB: map[map.length - 1],
+ stiffness: 1
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ spawn.bodyRect(650, 50, 70, 50);
+ spawn.bodyRect(300, 0, 100, 60);
+ spawn.bodyRect(400, 0, 100, 150);
+ spawn.bodyRect(2545, -50, 70, 50);
+ spawn.bodyRect(2550, 0, 100, 30);
+
+ spawn.randomSmallMob(200, -1300, 0.5);
+ spawn.randomSmallMob(300, -1300, 0.9);
+ spawn.randomSmallMob(470, -650, 1);
+ spawn.randomSmallMob(1000, -400, 1);
+ spawn.randomSmallMob(2550, -560, 1);
+ spawn.randomSmallMob(3350, -900, 1);
+ spawn.randomSmallMob(3600, -1210, 1);
+ spawn.randomSmallMob(700, -1950, 0.2);
+ spawn.randomSmallMob(5050, -550);
+ spawn.randomMob(-250, -250, 0.8);
+ spawn.randomMob(-300, -600, 0.6);
+ spawn.randomMob(350, -900, 0.5);
+ spawn.randomMob(770, -950, 0.8)
+ spawn.randomMob(900, -160, 1);
+ spawn.randomMob(2360, -820, 0.8);
+ spawn.randomMob(2700, -2020, 0.8);
+ spawn.randomMob(3050, -1650, 0.8);
+ spawn.randomMob(3350, -600, 0.8);
+ spawn.randomMob(4400, -50, 1);
+ spawn.randomGroup(1500, -1900, 0.5);
+ spawn.randomGroup(2350, -850, 1);
+ spawn.randomGroup(100, -450, 0.9);
+
+ if (simulation.difficulty > 1) spawn.randomLevelBoss(1850, -1400);
+ spawn.secondaryBossChance(1850, -1400)
+
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ basement() { // player made level by Francois 👑 from discord
+ simulation.makeTextLog(`
basement by
Francois `);
+ let button, door, buttonDoor, buttonPlateformEnd, doorPlateform
+ let isLevelReversed = Math.random();
+ if (isLevelReversed < 0.7) {
+ isLevelReversed = false;
+ } else {
+ isLevelReversed = true;
+ }
+ const elevator = level.elevator(4545, -220, 110, 30, -3000)
+ const hazard = level.hazard(1675, -1050, 800, 150);
+ const portal = level.portal({
+ x: -620,
+ y: -257
+ }, Math.PI / 2, { //down
+ x: 500,
+ y: 2025
+ }, -Math.PI / 2) //up
+ spawn.mapRect(350, 2025, 300, 300); //Bloc portail n°2
+
+ if (isLevelReversed === false) { /// Normal Spawn
+ button = level.button(2700, -1150);
+ level.setPosToSpawn(2600, -2050); //normal spawn
+ level.exit.x = level.enter.x + 4510;
+ level.exit.y = level.enter.y + 600;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ } else { /// Reversed spawn
+ button = level.button(1450, -1150);
+ buttonPlateformEnd = level.button(3530, -1150);
+ buttonDoor = level.button(8033, -3625);
+ door = level.door(7700, -3905, 25, 184, 184);
+ doorPlateform = level.door(3200, -1225, 299, 80, 525);
+ level.setPosToSpawn(7110, -1450); //normal spawn
+ level.exit.x = level.enter.x - 4510;
+ level.exit.y = level.enter.y - 600;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ spawn.mapRect(7675, -3935, 75, 25);
+ spawn.mapRect(7675, -3715, 75, 25);
+ spawn.bodyRect(8075, -3675, 50, 25);
+ }
+ const boost1 = level.boost(8290, -2100, 1800)
+ level.custom = () => {
+ boost1.query();
+
+ level.exit.drawAndCheck();
+ portal[2].query()
+ portal[3].query()
+ button.query();
+ button.draw();
+ if (isLevelReversed === true) { ///Reversed spawn
+ buttonDoor.draw();
+ buttonDoor.query();
+ buttonPlateformEnd.draw();
+ buttonPlateformEnd.query();
+ // hazard.query(); //bug reported from discord?
+ if (buttonDoor.isUp) {
+ door.isClosing = false
+ } else {
+ door.isClosing = true
+ }
+ door.openClose();
+ if (buttonPlateformEnd.isUp) {
+ doorPlateform.isClosing = true;
+ } else {
+ doorPlateform.isClosing = false;
+ }
+ door.openClose();
+ doorPlateform.openClose();
+ }
+ hazard.level(button.isUp)
+
+
+ level.enter.draw();
+ elevator.move();
+ elevator.drawTrack();
+ };
+
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(61,62,62,0.95)";
+ ctx.fillRect(-750, -900, 750, 450);
+
+ if (isLevelReversed === true) {
+ door.draw();
+ doorPlateform.draw();
+ }
+ portal[0].draw();
+ portal[1].draw();
+ portal[2].draw();
+ portal[3].draw();
+ hazard.query();
+ };
+
+ level.defaultZoom = 1300
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#c7c7c7";
+
+ // GROUND //
+ spawn.mapRect(-400, -2000, 400, 1430); //Gros left wall
+ spawn.mapRect(3700, -3000, 700, 2650); //Gros right wall //Puit
+ spawn.mapRect(-400, -2000, 3700, 250); //Ground
+ spawn.mapRect(2475, -1150, 1225, 250);
+ spawn.mapRect(500, -1150, 1175, 250); //Ground level 3
+ spawn.mapRect(350, -180, 4600, 1255); // Last ground
+ spawn.mapRect(-400, -458, 750, 3337); //mur left sous-sol
+ spawn.mapRect(-2850, -3375, 5300, 1375);
+ spawn.mapRect(-2850, -4200, 8000, 825);
+ spawn.mapRect(3700, -3375, 550, 375);
+ spawn.mapRect(-2850, -5200, 10200, 1000);
+ spawn.mapRect(5600, -1250, 3550, 2000);
+ spawn.mapRect(9150, -5200, 1725, 5800);
+ // SPAWN BOX //
+ spawn.mapRect(2300, -3375, 950, 1000);
+ spawn.mapRect(3550, -3375, 150, 1625);
+ spawn.mapVertex(2020, -791, " 250 250 -860 250 -2200 0 250 0"); //map vertex en haut
+ spawn.mapVertex(690, -295, "1700 0 -200 0 -200 -284 500 -284"); //map vertex en bas
+ spawn.mapRect(2950, -900, 750, 250); //Extension ground apres map vertex
+ if (isLevelReversed === false) {
+ spawn.mapRect(3250, -1800, 50, 150); //Petit picot en haut, à gauche
+ spawn.mapRect(3400, -1800, 50, 150); //Petit picot en haut, à droite
+ spawn.mapRect(3150, -1300, 50, 200) //Petit picot en bas, à gauche
+ spawn.mapRect(3500, -1300, 50, 200) //Petit picot en bas, à droite
+ spawn.mapRect(3050, -3375, 500, 1260);
+ spawn.mapRect(3400, -2265, 150, 515); //Mur fond tunnel
+ spawn.bodyRect(3625, -1225, 75, 75); //Pitit bloc à droite en bas spawn
+ } else {
+ spawn.mapRect(3050, -3375, 500, 1000);
+ spawn.mapRect(3400, -2400, 150, 650); //Mur fond tunnel
+ spawn.bodyRect(3425, -1515, 75, 75); //Petit en bas spawn
+ spawn.mapRect(3200, -1275, 300, 175);
+ }
+
+ // TRAMPOLING //
+ if (isLevelReversed === false) { /// Normal spawn
+ spawn.bodyRect(0, -1000, 500, 120, 1, spawn.propsHoist); //hoist
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: 250,
+ y: -1750,
+ },
+ bodyB: body[body.length - 1],
+ stiffness: 0.00014,
+ length: 120
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ spawn.bodyRect(0, -1250, 240, 190) //Fat cube ascenseur
+ } else { /// Reversed spawn
+ spawn.bodyRect(0, -650, 225, 175);
+ spawn.mapRect(425, -950, 175, 50);
+ spawn.mapRect(-25, -1150, 100, 50);
+ }
+ // PUIT //
+ spawn.mapVertex(4200, -1810, "0 0 450 0 600 -2500 0 -2500")
+ spawn.mapVertex(5000, -1809, "0 0 450 0 450 -2500 -150 -2500")
+ spawn.mapRect(4800, -3000, 800, 5875); //big right Puit
+ // BOSS AREA //
+ spawn.mapRect(4800, -3150, 50, 200); //Premiere barriere
+ spawn.mapRect(5100, -3530, 50, 380); //2nd barriere
+ spawn.mapRect(5100, -3200, 150, 50); //Marche en dessous mapVertex 1
+ spawn.mapVertex(5450, -3650, "220 0 200 30 -200 30 -220 0 -200 -30 200 -30");
+ spawn.mapVertex(6225, -3350, "275 0 250 50 -250 50 -275 0 -250 -50 250 -50");
+ spawn.mapRect(5600, -3000, 1600, 725); //ground Boss Area
+ //Ouverture right boss area
+ spawn.mapRect(7300, -3325, 50, 50); //petite marche pour accéder à l'ouverture
+ spawn.mapRect(7350, -4075, 850, 50); //Bouche
+ spawn.mapRect(7400, -4050, 800, 50); //Bouche
+ spawn.mapRect(7450, -4025, 750, 50); //Bouche
+ spawn.mapRect(7500, -4000, 700, 50); //Bouche
+ spawn.mapRect(7550, -3975, 650, 50); //Bouche
+ spawn.mapRect(7350, -3600, 850, 50); //Bouche
+ spawn.mapRect(7400, -3625, 800, 50); //Bouche
+ spawn.mapRect(7450, -3650, 575, 50); //Bouche
+ spawn.mapRect(7500, -3675, 525, 50); //Bouche
+ spawn.mapRect(7550, -3700, 475, 50); //Bouche
+ //Murs
+ spawn.mapRect(7350, -5200, 1800, 1125);
+ spawn.mapRect(8475, -4075, 675, 2825);
+ spawn.mapRect(7300, -2100, 1175, 850);
+ spawn.mapRect(7350, -3550, 850, 1275);
+ //Escaliers
+ spawn.mapRect(6600, -2100, 200, 75); //escaliers
+ spawn.mapRect(6750, -2100, 750, 250); //escaliers
+ spawn.mapRect(6950, -1850, 550, 200); //escaliers
+ spawn.mapRect(6750, -1400, 750, 150); //escaliers
+ spawn.mapRect(6550, -1625, 250, 375); //escaliers
+ spawn.mapRect(6350, -1800, 250, 550); //escaliers
+ spawn.mapRect(5600, -2275, 800, 1025); //escaliers
+ // BLOCS
+ if (isLevelReversed === false) { /// Normal spawn
+ spawn.bodyRect(1350, -1175, 225, 25);
+ spawn.bodyRect(1450, -1200, 25, 25);
+ } else { /// Reversed spawn
+ spawn.bodyRect(700, -1175, 225, 25);
+ spawn.bodyRect(800, -1200, 25, 25);
+ }
+ spawn.bodyRect(1100, -1375, 225, 225);
+ spawn.bodyRect(1775, -925, 75, 25);
+ spawn.bodyRect(2225, -950, 75, 50);
+ spawn.bodyRect(2000, -1000, 50, 100);
+ spawn.bodyRect(3100, -1175, 50, 25);
+ spawn.bodyRect(2200, -375, 50, 50);
+ spawn.bodyRect(2200, -425, 50, 50);
+ spawn.bodyRect(2200, -475, 50, 50);
+ spawn.bodyRect(2200, -525, 50, 50);
+ spawn.bodyRect(1050, -400, 50, 25);
+ spawn.mapRect(2200, -650, 50, 125);
+ spawn.mapRect(2200, -325, 50, 150);
+ spawn.mapRect(2875, -225, 250, 50);
+ spawn.mapRect(2050, -1225, 75, 100); //Plateforme over acid
+ // MOBS
+ if (isLevelReversed === false) { ///Normal spawn
+ if (simulation.difficulty > 1) {
+ if (Math.random() < 0.2) {
+ spawn.tetherBoss(7000, -3300, { x: 7300, y: -3300 }) // tether ball
+ } else {
+ spawn.randomLevelBoss(6100, -3600, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "pulsarBoss"]);
+ }
+ }
+ } else { /// Reversed spawn
+ if (simulation.difficulty > 1) {
+ if (Math.random() < 0.2) {
+ spawn.tetherBoss(2300, -1300, { x: 2300, y: -1750 }) // tether ball
+ } else {
+ spawn.randomLevelBoss(2300, -1400, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "dragonFlyBoss", "pulsarBoss"]);
+ }
+ }
+ }
+ spawn.randomSmallMob(100, -1000, 1);
+ spawn.randomSmallMob(1340, -675, 1);
+ spawn.randomSmallMob(7000, -3750, 1);
+ spawn.randomSmallMob(6050, -3200, 1);
+ spawn.randomMob(1970 + 10 * Math.random(), -1150 + 20 * Math.random(), 1);
+ spawn.randomMob(3500, -525, 0.8);
+ spawn.randomMob(6700, -3700, 0.8);
+ spawn.randomMob(2600, -1300, 0.7);
+ spawn.randomMob(600, -1250, 0.7);
+ spawn.randomMob(2450, -250, 0.6);
+ spawn.randomMob(6200, -3200, 0.6);
+ spawn.randomMob(900, -700, 0.5);
+ spawn.randomMob(1960, -400, 0.5);
+ spawn.randomMob(5430, -3520, 0.5);
+ spawn.randomMob(400, -700, 0.5);
+ spawn.randomMob(6500, -4000, 0.4);
+ spawn.randomMob(3333, -400, 0.4);
+ spawn.randomMob(3050, -1220, 0.4);
+ spawn.randomMob(800, 1200, 0.3);
+ spawn.randomMob(7200, -4000, 0.3);
+ spawn.randomMob(250, -1550, 0.3);
+ spawn.randomGroup(900, -1450, 0.3);
+ spawn.randomGroup(2980, -400, 0.3);
+ spawn.randomGroup(5750, -3860, 0.4);
+ spawn.randomGroup(1130, 1300, 0.1);
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ powerUps.spawn(1900, -940, "heal");
+ powerUps.spawn(3000, -230, "heal");
+ powerUps.spawn(5450, -3675, "ammo");
+
+ // SECRET BOSS AREA //
+ //hidden house
+ spawn.mapRect(-850, -2000, 600, 1150); //Toit hidden house
+ spawn.mapRect(-2850, -2000, 2150, 4880); //Mur gauche hidden house
+ spawn.mapRect(-850, -458, 500, 3340); //Bloc sol hidden house
+ //
+ spawn.mapRect(-400, 2025, 3450, 850); //Sol secret boss area
+ spawn.mapRect(625, 1300, 225, 50); //Plateforme horizontale n°1
+ spawn.mapRect(850, 1775, 470, 50); //Plateforme horizontale n°2
+ spawn.mapRect(1000, 1625, 100, 150); //Plateforme vertiale n°1
+ spawn.mapRect(1400, 1275, 100, 100); //Plateforme carrée
+ spawn.mapRect(1700, 1675, 75, 450); //Plateforme verticale n°2
+ spawn.mapRect(2100, 1375, 450, 50); //Plateforme accroche boss
+ spawn.mapRect(2900, 900, 175, 325); //Débord de toit droite haut
+ spawn.mapRect(2900, 1675, 150, 350); //Muret en bas à droite
+ spawn.mapRect(2900, 1225, 75, 100); //Picot haut entrée salle trésor
+ spawn.mapRect(2900, 1575, 75, 100); //Picot bas entrée salle trésor
+ spawn.mapRect(2800, 1575, 100, 25); //Plongeoir sortie salle trésor
+ spawn.mapRect(3050, 1675, 400, 1200); //Sol sallle trésor
+ spawn.mapRect(3075, 1075, 375, 150); //Plafond salle trésor
+ spawn.mapRect(3300, 1075, 1500, 1800); //Mur droite salle trésor
+ // tether ball
+ spawn.tetherBoss(2330, 1850, { x: 2330, y: 1425 })
+ spawn.secondaryBossChance(2330, 1850)
+ powerUps.chooseRandomPowerUp(3100, 1630);
+ },
+ // detours() { //by Francois from discord
+ // simulation.makeTextLog(`
detours by
Francois `);
+ // level.setPosToSpawn(0, 0); //lower start
+ // level.exit.y = 150;
+ // spawn.mapRect(level.enter.x, 45, 100, 20);
+ // level.exit.x = 10625;
+ // spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+ // level.defaultZoom = 1400;
+ // simulation.zoomTransition(level.defaultZoom)
+ // document.body.style.backgroundColor = "#d5d5d5";
+ // const BGColor = "rgba(0,0,0,0.1)";
+ // // level.fill.push({
+ // // x: -150,
+ // // y: -250,
+ // // width: 625,
+ // // height: 325,
+ // // color: BGColor
+ // // });
+ // // level.fill.push({
+ // // x: 475,
+ // // y: -520,
+ // // width: 5375,
+ // // height: 875,
+ // // color: BGColor
+ // // });
+ // // level.fill.push({
+ // // x: 5850,
+ // // y: -1275,
+ // // width: 2800,
+ // // height: 2475,
+ // // color: BGColor
+ // // });
+ // // level.fill.push({
+ // // x: 8650,
+ // // y: -500,
+ // // width: 1600,
+ // // height: 750,
+ // // color: BGColor
+ // // });
+ // // level.fill.push({
+ // // x: 10250,
+ // // y: -700,
+ // // width: 900,
+ // // height: 950,
+ // // color: BGColor
+ // // });
+ // const balance = level.spinner(5500, -412.5, 25, 660) //entrance
+ // const rotor = level.rotor(7000, 580, -0.001);
+ // const doorSortieSalle = level.door(8590, -520, 20, 800, 750)
+ // // let buttonSortieSalle
+ // // let portalEnBas
+ // let portalEnHaut
+ // // let door3isClosing = false;
+
+ // function drawOnTheMapMapRect(x, y, dx, dy) {
+ // spawn.mapRect(x, y, dx, dy);
+ // len = map.length - 1
+ // map[len].collisionFilter.category = cat.map;
+ // map[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ // Matter.Body.setStatic(map[len], true); //make static
+ // Composite.add(engine.world, map[len]); //add to world
+ // simulation.draw.setPaths() //update map graphics
+ // }
+
+ // function drawOnTheMapBodyRect(x, y, dx, dy) {
+ // spawn.bodyRect(x, y, dx, dy);
+ // len = body.length - 1
+ // body[len].collisionFilter.category = cat.body;
+ // body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
+ // Composite.add(engine.world, body[len]); //add to world
+ // body[len].classType = "body"
+ // }
+
+ // function spawnCouloirEnHaut() {
+ // // level.fill.push({
+ // // x: 2575,
+ // // y: -1150,
+ // // width: 2550,
+ // // height: 630,
+ // // color: BGColor
+ // // });
+ // // level.fill.push({
+ // // x: 1900,
+ // // y: -2300,
+ // // width: 1650,
+ // // height: 1150,
+ // // color: BGColor
+ // // });
+ // // level.fill.push({
+ // // x: 3550,
+ // // y: -1625,
+ // // width: 1650,
+ // // height: 475,
+ // // color: BGColor
+ // // });
+ // // level.fill.push({
+ // // x: 1800,
+ // // y: -1120,
+ // // width: 775,
+ // // height: 600,
+ // // color: BGColor
+ // // });
+ // drawOnTheMapMapRect(3800, -270, 75, 75);
+ // drawOnTheMapMapRect(3900, -895, 500, 75);
+ // drawOnTheMapMapRect(3900, -1195, 75, 375);
+ // drawOnTheMapMapRect(3525, -1195, 450, 75);
+ // drawOnTheMapMapRect(3525, -1995, 50, 1575);
+ // drawOnTheMapMapRect(3325, -1995, 50, 1575);
+ // drawOnTheMapMapRect(3525, -1670, 1675, 75);
+ // drawOnTheMapMapRect(5100, -1670, 100, 1250);
+ // drawOnTheMapMapRect(1800, -1195, 1575, 75);
+ // drawOnTheMapMapRect(1800, -1520, 375, 400);
+ // drawOnTheMapMapRect(1800, -2370, 100, 1250);
+ // drawOnTheMapMapRect(2375, -1845, 375, 250);
+ // drawOnTheMapMapRect(2700, -1745, 650, 75);
+ // drawOnTheMapMapRect(1800, -2370, 1775, 100);
+ // drawOnTheMapMapRect(3525, -2370, 50, 775);
+ // drawOnTheMapMapRect(4650, -1220, 550, 75);
+ // drawOnTheMapBodyRect(3225, -1845, 100, 100);
+ // drawOnTheMapBodyRect(3575, 1255, 125, 25);
+ // drawOnTheMapBodyRect(2450, 2255, 25, 25);
+ // drawOnTheMapBodyRect(3975, -945, 175, 50);
+ // drawOnTheMapBodyRect(4825, -1295, 50, 75);
+ // drawOnTheMapBodyRect(4850, -720, 250, 200);
+ // drawOnTheMapBodyRect(4050, -970, 25, 25);
+ // drawOnTheMapBodyRect(3075, -1245, 50, 50);
+ // portalEnHaut = level.portal({
+ // x: 3650,
+ // y: -1470
+ // }, Math.PI / 2, {
+ // x: 3250,
+ // y: -1473
+ // }, Math.PI / 2)
+
+ // spawn.randomSmallMob(2500, -2070 + Math.random(), 1);
+ // spawn.randomSmallMob(5000, -1370, 1);
+ // spawn.randomMob(5000, -645, 0.9);
+ // spawn.randomMob(4050, -970, 0.9);
+ // spawn.randomSmallMob(2800, -1620, 0.7);
+ // spawn.randomMob(2400, -1370, 0.5);
+ // spawn.randomMob(3725, -1320, 0.3);
+ // spawn.randomGroup(2115, -2020, 0.1)
+
+ // powerUps.spawn(5000, -1275, "heal");
+
+ // levelCustom2();
+ // }
+ // //////////////////////////////////////////
+ // level.custom = () => {
+ // level.exit.drawAndCheck();
+ // rotor.rotate();
+ // // rotor2.rotate()
+
+ // level.enter.draw();
+ // };
+ // level.customTopLayer = () => {
+ // doorSortieSalle.draw();
+ // ctx.fillStyle = "#233"
+ // ctx.beginPath();
+ // ctx.arc(balance.pointA.x, balance.pointA.y, 9, 0, 2 * Math.PI);
+ // ctx.fill();
+ // };
+ // ////////////////////////////////////////
+ // function levelCustom2() {
+ // level.custom = () => {
+ // portalEnHaut[2].query();
+ // portalEnHaut[3].query();
+ // rotor.rotate();
+ // doorSortieSalle.openClose();
+ // level.exit.drawAndCheck();
+
+ // level.enter.draw();
+ // };
+ // // //////////////////////////////////////
+ // level.customTopLayer = () => {
+ // doorSortieSalle.draw();
+ // portalEnHaut[0].draw();
+ // portalEnHaut[1].draw();
+ // portalEnHaut[2].draw();
+ // portalEnHaut[3].draw();
+ // ctx.fillStyle = "#233"
+ // ctx.beginPath();
+ // ctx.arc(balance.pointA.x, balance.pointA.y, 9, 0, 2 * Math.PI);
+ // ctx.fill();
+
+ // };
+ // }
+ // //spawn box
+ // spawn.mapRect(-200, -295, 75, 425);
+ // spawn.mapRect(-200, 55, 700, 75);
+ // spawn.mapRect(-200, -295, 700, 75);
+ // spawn.bodyRect(470, -220, 25, 275); //porte spawn box
+ // //couloir
+ // spawn.mapRect(450, -520, 50, 300); //muret gauche haut
+ // spawn.mapRect(450, 55, 50, 300); //muret gauche bas
+ // spawn.mapRect(1700, -520, 50, 325); //muret 2 haut
+ // spawn.mapRect(1700, 55, 50, 300); //muret 2 bas
+ // spawn.mapRect(4375, 55, 50, 300);
+ // spawn.mapRect(4575, 55, 50, 300);
+ // spawn.bodyRect(4625, 155, 75, 100);
+ // spawn.bodyRect(4725, 230, 50, 25);
+ // if (Math.random() > 0.5) {
+ // powerUps.chooseRandomPowerUp(4500, 200);
+ // } else {
+ // powerUps.chooseRandomPowerUp(8350, -630);
+ // }
+ // //blocs
+ // spawn.bodyRect(7475, 1055, 50, 75);
+ // spawn.bodyRect(7775, 1105, 25, 25);
+ // spawn.bodyRect(6925, 1105, 125, 25);
+ // spawn.bodyRect(6375, 380, 50, 50);
+ // spawn.bodyRect(6425, -220, 125, 150);
+ // spawn.bodyRect(6475, -245, 125, 25);
+ // spawn.bodyRect(7675, -245, 100, 50);
+ // spawn.bodyRect(7075, -520, 50, 100);
+ // spawn.bodyRect(8400, -595, 100, 75);
+ // spawn.bodyRect(1700, 5, 50, 50);
+ // spawn.bodyRect(1700, -45, 50, 50);
+ // spawn.bodyRect(1700, -95, 50, 50);
+ // spawn.bodyRect(1700, -145, 50, 50);
+ // spawn.bodyRect(1700, -195, 50, 50);
+ // spawn.mapRect(450, -520, 1600, 100); //plafond 1
+ // spawn.mapRect(450, 255, 1600, 100); //sol 1
+ // spawn.mapRect(2250, -45, 1450, 75); //entresol
+ // spawn.mapRect(3900, -520, 2000, 100); //plafond 2
+ // spawn.mapRect(3900, 255, 2000, 100); //sol 2
+ // //grande salle
+ // spawn.bodyRect(5900, 830, 325, 300); //bloc en bas à gauche
+ // spawn.mapRect(5775, -1295, 2900, 100);
+ // spawn.mapRect(5775, 1130, 2900, 100); //plancher + sol grande salle
+ // spawn.mapRect(5925, -70, 650, 50); //plateforme middle entrée
+ // spawn.mapRect(7575, -520, 1100, 100); //sol salle en haut à droite
+ // spawn.mapRect(6800, -420, 450, 50); //petite plateforme transition vers salle en haut
+ // spawn.mapRect(7750, -1295, 75, 575); //mur gauche salle en haut à droite
+ // spawn.mapRect(6100, 430, 375, 50); //plateforme en bas, gauche rotor
+ // spawn.mapRect(7450, -195, 1225, 75); //longue plateforme
+ // //murs grande salle
+ // spawn.mapRect(5775, -1295, 125, 875);
+ // spawn.mapRect(5775, 255, 125, 975);
+ // spawn.mapRect(8550, -1295, 125, 875);
+ // spawn.mapRect(8550, 180, 125, 1050);
+ // //couloir 2
+ // spawn.mapRect(8875, -520, 1425, 325);
+ // spawn.mapRect(8550, -520, 1750, 100);
+ // spawn.mapRect(8550, 180, 2625, 100);
+ // spawn.mapRect(10175, -745, 125, 325);
+ // spawn.mapRect(10175, -745, 1000, 125);
+ // spawn.mapRect(11050, -745, 125, 1025);
+ // spawn.mapRect(8875, 80, 1425, 200);
+ // //MOBS
+ // spawn.randomSmallMob(900, -70, 1);
+ // spawn.randomMob(4300, 95, 1);
+ // spawn.randomSmallMob(6250, 630, 1);
+ // spawn.randomMob(6255, -835, 0.9);
+ // spawn.randomMob(8200, -900, 0.7);
+ // spawn.randomMob(5700, -270, 0.7);
+ // spawn.randomMob(8275, -320, 0.7);
+ // spawn.randomMob(2700, -270, 0.7);
+ // spawn.randomMob(7575, 950, 0.5);
+ // spawn.randomMob(7000, -695, 0.4);
+ // spawn.randomMob(1850, -345, 0.3);
+ // spawn.randomMob(3600, -270, 0.3);
+ // spawn.randomMob(1500, -270, 0.2);
+ // spawn.randomMob(1250, 55, 0.2);
+ // spawn.randomMob(8800, -45, 0.2);
+ // spawn.randomGroup(8025, -845, 0.2);
+
+ // if (simulation.difficulty > 2) {
+ // // if (Math.random() < 0.2) {
+ // // // tether ball
+ // // spawn.tetherBoss(8000, 630, { x: 8550, y: 680 })
+ // // let me = mob[mob.length - 1];
+ // // me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs
+ // // this.removeCons(); //remove constraint
+ // // spawnCouloirEnHaut()
+ // // doorSortieSalle.isClosing = false;
+ // // };
+ // // if (simulation.difficulty > 4) spawn.nodeGroup(8000, 630, "spawns", 8, 20, 105);
+ // // } else {
+ // spawn.randomLevelBoss(8000, 630, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "bomberBoss", "orbitalBoss", "pulsarBoss"]);
+ // spawn.secondaryBossChance(8000, 630)
+ // //find level boss index
+ // let me
+ // for (let i = 0, len = mob.length; i < len; i++) {
+ // if (mob[i].isBoss) me = mob[i]
+ // }
+ // if (me) {
+ // me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs
+ // spawnCouloirEnHaut()
+ // doorSortieSalle.isClosing = false;
+ // };
+ // } else {
+ // spawnCouloirEnHaut()
+ // doorSortieSalle.isClosing = false;
+ // }
+ // // }
+ // } else {
+ // spawn.randomLevelBoss(8000, 630, ["shooterBoss"]);
+ // let me
+ // for (let i = 0, len = mob.length; i < len; i++) {
+ // if (mob[i].isBoss) me = mob[i]
+ // }
+ // if (me) {
+ // me.onDeath = function() { //please don't edit the onDeath function this causes serious bugs
+ // spawnCouloirEnHaut()
+ // doorSortieSalle.isClosing = false;
+ // };
+ // } else {
+ // spawnCouloirEnHaut()
+ // doorSortieSalle.isClosing = false;
+ // }
+ // }
+ // },
+ house() { //by Francois from discord
+ simulation.makeTextLog(`
house by
Francois `);
+ const rotor = level.rotor(4251, -325, 120, 20, 200, 0, 0.01, 0, -0.0001);
+ const hazard = level.hazard(4350, -1000, 300, 110);
+ const doorBedroom = level.door(1152, -1150, 25, 250, 250);
+ const doorGrenier = level.door(1152, -1625, 25, 150, 160);
+ const buttonBedroom = level.button(1250, -850);
+ const voletLucarne1 = level.door(1401, -2150, 20, 26, 28);
+ const voletLucarne2 = level.door(1401, -2125, 20, 26, 53);
+ const voletLucarne3 = level.door(1401, -2100, 20, 26, 78);
+ const voletLucarne4 = level.door(1401, -2075, 20, 26, 103);
+ const voletLucarne5 = level.door(1401, -2050, 20, 26, 128);
+ const voletLucarne6 = level.door(1401, -2025, 20, 26, 153);
+ let hasAlreadyBeenActivated = false;
+ let grd
+
+ level.setPosToSpawn(0, -50); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.x = 3100;
+ level.exit.y = -2480;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "rgb(170 170 170)"
+
+ level.custom = () => {
+ ctx.fillStyle = "rgb(221, 221, 221)";
+ ctx.fillRect(1175, -1425, 4000, 1200);
+ ctx.fillStyle = "rgb(170 170 170)";
+ ctx.fillRect(1650, -1300, 175, 150);
+ ctx.fillStyle = "rgb(77, 76, 76)";
+ ctx.fillRect(624, -1150, 28, 1075);
+ ctx.fillStyle = "#ababab";
+ ctx.fillRect(3420, -380, 285, 40);
+ ctx.fillStyle = "#474747";
+ ctx.fillRect(3555, -367.5, 15, 15);
+ ctx.fillRect(3418, -344, 288, 8);
+ ctx.fillRect(3555, -327.5, 15, 15);
+ ctx.fillRect(3418, -304, 288, 8);
+ ctx.fillRect(3555, -285, 15, 15);
+ ctx.fillStyle = "#ababab";
+ ctx.fillRect(3420, -340, 285, 40);
+ ctx.fillRect(3420, -300, 285, 45);
+ ctx.fillStyle = "rgba(141, 141, 141,1)";
+ ctx.fillRect(3800, -1275, 250, 425);
+ ctx.fillStyle = "#000";
+ ctx.fillRect(3800, -1275, 250, 3);
+ ctx.fillRect(4048, -1275, 3, 425);
+ ctx.fillRect(3800, -1275, 3, 425);
+ ctx.fillRect(3830, -1050, 35, 10);
+ ctx.fillStyle = "rgba(225, 242, 245,0.6)";
+ ctx.fillRect(4050, -1425, 1125, 600);
+ ctx.fillStyle = "#444";
+ ctx.fillRect(1736, -1300, 3, 150);
+ ctx.fillRect(1650, -1224, 175, 3);
+ ctx.fillStyle = "#5806ac";
+ ctx.fillRect(3375, -625, 375, 175);
+ ctx.fillStyle = "rgba(166, 166, 166,0.8)";
+ ctx.fillRect(4050, -1425, 1, 600);
+ ctx.fillRect(4090, -1425, 1, 600);
+ ctx.fillRect(4130, -1425, 1, 600);
+ ctx.fillRect(4170, -1425, 1, 600);
+ ctx.fillRect(4210, -1425, 1, 600);
+ ctx.fillRect(4250, -1425, 1, 600);
+ ctx.fillRect(4290, -1425, 1, 600);
+ ctx.fillRect(4330, -1425, 1, 600);
+ ctx.fillRect(4370, -1425, 1, 600);
+ ctx.fillRect(4410, -1425, 1, 600);
+ ctx.fillRect(4450, -1425, 1, 600);
+ ctx.fillRect(4490, -1425, 1, 600);
+ ctx.fillRect(4530, -1425, 1, 600);
+ ctx.fillRect(4570, -1425, 1, 600);
+ ctx.fillRect(4610, -1425, 1, 600);
+ ctx.fillRect(4650, -1425, 1, 600);
+ ctx.fillRect(4690, -1425, 1, 600);
+ ctx.fillRect(4730, -1425, 1, 600);
+ ctx.fillRect(4770, -1425, 1, 600);
+ ctx.fillRect(4810, -1425, 1, 600);
+ ctx.fillRect(4850, -1425, 1, 600);
+ ctx.fillRect(4890, -1425, 1, 600);
+ ctx.fillRect(4930, -1425, 1, 600);
+ ctx.fillRect(4970, -1425, 1, 600);
+ ctx.fillRect(5010, -1425, 1, 600);
+ ctx.fillRect(5050, -1425, 1, 600);
+ ctx.fillRect(5090, -1425, 1, 600);
+ ctx.fillRect(5130, -1425, 1, 600);
+ ctx.fillRect(4050, -1425, 1125, 2);
+ ctx.fillRect(4050, -1385, 1125, 2);
+ ctx.fillRect(4050, -1345, 1125, 2);
+ ctx.fillRect(4050, -1305, 1125, 2);
+ ctx.fillRect(4050, -1265, 1125, 2);
+ ctx.fillRect(4050, -1225, 1125, 2);
+ ctx.fillRect(4050, -1185, 1125, 2);
+ ctx.fillRect(4050, -1145, 1125, 2);
+ ctx.fillRect(4050, -1105, 1125, 2);
+ ctx.fillRect(4050, -1065, 1125, 2);
+ ctx.fillRect(4050, -1025, 1125, 2);
+ ctx.fillRect(4050, -985, 1125, 2);
+ ctx.fillRect(4050, -945, 1125, 2);
+ ctx.fillRect(4050, -905, 1125, 2);
+ ctx.fillRect(4050, -865, 1125, 2);
+
+ buttonBedroom.query();
+ buttonBedroom.draw();
+ if (buttonBedroom.isUp) {
+ if (hasAlreadyBeenActivated == false) {
+ doorBedroom.isClosing = true;
+ doorGrenier.isClosing = true;
+ voletLucarne1.isClosing = true;
+ voletLucarne2.isClosing = true;
+ voletLucarne3.isClosing = true;
+ voletLucarne4.isClosing = true;
+ voletLucarne5.isClosing = true;
+ voletLucarne6.isClosing = true;
+ }
+ } else {
+ doorBedroom.isClosing = false;
+ doorGrenier.isClosing = false;
+ voletLucarne1.isClosing = false;
+ voletLucarne2.isClosing = false;
+ voletLucarne3.isClosing = false;
+ voletLucarne4.isClosing = false;
+ voletLucarne5.isClosing = false;
+ voletLucarne6.isClosing = false;
+ if (hasAlreadyBeenActivated == false) {
+ hasAlreadyBeenActivated = true;
+ }
+ }
+ doorBedroom.openClose();
+ doorGrenier.openClose();
+ voletLucarne1.openClose();
+ voletLucarne2.openClose();
+ voletLucarne3.openClose();
+ voletLucarne4.openClose();
+ voletLucarne5.openClose();
+ voletLucarne6.openClose();
+ rotor.rotate();
+ ///
+ grd = ctx.createRadialGradient(512.5, -1025, 5, 512.5, -1025, 100);
+ grd.addColorStop(0, "rgb(255, 199, 43)");
+ grd.addColorStop(1, "rgb(170 170 170)");
+ ctx.fillStyle = grd;
+ ctx.fillRect(450, -1025, 125, 100);
+ ///
+ grd = ctx.createRadialGradient(762.5, -1025, 5, 762.5, -1025, 100);
+ grd.addColorStop(0, "rgb(255, 199, 43, 1)");
+ grd.addColorStop(1, "rgb(170 170 170)");
+ ctx.fillStyle = grd;
+ ctx.fillRect(700, -1025, 125, 100);
+ ///
+ ctx.lineWidth = 7;
+ ctx.strokeStyle = "#444444"
+ ctx.strokeRect(1650, -1300, 175, 150);
+
+ chair.force.y += chair.mass * simulation.g;
+ chair2.force.y += chair2.mass * simulation.g;
+ person.force.y += person.mass * simulation.g;
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(64,64,64,0.97)";
+ ctx.fillRect(2800, -400, 275, 175);
+
+ hazard.query();
+ doorBedroom.draw();
+ doorGrenier.draw();
+ voletLucarne1.draw();
+ voletLucarne2.draw();
+ voletLucarne3.draw();
+ voletLucarne4.draw();
+ voletLucarne5.draw();
+ voletLucarne6.draw();
+ };
+ //chairs
+ const part1 = Matter.Bodies.rectangle(4525, -255, 25, 200, {
+ density: 0.0005,
+ isNotHoldable: true,
+ });
+ const part2 = Matter.Bodies.rectangle(4562, -235, 100, 25, {
+ density: 0.0005,
+ isNotHoldable: true,
+ });
+ const part3 = Matter.Bodies.rectangle(4600, -202, 25, 91.5, {
+ density: 0.0005,
+ isNotHoldable: true,
+ });
+ const part4 = Matter.Bodies.rectangle(5100, -255, 25, 200, {
+ density: 0.0005,
+ isNotHoldable: true,
+ });
+ const part5 = Matter.Bodies.rectangle(5063, -235, 100, 25, {
+ density: 0.0005,
+ isNotHoldable: true,
+ });
+ const part6 = Matter.Bodies.rectangle(5025, -202, 25, 91.5, {
+ density: 0.0005,
+ isNotHoldable: true,
+ });
+ chair = Body.create({
+ parts: [part1, part2, part3],
+ });
+ chair2 = Body.create({
+ parts: [part4, part5, part6],
+ });
+ Composite.add(engine.world, [chair]);
+ Composite.add(engine.world, [chair2]);
+ composite[composite.length] = chair;
+ composite[composite.length] = chair2;
+ body[body.length] = part1;
+ body[body.length] = part2;
+ body[body.length] = part3;
+ body[body.length] = part4;
+ body[body.length] = part5;
+ body[body.length] = part6;
+ setTimeout(function () {
+ chair.collisionFilter.category = cat.body;
+ chair.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map
+ }, 1000);
+ setTimeout(function () {
+ chair2.collisionFilter.category = cat.body;
+ chair2.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map
+ }, 1000);
+ var head = Matter.Bodies.rectangle(300, -200 - 60, 34, 40, {
+ isNotHoldable: true,
+ });
+ var chest = Matter.Bodies.rectangle(300, -200, 55, 80, {
+ isNotHoldable: true,
+ });
+ var rightUpperArm = Matter.Bodies.rectangle(300 + 39, -200 - 15, 20, 40, {
+ isNotHoldable: true,
+ });
+ var rightLowerArm = Matter.Bodies.rectangle(300 + 39, -200 + 25, 20, 60, {
+ isNotHoldable: true,
+ });
+ var leftUpperArm = Matter.Bodies.rectangle(300 - 39, -200 - 15, 20, 40, {
+ isNotHoldable: true,
+ });
+ var leftLowerArm = Matter.Bodies.rectangle(300 - 39, -200 + 25, 20, 60, {
+ isNotHoldable: true,
+ });
+ var leftUpperLeg = Matter.Bodies.rectangle(300 - 20, -200 + 57, 20, 40, {
+ isNotHoldable: true,
+ });
+ var leftLowerLeg = Matter.Bodies.rectangle(300 - 20, -200 + 97, 20, 60, {
+ isNotHoldable: true,
+ });
+ var rightUpperLeg = Matter.Bodies.rectangle(300 + 20, -200 + 57, 20, 40, {
+ isNotHoldable: true,
+ });
+ var rightLowerLeg = Matter.Bodies.rectangle(300 + 20, -200 + 97, 20, 60, {
+ isNotHoldable: true,
+ });
+
+ //man
+ var person = Body.create({
+ parts: [chest, head, leftLowerArm, leftUpperArm,
+ rightLowerArm, rightUpperArm, leftLowerLeg,
+ rightLowerLeg, leftUpperLeg, rightUpperLeg
+ ],
+ });
+ Composite.add(engine.world, [person]);
+ composite[composite.length] = person
+ body[body.length] = chest
+ body[body.length] = head
+ body[body.length] = part3
+ body[body.length] = leftLowerLeg
+ body[body.length] = leftUpperLeg
+ body[body.length] = leftUpperArm
+ body[body.length] = leftLowerArm
+ body[body.length] = rightLowerLeg
+ body[body.length] = rightUpperLeg
+ body[body.length] = rightLowerArm
+ body[body.length] = rightUpperArm
+ setTimeout(function () {
+ person.collisionFilter.category = cat.body;
+ person.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map
+ }, 1000);
+
+ //rez de chaussée
+ spawn.mapRect(-200, 0, 5400, 100); //ground
+ spawn.mapRect(1150, -255, 4050, 355); //additionnal ground
+ spawn.mapRect(800, -255, 400, 90); //1st step
+ spawn.mapRect(650, -170, 550, 90); //2nd step
+ spawn.mapRect(500, -85, 700, 90); //3rd step
+ spawn.mapRect(1150, -850, 50, 175); //porte entrée
+ spawn.bodyRect(1162.5, -675, 25, 420) //porte entrée
+ spawn.mapRect(1150, -850, 1500, 50); //plafond 1
+ spawn.mapRect(3025, -850, 2175, 50); //plafond 2
+ spawn.mapRect(5150, -850, 50, 650); //mur cuisine
+ //lave-vaisselle
+ spawn.mapRect(4225, -400, 25, 150);
+ spawn.mapRect(4225, -400, 175, 25);
+ spawn.mapRect(4375, -400, 25, 150);
+ spawn.bodyRect(4350, -350, 20, 40);
+ spawn.bodyRect(4325, -325, 20, 20);
+ spawn.bodyRect(4325, -275, 20, 20);
+ //escalier
+ spawn.mapRect(3025, -850, 50, 225);
+ spawn.mapRect(2925, -775, 150, 150);
+ spawn.mapRect(2800, -700, 275, 75);
+ spawn.mapRect(2575, -400, 175, 175);
+ spawn.mapRect(2475, -325, 175, 100);
+ spawn.mapRect(2675, -475, 400, 100);
+ spawn.mapRect(2675, -475, 150, 250);
+ //cuisine
+ spawn.mapRect(4025, -850, 50, 175); //porte cuisine
+ spawn.mapRect(4025, -375, 50, 125); //porte cuisine
+
+ map[map.length] = Bodies.polygon(4050, -675, 0, 15); //circle above door
+ spawn.bodyRect(4040, -650, 20, 260, 1, spawn.propsDoor); // door
+ body[body.length - 1].isNotHoldable = true;
+ //makes door swing
+ consBB[consBB.length] = Constraint.create({
+ bodyA: body[body.length - 1],
+ pointA: {
+ x: 0,
+ y: -130
+ },
+ bodyB: map[map.length - 1],
+ stiffness: 1
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+
+ //table + chaises
+ spawn.mapRect(4025, -850, 50, 175);
+ spawn.mapRect(4650, -375, 325, 25);
+ spawn.mapRect(4700, -350, 25, 100);
+ spawn.mapRect(4900, -350, 25, 100);
+ spawn.bodyRect(4875, -400, 75, 25);
+ spawn.bodyRect(4700, -400, 75, 25);
+
+ //murs télé
+ spawn.mapRect(3400, -400, 20, 150);
+ spawn.mapRect(3705, -400, 20, 150);
+ spawn.mapRect(3400, -400, 325, 20);
+ //socle écran
+ spawn.mapRect(3500, -415, 125, 17);
+ spawn.mapRect(3550, -450, 25, 50);
+ // ???
+ spawn.bodyRect(3075, -375, 125, 125);
+ spawn.bodyRect(3075, -400, 50, 25);
+ spawn.bodyRect(3725, -325, 100, 75);
+ spawn.bodyRect(3375, -275, 25, 25);
+ // premier étage
+ spawn.mapRect(1150, -1450, 4050, 50);
+ spawn.mapRect(5150, -1450, 50, 650);
+ spawn.mapRect(1150, -1450, 50, 300);
+ spawn.mapRect(1150, -900, 50, 100);
+ spawn.mapVertex(1066, -730, "-200 60 0 -60 100 -60 100 60")
+ //chambre
+ spawn.mapRect(2350, -1450, 50, 175); //porte chambre
+ //lit
+ spawn.mapRect(1475, -1025, 25, 225); //pied de lit 1
+ spawn.mapRect(1850, -925, 25, 125); //pied de lit 2
+ spawn.mapRect(1475, -925, 400, 50); //sommier
+ spawn.bodyRect(1500, -950, 375, 25); //matelat
+ spawn.bodyRect(1500, -1000, 75, 50); //oreiller
+ //table
+ spawn.bodyRect(1950, -1000, 30, 150); //pied table
+ spawn.bodyRect(2250, -1000, 30, 150); //pied table
+ spawn.bodyRect(1920, -1025, 390, 25); //table
+ //salle de bain
+ spawn.mapRect(4025, -1450, 50, 175); //porte salle de bain
+ map[map.length] = Bodies.polygon(5050, -925, 0, 35.4);
+ spawn.mapRect(5015, -960, 125, 40);
+ spawn.mapRect(5050, -925, 90, 35.4);
+ spawn.mapVertex(5086.5, -875, "100 60 -30 60 20 0 100 0")
+ spawn.mapRect(5125, -1070, 15, 120)
+ spawn.bodyRect(5016, -965, 108, 15)
+ //baignoire
+ spawn.mapVertex(4316, -965, "30 100 0 100 -80 -50 30 -50") //bord 1
+ spawn.mapVertex(4675, -961.5, "30 100 0 100 0 -50 80 -50") //bord 2
+ spawn.mapVertex(4400, -860, "0 -20 -20 20 20 20 0 -20") //pied 1
+ spawn.mapVertex(4600, -860, "0 -20 -20 20 20 20 0 -20") //pied 2
+ spawn.mapRect(4325, -900, 350, 25); //fond baignoire
+ spawn.mapRect(4300, -1175, 25, 175);
+ spawn.mapRect(4300, -1175, 125, 25);
+ spawn.mapRect(4400, -1175, 25, 50); //pied pommeau de douche
+ spawn.mapVertex(4412.5, -1105, "-20 -20 -30 40 30 40 20 -20") //pommeau de douche
+
+ //grenier
+ spawn.mapRect(1150, -1475, 50, 50);
+ spawn.mapRect(1150, -1800, 50, 175);
+ spawn.mapRect(5150, -1800, 50, 400); //murs
+ spawn.mapVertex(1300, -1900, "-150 200 -200 200 50 0 100 0");
+ spawn.mapVertex(1800, -2300, "-150 200 -200 200 175 -100 225 -100");
+ spawn.mapRect(1390, -2180, 250, 30); //lucarne
+ spawn.mapVertex(5050, -1900, "150 200 200 200 -50 0 -100 0");
+ spawn.mapVertex(4550, -2300, "150 200 200 200 -175 -100 -225 -100");
+ spawn.mapRect(4710, -2175, 250, 25); //lucarne 2
+ spawn.mapRect(5150, -1450, 200, 50);
+ //obstacles
+ spawn.mapRect(3775, -1800, 99, 50);
+ spawn.mapRect(2425, -2150, 50, 425);
+ spawn.mapRect(2150, -1775, 325, 50);
+ spawn.mapRect(3825, -2150, 50, 750);
+ spawn.mapRect(3826, -2150, 149, 50);
+ spawn.mapRect(4125, -2150, 149, 50);
+ spawn.mapRect(4225, -2150, 50, 450);
+ spawn.mapRect(4225, -1750, 250, 50);
+ level.chain(2495, -2130, 0, true, 10);
+
+ spawn.bodyRect(2950, -375, 120, 120) //bloc hidden zone
+ spawn.bodyRect(2350, -1850, 75, 75);
+ spawn.bodyRect(4275, -1900, 75, 100);
+ spawn.bodyRect(4825, -1650, 325, 200);
+ spawn.bodyRect(5025, -1725, 25, 25);
+ spawn.bodyRect(4900, -1700, 200, 75);
+ spawn.mapVertex(2950, -2096, "-75 -50 75 -50 75 0 0 100 -75 0")
+
+ /*cheminée + roof*/
+ spawn.mapRect(1963, -2450, 2425, 35);
+ spawn.mapRect(2925, -2900, 125, 480);
+ spawn.mapRect(2900, -2900, 175, 75);
+ spawn.mapRect(2900, -2975, 25, 100);
+ spawn.mapRect(3050, -2975, 25, 100);
+ spawn.mapRect(2875, -3000, 225, 25);
+ // lampadaire + jump
+ spawn.mapRect(1000, -1450, 200, 25);
+ spawn.mapRect(500, -1150, 275, 25);
+ spawn.mapRect(750, -1150, 25, 75);
+ spawn.mapRect(500, -1150, 25, 75);
+ spawn.mapRect(450, -1075, 125, 50);
+ spawn.mapRect(700, -1075, 125, 50);
+ spawn.mapRect(2985, -4600, 0.1, 1700)
+
+ //bodyRects ~= debris
+ spawn.bodyRect(1740, -475, 80, 220)
+ spawn.bodyRect(1840, -290, 38, 23)
+ spawn.bodyRect(1200 + 1475 * Math.random(), -350, 15 + 110 * Math.random(), 15 + 110 * Math.random());
+ spawn.bodyRect(1200 + 1475 * Math.random(), -350, 15 + 110 * Math.random(), 15 + 110 * Math.random());
+ spawn.bodyRect(3070 + 600 * Math.random(), -1100, 20 + 50 * Math.random(), 150 + 100 * Math.random())
+ spawn.bodyRect(3050 + 1000 * Math.random(), -920, 30 + 100 * Math.random(), 15 + 65 * Math.random());
+ spawn.bodyRect(1600 + 250 * Math.random(), -1540, 80, 220) //boss room
+ spawn.debris(3070, -900, 1000, 3); //16 debris per level
+ spawn.debris(1200, -350, 1475, 4); //16 debris per level
+ spawn.debris(1250, -1550, 3565, 9); //16 debris per level
+
+ powerUps.chooseRandomPowerUp(2860, -270);
+ // Mobs
+
+ spawn.randomSmallMob(1385, -600, 1);
+ spawn.randomSmallMob(5000, -680, 1);
+ spawn.randomSmallMob(4750, -925, 1);
+ spawn.randomSmallMob(2300, -1830, 1);
+ spawn.randomMob(3170, -720, 0.8);
+ spawn.randomMob(3700, -975, 0.8);
+ spawn.randomMob(2625, -1150, 0.7);
+ spawn.randomMob(4175, -750, 0.7);
+ spawn.randomMob(2100, -370, 0.7);
+ spawn.randomMob(2000, -1230, 0.7);
+ spawn.randomMob(4175, -1075, 0.6);
+ spawn.randomMob(3965, -1650, 0.6)
+ spawn.randomMob(4650, -1750, 0.6);
+ spawn.randomMob(830, -1170, 0.5);
+ spawn.randomGroup(3730, -1100, 0.5);
+ spawn.randomMob(2650, -2250, 0.3);
+ spawn.randomMob(1615, -2270, 0.3);
+ spawn.randomMob(1380, -1280, 0.25);
+ spawn.randomMob(2280, -650, 0.2);
+ spawn.randomGroup(2450, -2650, 0.2);
+ spawn.randomMob(3800, -580, 0.2);
+ spawn.randomMob(4630, -425, 0.1);
+ spawn.randomGroup(630, -1300, -0.1);
+ spawn.randomGroup(3450, -2880, -0.2)
+ if (simulation.difficulty > 3) {
+ spawn.secondaryBossChance(3380, -1775)
+ if (Math.random() < 0.16) {
+ spawn.tetherBoss(3380, -1775, { x: 3775, y: -1775 })
+ } else {
+ spawn.randomLevelBoss(3100, -1850, ["shooterBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "dragonFlyBoss", "laserBoss"]);
+ }
+ }
+ },
+ perplex() { //by Oranger from discord
+ simulation.makeTextLog(`
perplex by
Oranger `);
+ document.body.style.backgroundColor = "#dcdcde";
+ level.setPosToSpawn(-600, 400);
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.x = 550;
+ level.exit.y = -2730;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+
+ const portal = level.portal({ //main portals
+ x: -1000,
+ y: 50
+ }, -Math.PI / 2, { //up
+ x: 1000,
+ y: 50
+ }, -Math.PI / 2) //up
+ const portal2 = level.portal({ //portals in upper right corner
+ x: 1400,
+ y: -2200
+ }, -Math.PI / 2, { //up
+ x: 1700,
+ y: -1700
+ }, -Math.PI / 2) //up
+ // rotor(x, y, width, height, density = 0.001, angle = 0, frictionAir = 0.001, angularVelocity = 0, rotationForce = 0.0005) {
+ const rotor = level.rotor(-600, -1950, 800, 50, 0.001, 0, 0.01, 0, -0.001)
+
+ level.custom = () => {
+ portal[2].query(true)
+ portal[3].query(true)
+ portal2[2].query(true)
+ portal2[3].query(true)
+ rotor.rotate();
+
+ ctx.fillStyle = "#d4f4f4";
+ ctx.fillRect(375, -3000, 450, 300);
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+
+ level.customTopLayer = () => {
+ portal[0].draw();
+ portal[1].draw();
+ portal[2].draw();
+ portal[3].draw();
+ portal2[0].draw();
+ portal2[1].draw();
+ portal2[2].draw();
+ portal2[3].draw();
+ ctx.fillStyle = "rgba(0,0,0,0.03)";
+ ctx.fillRect(-875, -250, 1500, 700);
+ ctx.fillRect(-925, -505, 930, 255);
+ ctx.fillStyle = "rgba(0,0,0,0.1)";
+ ctx.fillRect(725, -1400, 200, 200);
+ ctx.fillRect(925, -2150, 150, 2175);
+ ctx.fillRect(925, -3400, 150, 850);
+ ctx.fillStyle = "rgba(0,0,0,0.03)";
+ ctx.fillRect(1800, -2600, 400, 400);
+ ctx.fillRect(2200, -2600, 400, 1250);
+
+ };
+
+ level.defaultZoom = 1700 // 4500 // 1400
+ simulation.zoomTransition(level.defaultZoom)
+
+ //section 1: before portals
+ spawn.mapRect(-925, 450, 1850, 250); //1-1 base
+ spawn.mapRect(-925, -300, 55, 755); //1 left wall
+ spawn.mapRect(-875, 50, 1100, 50); //1-1 ceiling
+ spawn.mapRect(620, -300, 305, 755); //1-1 and 1-2 right wall
+ spawn.bodyRect(200, 350, 230, 100);
+ spawn.bodyRect(300, 250, 150, 100);
+ spawn.mapRect(-875, -300, 580, 50); //1-2 ceiling on left
+ spawn.mapRect(0, -300, 625, 50); //1-2 ceiling on right
+ spawn.mapRect(0, -650, 150, 350); //1-3 right wall
+ spawn.mapRect(-925, -650, 975, 150); //1-3 ceiling
+ spawn.mapRect(-1280, 100, 205, 150); //1-4 floor
+ spawn.mapRect(-1280, 245, 360, 455); //bottom left corner
+ spawn.mapRect(-1600, -200, 200, 50); //1-4 platform 1
+
+ //section 2: lower central room (gone through main portals 1 time)
+ spawn.mapRect(920, 245, 160, 455); //below right portal
+ spawn.mapRect(1075, -300, 500, 1000); //2-1 right floor
+ spawn.bodyRect(100, -1000, 50, 350);
+ spawn.bodyRect(100, -1015, 250, 15);
+ spawn.mapRect(-925, -1600, 100, 1000); //2-2 left wall
+ spawn.mapRect(725, -2150, 200, 750); //2-2 right wall
+ spawn.mapRect(725, -1200, 200, 200); //2-2 right wall 2
+ spawn.mapRect(300, -1000, 625, 50); //2 central ledge
+ //shute
+ spawn.mapRect(1075, -2005, 550, 1055); //shute right wall
+ spawn.mapRect(875, -1000, 50, 300); //shute left 1
+ spawn.mapRect(860, -1030, 50, 300); //shute left 2
+ spawn.mapRect(850, -1100, 50, 300); //shute left 3
+ spawn.mapRect(830, -980, 50, 50); //shute left 4
+ spawn.mapRect(1075, -1000, 50, 300); //shute right 1
+ spawn.mapRect(1090, -1030, 50, 300); //shute right 2
+ spawn.mapRect(1100, -1100, 50, 300); //shute right 3
+ spawn.mapRect(1120, -980, 50, 50); //shute right 4
+ spawn.mapRect(1850, -650, 400, 50); //drop from 4-1
+ //section 3: upper left room and upper central room (gone through main portals 2 times)
+ //3-2 is just the upper part of 2-2
+ spawn.mapRect(-1775, -1000, 700, 300); //3-1 floor
+ spawn.mapRect(-1900, -2300, 175, 1600); //3-1 left wall
+ spawn.mapRect(-1375, -1300, 300, 50); //3-1 platform 1
+ spawn.mapRect(-1600, -1650, 300, 50); //3-1 platform 2
+ spawn.mapRect(-1775, -2300, 700, 300); //3-1 ceiling
+ spawn.mapRect(-830, -1600, 300, 50); //3-2 left ledge
+ spawn.mapRect(250, -2150, 675, 50); //3-2 right ledge
+ spawn.mapRect(-925, -2300, 100, 300); //3-2 left wall
+ spawn.mapRect(-600, -2700, 1525, 150); //3-2 ceiling
+ spawn.mapRect(1075, -2150, 250, 150); //next to upper portal
+ // level.fill.push({
+ // x: -1730,
+ // y: -2300,
+ // width: 870,
+ // height: 1600,
+ // color: "rgba(0,0,0,0.03)"
+ // });
+
+ //section 4: upper right portals
+ spawn.mapRect(1475, -2700, 150, 700); //4-1 left wall
+ spawn.mapRect(1775, -1650, 250, 150); //4-1 floor-ish
+ spawn.mapRect(1575, -1505, 450, 555); //below upper right portal
+ spawn.mapRect(1800, -2250, 400, 50); //4-1 platform 2
+ spawn.bodyRect(2200, -2250, 15, 300);
+ spawn.mapRect(2200, -1950, 400, 50); //4-1 platform 1
+ //spawn.bodyRect(2575, -2600, 25, 650);
+ spawn.mapRect(2600, -1650, 400, 50); //4-1 platform 0
+ spawn.mapRect(2200, -1350, 400, 50); //4-1 platform -1
+ spawn.bodyRect(2200, -1900, 15, 550);
+ spawn.bodyRect(2585, -1650, 15, 300);
+
+ spawn.mapRect(1800, -4200, 800, 1600); //4-2 right wall
+ spawn.mapRect(800, -4200, 1800, -500); //4-2 ceiling
+ spawn.mapRect(1075, -3400, 225, 850); //upper shute right wall
+ spawn.mapRect(800, -3400, 125, 850); //upper shute left wall
+
+ //section 5: after portals (gone through main portals 3 times)
+ spawn.mapRect(-700, -2700, 100, 450); //5-1 right wall
+ spawn.mapRect(-1450, -2700, 900, 50); //5-1 ceiling
+ spawn.mapRect(-925, -2300, 325, 50); //5-1 right floor
+ spawn.mapRect(-1900, -3000, 450, 50); //stair cover
+ spawn.bodyRect(-1150, -2950, 150, 250); //5-2 block
+
+ //top left corner stuff
+ spawn.mapRect(-1900, -2450, 250, 450); //
+ //exit room
+ spawn.mapRect(350, -3000, 50, 100); //exit room left wall
+ spawn.mapRect(350, -3000, 450, -1700); //exit room ceiling
+ spawn.bodyRect(350, -2900, 50, 50.5); //door
+ spawn.bodyRect(350, -2850, 50, 50.5); //door
+ spawn.bodyRect(350, -2800, 50, 50.5); //door
+ spawn.bodyRect(350, -2750, 50, 50.5); //door
+
+ spawn.debris(-400, 450, 400, 5); //16 debris per level
+ spawn.debris(-1650, -2300, 250, 4); //16 debris per level
+ spawn.debris(-750, -650, 750, 3); //16 debris per level
+
+ //mobs
+ spawn.randomMob(-650, -100, 0.7); //1-2 left
+ spawn.randomMob(100, -150, 0.3); //1-2 right
+ spawn.randomMob(-100, -400, 0); //1-3 right
+ //spawn.randomMob(-1500, -300, 0.3); //1-4 platform
+ spawn.randomMob(1450, -450, 0); //2-1 right
+ spawn.randomMob(1700, -800, 1); //2-1 off the edge. chance is 1 because some enemies just fall
+ spawn.randomGroup(-550, -900, -0.3); //2-2
+ spawn.randomMob(-1550, -1800, 0.7); //3-1 upper platform
+ //spawn.randomMob(-1225, -1400, 0.3); //3-1 lower platform
+ spawn.randomMob(450, -2350, 0.3); //3-2 right ledge
+ //spawn.randomMob(1150, -2250, 0); //3-2 far right
+ spawn.randomGroup(2400, -2300, -0.3); //4-1 floating
+ spawn.randomMob(2400, -1450, 0); //4-1 platform -1
+ spawn.randomMob(2800, -1800, 0.5); //4-1 platform 0
+ spawn.randomMob(-1700, -3200, 0.7); //5-2 left platform
+ spawn.randomMob(-550, -2800, 0.3); //5-2 middle
+ if (simulation.difficulty > 3) {
+ if (Math.random() < 0.5) {
+ spawn.randomLevelBoss(450, -1350, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "shieldingBoss", "pulsarBoss", "laserBoss"]);
+ } else {
+ spawn.randomLevelBoss(-300, -3200, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "shieldingBoss", "pulsarBoss", "laserBoss"]);
+ }
+ }
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ spawn.secondaryBossChance(7725, 2275)
+ },
+ coliseum() {
+ simulation.makeTextLog(`
coliseum by
iNoobBoi `);
+ level.custom = () => {
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => { };
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#dcdcde";
+ //Level
+ level.setPosToSpawn(200, 50);
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+
+ level.exit.x = 8950;
+ level.exit.y = 170;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+
+ //Map
+ spawn.mapRect(-100, -400, 100, 600);
+ spawn.mapRect(-100, 100, 700, 100);
+ spawn.mapRect(500, 100, 100, 1700);
+ spawn.mapRect(500, 1700, 4000, 100);
+ spawn.mapRect(4100, 600, 400, 100);
+ spawn.mapRect(4400, 600, 100, 1600);
+ spawn.mapRect(4400, 2100, 4300, 100);
+ spawn.mapRect(8600, 200, 100, 2000);
+ spawn.mapRect(8600, 200, 700, 100);
+ spawn.mapRect(9200, -300, 100, 600);
+ spawn.mapRect(8600, -300, 700, 100);
+ spawn.mapRect(8600, -700, 100, 500);
+ spawn.mapRect(4400, -700, 4300, 100);
+ spawn.mapRect(4400, -700, 100, 900);
+ spawn.mapRect(-100, -400, 4600, 100);
+
+ //Platforms
+ spawn.mapRect(1100, 400, 300, 100);
+ spawn.mapRect(500, 500, 300, 100);
+ spawn.mapRect(1050, 800, 300, 100);
+ spawn.mapRect(1770, 1050, 300, 100);
+ spawn.mapRect(1800, 500, 300, 100);
+ spawn.mapRect(2550, 900, 300, 100);
+ spawn.mapRect(2800, 1400, 300, 100);
+ spawn.mapRect(1250, 1350, 300, 100);
+ spawn.mapRect(4750, 850, 300, 100);
+ spawn.mapRect(3200, 1050, 300, 100);
+ spawn.mapRect(4700, 100, 300, 100);
+ spawn.mapRect(5350, 0, 300, 100);
+ spawn.mapRect(3800, 900, 300, 100);
+ spawn.mapRect(5100, 500, 300, 100);
+ spawn.mapRect(5900, -300, 300, 100);
+ spawn.mapRect(6500, -700, 300, 1300);
+ spawn.mapRect(7900, 0, 300, 100);
+ spawn.mapRect(8050, 800, 300, 100);
+ spawn.mapRect(7800, 1900, 300, 100);
+ spawn.mapRect(8300, 450, 300, 100);
+ spawn.mapRect(8400, 1200, 300, 100);
+ spawn.mapRect(7570, 1100, 300, 100);
+ spawn.mapRect(6700, 1850, 300, 100);
+ spawn.mapRect(8000, 1500, 300, 100);
+ spawn.mapRect(7120, -100, 300, 100);
+ spawn.mapRect(7000, 1500, 300, 100);
+ spawn.mapRect(6500, 1000, 300, 1200);
+ spawn.mapRect(5800, 1100, 300, 100);
+ spawn.mapRect(5900, 1700, 300, 100);
+ spawn.mapRect(5300, 1400, 300, 100);
+ spawn.mapRect(5200, 1100, 300, 100);
+ spawn.mapRect(6700, 1100, 300, 100);
+ spawn.mapRect(4800, 1650, 300, 100);
+
+ //Room 1 Spawning
+ spawn.randomMob(1000, 700, 0.7);
+ spawn.randomGroup(1100, 700, 0.5);
+ spawn.randomMob(1900, 400, 0.7);
+ spawn.randomGroup(2000, 400, 0.4);
+ spawn.randomGroup(1800, 1100, 0.4);
+ spawn.randomGroup(2700, 700, 0.5);
+ spawn.randomMob(2900, 1200, 0.7);
+ spawn.randomSmallMob(3200, 300, 0.9);
+ spawn.randomSmallMob(3700, 800, 0.9);
+ spawn.randomMob(1100, 700, 0.6);
+ spawn.randomGroup(1200, 700, 0.5);
+ spawn.randomMob(2000, 400, 0.8);
+ spawn.randomGroup(2100, 400, 0.5);
+ spawn.randomGroup(1900, 1100, 0.5);
+ spawn.randomGroup(2800, 700, 0.5);
+ spawn.randomMob(3000, 1200, 0.7);
+ spawn.randomSmallMob(3200, 300, 0.9);
+ spawn.randomSmallMob(3700, 800, 0.9);
+ spawn.randomMob(800, 1500, 0.9);
+ spawn.randomMob(1500, 1500, 0.7);
+ spawn.randomMob(2200, 1500, 0.6);
+ spawn.randomMob(2500, 1500, 0.7);
+ spawn.randomMob(2800, 1500, 0.7);
+ spawn.randomMob(3300, 1500, 0.6);
+
+ //Room 2 Spawning
+ spawn.randomGroup(4700, 2000, 0.9);
+ spawn.randomMob(5000, 2000, 0.5);
+ spawn.randomSmallMob(5700, 1500, 0.9);
+ spawn.randomMob(8500, 2000, 0.6);
+ spawn.randomGroup(8000, 1300, 0.9);
+ spawn.randomMob(8300, -300, 0.4);
+ spawn.randomSmallMob(7600, -200, 0.9);
+ spawn.randomMob(5200, -300, 0.5);
+ spawn.randomSmallMob(4700, -200, 0.5);
+ spawn.randomGroup(4700, 2000, 0.8);
+ spawn.randomMob(5000, 2000, 0.5);
+ spawn.randomSmallMob(5700, 1500, 0.9);
+ spawn.randomGroup(8500, 2000, 0.3);
+ spawn.randomSmallMob(8000, 1300, 0.4);
+ spawn.randomMob(8300, -300, 0.3);
+ spawn.randomGroup(7600, -200, 0.5);
+ spawn.randomMob(5200, -300, 0.3);
+ spawn.randomGroup(4700, -200, 0.4);
+ spawn.randomGroup(8650, -200, 0.9); //end guards
+ spawn.randomMob(8650, -200, 0.9); //end guards
+
+
+ //Boss Spawning
+ if (simulation.difficulty > 3) {
+ spawn.randomLevelBoss(6000, 700, ["pulsarBoss", "laserTargetingBoss", "powerUpBoss", "bomberBoss", "historyBoss", "orbitalBoss"]);
+ // if (simulation.difficulty > 10) spawn.shieldingBoss(7200, 500);
+ // if (simulation.difficulty > 20) spawn.randomLevelBoss(2000, 300, ["historyBoss", "shooterBoss"]);
+ }
+
+ //Blocks
+ spawn.bodyRect(550, -300, 50, 400); //spawn door
+ spawn.bodyRect(4400, 200, 100, 400); //boss door
+ spawn.bodyRect(6600, 600, 50, 400); //boss 2 door
+ spawn.debris(400, 800, 400, 2);
+ spawn.debris(3800, 1600, 1200, 6);
+ spawn.debris(7500, 2000, 800, 4);
+ spawn.debris(5500, 2000, 800, 4);
+
+ //Powerups
+ powerUps.spawnStartingPowerUps(1250, 1500);
+ // powerUps.spawnStartingPowerUps(1500, 1500);
+ powerUps.spawn(8650, -200, "ammo");
+ // powerUps.spawn(8650, -200, "ammo");
+ // powerUps.spawn(8650, -200, "ammo");
+ // powerUps.spawn(8650, -200, "ammo");
+ powerUps.spawn(200, 50, "heal");
+ // powerUps.spawn(200, 50, "ammo");
+ // powerUps.spawn(200, 50, "ammo");
+ // powerUps.spawn(200, 50, "ammo");
+
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ spawn.secondaryBossChance(6600, 600)
+ },
+ crossfire() {
+ simulation.makeTextLog(`
crossfire by
iNoobBoi `);
+
+ //*1.5
+ //Level Setup
+ const slimePitOne = level.hazard(0, 850, 3800, 120);
+ const slimePitTwo = level.hazard(4600, 430, 2000, 120);
+ const slimePitThree = level.hazard(6500, 200, 1000, 170);
+
+ level.custom = () => {
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ slimePitOne.query();
+ slimePitTwo.query();
+ slimePitThree.query();
+ };
+
+ level.setPosToSpawn(-500, 550); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+
+ level.exit.x = 10300;
+ level.exit.y = -830;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+
+ level.defaultZoom = 3000
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#dcdcde";
+
+ //Map Elements
+ spawn.mapRect(-800, -600, 800, 200);
+ spawn.mapRect(-200, -600, 200, 800);
+ spawn.mapRect(-800, -600, 200, 800);
+ spawn.mapRect(-1000, 0, 1000, 200);
+ spawn.mapRect(-1000, 0, 200, 800);
+ spawn.mapRect(-1000, 600, 1400, 200);
+ spawn.mapRect(0, 600, 200, 400);
+ spawn.mapRect(0, 950, 4000, 100);
+ spawn.mapRect(800, 800, 600, 200);
+ spawn.mapRect(1700, 700, 500, 300);
+ spawn.mapRect(2500, 600, 400, 400);
+ spawn.mapRect(3200, 600, 1200, 200);
+ spawn.mapRect(3800, 600, 200, 800); //
+ spawn.mapRect(3800, 1200, 800, 200);
+ spawn.mapRect(4400, 400, 300, 1000);
+ spawn.mapRect(4400, 500, 2000, 100);
+ spawn.mapRect(6500, 300, 1000, 100);
+ spawn.mapRect(5000, 200, 700, 400);
+ spawn.mapRect(6000, 0, 650, 600);
+ spawn.mapRect(6900, -300, 700, 100);
+ spawn.mapRect(7400, -600, 200, 1100);
+ spawn.mapRect(7400, 300, 2600, 200);
+ spawn.mapRect(9800, -800, 200, 1300);
+ spawn.mapRect(9800, -800, 1000, 200);
+ spawn.mapRect(10600, -1400, 200, 800);
+ spawn.mapRect(9800, -1400, 200, 400);
+ spawn.mapRect(7400, -1400, 3400, 200);
+ spawn.mapRect(7400, -1600, 200, 800);
+ spawn.mapRect(5400, -1600, 2200, 200);
+ spawn.mapRect(6000, -1600, 200, 800);
+ spawn.mapRect(5400, -1600, 200, 800);
+ spawn.mapRect(4800, -1000, 1400, 200);
+ spawn.mapRect(4800, -1000, 200, 600);
+ spawn.mapRect(3800, -600, 1200, 200);
+ spawn.mapRect(3200, -800, 800, 200);
+ spawn.mapRect(3200, -800, 200, 800);
+ spawn.mapRect(3800, -800, 200, 800);
+ spawn.mapRect(-200, -200, 4200, 200);
+
+ //Boss Room Platforms
+ spawn.mapRect(7700, 100, 300, 40);
+ spawn.mapRect(8600, 0, 300, 40);
+ spawn.mapRect(9200, 100, 300, 40);
+ spawn.mapRect(9400, -200, 300, 40);
+ spawn.mapRect(8000, -200, 300, 40);
+ spawn.mapRect(8500, -400, 300, 40);
+ spawn.mapRect(9000, -600, 300, 40);
+ spawn.mapRect(9400, -800, 300, 40);
+ spawn.mapRect(8600, -1000, 300, 40);
+ spawn.mapRect(7900, -800, 300, 40);
+
+ //Mob Spawning
+ spawn.randomMob(200, 400, 0.7);
+ // spawn.randomMob(1200, 400, 0.7);
+ spawn.randomMob(2000, 400, 0.7);
+ // spawn.randomMob(3000, 400, 0.7);
+ spawn.randomMob(5000, 0, 0.7);
+ spawn.randomMob(5600, 0, 0.7);
+ spawn.randomMob(6200, -200, 0.7);
+ // spawn.randomMob(6600, -200, 0.7);
+ spawn.randomMob(7200, -800, 0.7);
+ spawn.randomSmallMob(800, 400, 0.9);
+ spawn.randomSmallMob(1800, 400, 0.9);
+ // spawn.randomSmallMob(2600, 400, 0.9);
+ spawn.randomSmallMob(5200, 0, 0.9);
+ // spawn.randomSmallMob(5400, 0, 0.9);
+ spawn.randomSmallMob(6400, -200, 0.9);
+ spawn.randomGroup(3800, 400, 0.5);
+ spawn.randomGroup(4200, 400, 0.5);
+ // spawn.randomGroup(4400, 200, 0.5);
+ spawn.randomGroup(7000, -800, 0.5);
+ // spawn.randomGroup(7700, 300, 0.5);
+ spawn.randomGroup(9800, 300, 0.5);
+ // spawn.randomGroup(7700, -1100, 0.5);
+ spawn.randomGroup(9800, -1100, 0.5);
+
+ if (simulation.difficulty > 3) spawn.randomLevelBoss(8600, -600, ["powerUpBoss", "bomberBoss", "dragonFlyBoss", "spiderBoss", "historyBoss"])
+ spawn.secondaryBossChance(7900, -400)
+
+ //Boss Spawning
+ if (simulation.difficulty > 10) {
+ spawn.pulsarBoss(3600, -400);
+ powerUps.chooseRandomPowerUp(4006, 400);
+ powerUps.chooseRandomPowerUp(4407, 400);
+ powerUps.spawnStartingPowerUps(4400, 400);
+ if (simulation.difficulty > 30) {
+ powerUps.chooseRandomPowerUp(4002, 400);
+ powerUps.chooseRandomPowerUp(4004, 400);
+ spawn.pulsarBoss(4200, 1000);
+ if (simulation.difficulty > 60) {
+ powerUps.chooseRandomPowerUp(4409, 400);
+ spawn.pulsarBoss(5800, -1200);
+ if (simulation.difficulty > 80) {
+ spawn.pulsarBoss(-400, -200);
+ if (simulation.difficulty > 100) {
+ spawn.pulsarBoss(3600, -400);
+ if (simulation.difficulty > 120) {
+ spawn.pulsarBoss(-400, -200);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //Powerup Spawning
+ powerUps.spawnStartingPowerUps(4000, 400);
+ powerUps.addResearchToLevel(); //needs to run after mobs are spawned
+
+ //Block Spawning
+ // spawn.bodyRect(-100, 200, 100, 400); //spawn door
+ spawn.bodyRect(7450, -800, 25, 200); //boss room door
+ spawn.bodyRect(9850, -1000, 25, 200); //end door
+ spawn.mapRect(-200, 350, 200, 450);
+
+ // spawn.mapRect(3875, -75, 50, 575);
+ spawn.mapRect(3800, -75, 200, 525);
+ spawn.mapRect(3875, 590, 50, 150);
+ spawn.mapRect(3875, 350, 50, 140);
+
+ const debrisCount = 3
+ spawn.debris(1050, 700, 400, debrisCount);
+ spawn.debris(1900, 600, 400, debrisCount);
+ spawn.debris(2700, 500, 400, debrisCount);
+ // spawn.debris(3500, 450, 400, debrisCount);
+ spawn.debris(4150, 500, 400, debrisCount);
+ spawn.debris(5300, 0, 400, debrisCount);
+ spawn.debris(6300, -100, 400, debrisCount);
+ spawn.debris(7200, -500, 400, debrisCount);
+ spawn.debris(8000, -600, 400, debrisCount);
+ spawn.debris(8700, -700, 400, debrisCount);
+ spawn.debris(9300, -900, 400, debrisCount);
+ },
+ vats() { // Made by Dablux#6610 on Discord
+ simulation.makeTextLog(`
vats by
Dablux `);
+
+ simulation.zoomScale = 1500;
+ level.setPosToSpawn(4400, -1060)
+ spawn.mapRect(level.enter.x, level.enter.y + 30, 100, 20)
+ level.exit.x = 3900;
+ level.exit.y = 1060;
+ spawn.mapRect(level.exit.x, level.exit.y + 30, 100, 20)
+ document.body.style.backgroundColor = "#dcdcde";
+
+ var nextBlockSpawn = simulation.cycle + Math.floor(Math.random() * 60 + 30)
+ const door = level.door(475, 900, 50, 200, 201)
+ const exitDoor = level.door(3375, 900, 50, 200, 201)
+ const deliveryButton = level.button(3500, -410)
+ const buttonGreen = level.button(-1600, 1090)
+ const buttonYellow = level.button(-1600, -1160)
+ const buttonRed = level.button(5874, -2410)
+ let g = false;
+ let y = false;
+ let r = false;
+ const deliverySlime = level.hazard(3700, -940, 100, 480)
+ const deliverySlime2 = level.hazard(3700, -461, 100, 1141)
+ const slimePit = level.hazard(700, 1200, 2500, 1300, 0.004)
+ const topSlime = level.hazard(800, -460, 2900, 90, 0.004)
+ // const rotor = level.rotor(0, -725, 0.001)
+ const rotor = level.rotor(-400, -725, 800, 50, 0.001, 0, 0.01, 0, 0.001)
+
+
+ const portal = level.portal({
+ x: -135,
+ y: 800
+ }, Math.PI / 2, {
+ x: 570,
+ y: -395
+ }, -Math.PI / 2)
+ const portal2 = level.portal({
+ x: -1800,
+ y: 1900
+ }, Math.PI, {
+ x: 200,
+ y: 1105
+ }, -Math.PI / 2)
+ const drip1 = level.drip(1875, -660, -400, 70)
+ const drip2 = level.drip(3525, -940, -400, 150)
+ const drip3 = level.drip(1975, 100, 1200, 100)
+ door.isClosing = true;
+ exitDoor.isClosing = true;
+
+ // UPPER AREA //
+ spawn.mapRect(4500, -2400, 1700, 2050)
+ spawn.mapRect(3800, -1000, 700, 650)
+ spawn.mapRect(4000, -1310, 50, 60)
+ spawn.mapRect(4450, -1310, 50, 60)
+ spawn.mapRect(4000, -1320, 500, 20)
+ level.chain(4025, -1225, 0.5 * Math.PI, false, 5, 25)
+ spawn.mapRect(3650, -460, 50, 90)
+ spawn.mapRect(3525, -1000, 325, 20)
+ spawn.mapRect(3650, -1000, 50, 440)
+ spawn.mapRect(3300, -1000, 50, 450)
+ spawn.mapRect(3325, -725, 150, 25)
+ spawn.mapRect(3500, -980, 175, 35)
+ spawn.mapRect(3325, -980, 50, 35)
+ spawn.mapRect(-1800, -1250, 50, 120)
+ spawn.mapRect(6150, -2500, 50, 120)
+ spawn.bodyRect(3350, -1000, 175, 20, 1, spawn.propsIsNotHoldable) // Cover
+ Matter.Body.setMass(body[body.length - 1], 0.7) // Make cover easier to remove
+ spawn.mapRect(750, -475, 50, 75);
+ for (let i = 1; i < 5; i++) {
+ spawn.mapRect(800 + (i * 100) + (500 * (i - 1)), -460 + (i * -120) + (20 * (i - 1)), 500, 20)
+ }
+
+ // ARENA //
+ spawn.mapRect(400, -400, 2950, 500)
+ spawn.mapRect(-1800, -1150, 1800, 1950)
+ spawn.mapRect(-1800, 1100, 780, 1800)
+ spawn.mapRect(-300, 1100, 1000, 1800)
+ //spawn.mapRect(-1800, -1450, 100, 2000)
+ spawn.blockDoor(-1800, 1070)
+ level.chain(-1000, 1120, 0, true, 18, 20)
+ spawn.mapRect(700, 2500, 2500, 900)
+ spawn.mapRect(400, 100, 200, 599)
+ spawn.mapRect(400, 650, 75, 250)
+ spawn.mapRect(525, 650, 75, 250)
+ spawn.mapRect(3300, 650, 75, 250)
+ spawn.mapRect(3425, 650, 75, 250)
+ spawn.mapRect(3200, 1100, 1800, 2200)
+ spawn.mapRect(3300, -400, 200, 1099) // STOP CHANGING THIS ONE!!!!
+ spawn.mapRect(3450, -400, 250, 1100)
+ spawn.mapRect(3650, 680, 200, 20)
+ spawn.mapRect(3800, -400, 1400, 1100)
+ spawn.mapRect(4100, 700, 100, 300)
+ spawn.mapRect(4900, -400, 1300, 2500)
+ spawn.bodyRect(4100, 1000, 100, 100)
+
+ spawn.bodyRect(-2100, 2050, 290, 30) //Portal platform
+ let b = body[body.length - 1];
+ b.isNotHoldable = true
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: -1820,
+ y: 2065
+ },
+ bodyB: b,
+ pointB: {
+ x: -135,
+ y: 0
+ },
+ stiffness: 1,
+ length: 1
+ });
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: -1800,
+ y: 1400
+ },
+ bodyB: b,
+ pointB: {
+ x: 135,
+ y: 0
+ },
+ stiffness: 0.005,
+ length: 700
+ });
+ Composite.add(engine.world, [cons[cons.length - 2], cons[cons.length - 1]]);
+
+ spawn.bodyRect(5225, -2525, 300, 75);
+ spawn.bodyRect(4700, -2525, 100, 75, 0.5);
+ spawn.bodyRect(4900, -2600, 50, 50, 0.4);
+ spawn.bodyRect(5050, -2475, 500, 100, 0.4);
+ spawn.bodyRect(2950, -950, 175, 75, 0.5);
+ spawn.bodyRect(3050, -1000, 75, 50, 0.3);
+ spawn.bodyRect(2300, -850, 75, 50, 0.7);
+ spawn.bodyRect(2150, -575, 100, 175, 0.6);
+ spawn.bodyRect(2500, -550, 400, 150, 0.2);
+ spawn.bodyRect(1525, -500, 225, 100, 0.2);
+ spawn.bodyRect(1625, -575, 100, 75);
+ spawn.bodyRect(1000, -475, 100, 100, 0.8);
+ spawn.bodyRect(1225, -450, 125, 50, 0.9);
+ spawn.bodyRect(525, -500, 175, 125, 0.75);
+ spawn.bodyRect(575, -600, 100, 75, 0.5);
+ spawn.bodyRect(-925, -1225, 275, 75, 0.4);
+ spawn.bodyRect(-1125, -1300, 200, 150, 0.7);
+ spawn.bodyRect(-475, -1250, 200, 100, 0.8);
+ spawn.bodyRect(-425, -1300, 100, 50, 0.75);
+ spawn.bodyRect(-1225, -1200, 100, 25, 0.45);
+ spawn.bodyRect(-1025, -1350, 75, 50, 0.5);
+ spawn.bodyRect(-450, 1025, 75, 50, 0.5);
+ spawn.bodyRect(-775, 1050, 50, 50, 0.6);
+ spawn.bodyRect(-650, 975, 75, 75, 0.2);
+ spawn.bodyRect(-475, 1025, 100, 50, 0.7);
+ spawn.bodyRect(-450, 1025, 75, 50, 0.6);
+ spawn.bodyRect(-800, 1050, 100, 50, 0.5);
+ spawn.bodyRect(-600, 950, 75, 75, 0.3);
+ spawn.bodyRect(-500, 1000, 75, 25, 0.2);
+ spawn.bodyRect(-900, 1025, 150, 50);
+ spawn.bodyRect(-1350, 1000, 100, 100, 0.4);
+ spawn.bodyRect(-1225, 1075, 100, 25);
+ spawn.debris(900, -1000, 2000, 16);
+
+ // MOBS //
+ spawn.randomSmallMob(2900, -1000)
+ spawn.randomSmallMob(1750, -700)
+ spawn.randomMob(4250, -1400)
+ spawn.randomMob(4800, -2400, 0.3)
+ spawn.randomMob(1000, 600, 0.3)
+ spawn.randomMob(1650, 950, 0.2)
+ spawn.randomMob(1300, -1250, 0)
+ spawn.randomMob(-600, -1250, 0.1)
+ spawn.randomMob(1000, -600, 0.4)
+ spawn.randomMob(1800, -700, 0.4)
+ spawn.randomMob(2200, 950, 0.2)
+ spawn.randomMob(-1900, 1400, 0.3)
+ spawn.randomMob(-750, -1000, 0.3)
+ spawn.randomMob(3250, 1000, 0.1)
+ spawn.randomMob(2000, -2800, 0.4)
+ spawn.randomMob(2200, -500, 0)
+ spawn.randomMob(1800, -450, 0.3)
+ spawn.randomGroup(2300, -450, 1)
+ spawn.randomGroup(3000, -450, 0.3)
+ spawn.randomGroup(6000, -2700, 0)
+ spawn.randomGroup(-1200, -1300, -0.3)
+ powerUps.addResearchToLevel()
+
+ if (simulation.difficulty > 3) {
+ spawn.randomLevelBoss(1900, 400, ["shieldingBoss", "shooterBoss", "launcherBoss", "streamBoss"])
+ } else {
+ exitDoor.isClosing = false;
+ }
+ spawn.secondaryBossChance(800, -800)
+
+ powerUps.spawn(4450, 1050, "heal");
+ if (Math.random() > (0.2 + (simulation.difficulty / 60))) {
+ powerUps.spawn(4500, 1050, "ammo");
+ powerUps.spawn(4550, 1050, "ammo");
+ } else {
+ powerUps.spawn(4500, 1050, "tech");
+ spawn.randomMob(4550, 1050, Infinity);
+ }
+ powerUps.spawnStartingPowerUps(3750, -940)
+
+ const W = 500;
+ const H = 20;
+ for (let i = 1; i < 5; i++) {
+ spawn.bodyRect(700 + (i * 100) + (W * (i - 1)), 1110, W, H, 1, spawn.propsIsNotHoldable)
+ let b = body[body.length - 1];
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: b.position.x - (W / 2) + 50,
+ y: b.position.y - 1025
+ },
+ bodyB: b,
+ pointB: {
+ x: -(W / 2) + 50,
+ y: 0
+ },
+ stiffness: 0.002,
+ length: 1000
+ });
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: b.position.x + (W / 2) - 50,
+ y: b.position.y - 1025
+ },
+ bodyB: b,
+ pointB: {
+ x: (W / 2) - 50,
+ y: 0
+ },
+ stiffness: 0.002,
+ length: 1000
+ });
+ Composite.add(engine.world, [cons[cons.length - 1], cons[cons.length - 2]])
+ }
+ const boost1 = level.boost(4400, -1385, 1200)
+
+ level.custom = () => {
+ boost1.query();
+ buttonGreen.query()
+ buttonYellow.query()
+ buttonRed.query()
+
+ if (!buttonGreen.isUp) {
+ if (!g) {
+ Matter.Composite.remove(engine.world, cons[1])
+ cons.splice(1, 2)
+ }
+ g = true;
+ }
+ if (!buttonYellow.isUp) {
+ y = true;
+ }
+ if (!buttonRed.isUp) {
+ r = true;
+ }
+
+ if (g && y && r) {
+ door.isClosing = false;
+ } else {
+ door.isClosing = true;
+ }
+
+ door.openClose()
+ exitDoor.openClose()
+
+ if (m.pos.y > 1600 && 700 < m.pos.x && m.pos.x < 3200) { // Saving player from slime pit
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: 0
+ });
+ Matter.Body.setPosition(player, {
+ x: 200,
+ y: 1000
+ });
+ // move bots
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ m.damage(0.1 * simulation.difficultyMode)
+ m.energy -= 0.1 * simulation.difficultyMode
+ }
+
+ if (simulation.cycle >= nextBlockSpawn && body.length < 100) {
+ var len = body.length;
+ body[len] = Matter.Bodies.polygon(Math.floor(Math.random() * 1700) + 1050, 100, Math.floor(Math.random() * 11) + 10, Math.floor(Math.random() * 20) + 15)
+ body[len].collisionFilter.category = cat.body;
+ body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet;
+ Composite.add(engine.world, body[len])
+ nextBlockSpawn = simulation.cycle + Math.floor(Math.random() * 60 + 30)
+ }
+
+ if (exitDoor.isClosing) {
+ exitDoor.isClosing = false;
+ for (i = 0; i < mob.length; i++) {
+ if (mob[i].isBoss && 525 < mob[i].position.x < 3200 && -2500 < mob[i].position.y < 100) {
+ exitDoor.isClosing = true;
+ }
+ }
+ }
+
+ for (let i = 0, len = body.length; i < len; i++) {
+ if (body[i].position.x > 700 && body[i].position.x < 3200 && body[i].position.y > 1200 && !body[i].isNotHoldable) {
+ Matter.Body.scale(body[i], 0.99, 0.99);
+ if (body[i].velocity.y > 3) body[i].force.y -= 0.96 * body[i].mass * simulation.g
+ const slowY = (body[i].velocity.y > 0) ? Math.max(0.3, 1 - 0.0015 * body[i].velocity.y * body[i].velocity.y) : Math.max(0.98, 1 - 0.001 * Math.abs(body[i].velocity.y)) //down : up
+ Matter.Body.setVelocity(body[i], {
+ x: Math.max(0.6, 1 - 0.07 * Math.abs(body[i].velocity.x)) * body[i].velocity.x,
+ y: slowY * body[i].velocity.y
+ });
+ if (body[i].mass < 0.05) {
+ Matter.Composite.remove(engine.world, body[i])
+ body.splice(i, 1)
+ break
+ }
+ }
+ }
+
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (mob[i].position.x > 700 && mob[i].position.x < 3200 && mob[i].alive && !mob[i].isShielded && mob[i].position.y > 1200) {
+ mobs.statusDoT(mob[i], 0.005, 30)
+ }
+ }
+
+ ctx.beginPath()
+ ctx.fillStyle = "#666";
+ ctx.arc(buttonGreen.min.x - 50, buttonGreen.min.y - 70, 20, 0, 2 * Math.PI)
+ ctx.fillRect(buttonGreen.min.x - 55, buttonGreen.max.y + 25, 10, -95)
+ ctx.fill()
+ ctx.beginPath()
+ ctx.arc(buttonYellow.min.x - 50, buttonYellow.min.y - 70, 20, 0, 2 * Math.PI)
+ ctx.fillRect(buttonYellow.min.x - 55, buttonYellow.max.y + 25, 10, -95)
+ ctx.fill()
+ ctx.beginPath()
+ ctx.arc(buttonRed.min.x - 50, buttonRed.min.y - 70, 20, 0, 2 * Math.PI)
+ ctx.fillRect(buttonRed.min.x - 55, buttonRed.max.y + 25, 10, -95)
+ ctx.fill()
+
+ ctx.beginPath()
+ ctx.arc(buttonGreen.min.x - 50, buttonGreen.min.y - 70, 10, 0, 2 * Math.PI)
+ ctx.fillStyle = (g ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`);
+ ctx.fill()
+ ctx.beginPath()
+ ctx.arc(buttonYellow.min.x - 50, buttonYellow.min.y - 70, 10, 0, 2 * Math.PI)
+ ctx.fillStyle = (y ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`);
+ ctx.fill()
+ ctx.beginPath()
+ ctx.arc(buttonRed.min.x - 50, buttonRed.min.y - 70, 10, 0, 2 * Math.PI)
+ ctx.fillStyle = (r ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`);
+ ctx.fill()
+
+ slimePit.query();
+ ctx.shadowColor = 'hsla(160, 100%, 50%, 1)'
+ ctx.shadowBlur = 100;
+ // slimePit.draw()
+ ctx.shadowBlur = 0;
+ ctx.shadowColor = 'rgba(0, 0, 0, 0)'
+
+ deliveryButton.query()
+ portal[2].query()
+ //portal[3].query()
+ portal2[2].query()
+ //portal2[3].query()
+
+ deliverySlime.level(deliveryButton.isUp)
+ topSlime.level(!r)
+ rotor.rotate()
+
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(3500, 675, 600, 450)
+ level.enter.draw()
+ level.exit.drawAndCheck()
+ }
+
+ level.customTopLayer = () => {
+ topSlime.query();
+ deliverySlime.query()
+ deliverySlime2.query()
+ drip1.draw()
+ drip2.draw()
+ drip3.draw()
+
+ ctx.fillStyle = `rgba(68, 68, 68, ${Math.max(0.3, Math.min((4200 - m.pos.x) / 100, 0.99))})`
+ ctx.fillRect(4100, 650, 850, 500)
+
+ ctx.fillStyle = "rgba(0,20,40,0.1)"
+ ctx.fillRect(4025, -1300, 475, 300)
+ ctx.fillRect(3325, -1000, 375, 600)
+ ctx.fillRect(425, 100, 3050, 2400)
+ ctx.fillRect(-1775, 800, 1750, 2100)
+ ctx.fillStyle = "rgba(0,20,40,0.2)"
+ ctx.fillRect(2725, -860, 450, 460)
+ ctx.fillRect(2125, -760, 450, 360)
+ ctx.fillRect(1525, -660, 450, 260)
+ ctx.fillRect(925, -560, 450, 160)
+ ctx.fillRect(3700, -980, 100, 1200)
+
+ ctx.fillStyle = `#444`;
+ ctx.fillRect(465, 690, 70, 209)
+ ctx.fillRect(3365, 690, 70, 209)
+
+ ctx.beginPath()
+ ctx.arc(500, 870, 20, 0, 2 * Math.PI)
+ ctx.arc(500, 820, 20, 0, 2 * Math.PI)
+ ctx.arc(500, 770, 20, 0, 2 * Math.PI)
+ ctx.fillStyle = "rgba(0, 0, 0, 0.3";
+ ctx.fill()
+
+ ctx.beginPath()
+ ctx.arc(500, 870, 10, 0, 2 * Math.PI)
+ ctx.fillStyle = (g ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`);
+ ctx.fill()
+ ctx.beginPath()
+ ctx.arc(500, 820, 10, 0, 2 * Math.PI)
+ ctx.fillStyle = (y ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`);
+ ctx.fill()
+ ctx.beginPath()
+ ctx.arc(500, 770, 10, 0, 2 * Math.PI)
+ ctx.fillStyle = (r ? `rgba(0, 255, 0, 0.9)` : `rgba(255, 0, 0, 0.9)`);
+ ctx.fill()
+
+ deliveryButton.draw()
+ // deliverySlime.draw()
+ // deliverySlime2.draw()
+ // topSlime.draw()
+ buttonGreen.draw()
+ buttonYellow.draw()
+ buttonRed.draw()
+ portal[0].draw()
+ portal[2].draw()
+ portal2[0].draw()
+ portal2[2].draw()
+ }
+ },
+ ngon() { //make by Oranger
+ simulation.makeTextLog(`
"ngon" by
Oranger `);
+
+ document.body.style.backgroundColor = "#dcdcde";
+ let needGravity = [];
+ let s = { //mech statue
+ x: -200,
+ y: -2350,
+ angle: 0,
+ scale: 15,
+ h: { //hip
+ x: 12,
+ y: 24
+ },
+ k: { //knee
+ x: -30.96, //-17.38
+ y: 58.34, //70.49
+ //x2: -33.96, //x - 3
+ //y2: 58.34 //same as y
+ },
+ f: { //foot
+ x: 0,
+ y: 91 //112
+ },
+ fillColor: "#ccc", //white
+ fillColorDark: "#bbb", //25% from white
+ lineColor: "#999", //#333
+ lineColorLight: "#aaa" //#4a4a4a
+ }
+ const boost1 = level.boost(2550, 1500, 1700)
+ const boost2 = level.boost(-3400, -2050, 2100)
+
+ level.custom = () => {
+ boost1.query();
+ boost2.query();
+
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ for (let i = 0; i < needGravity.length; i++) {
+ needGravity[i].force.y += needGravity[i].mass * simulation.g;
+ }
+ ctx.fillStyle = "#444" //light fixtures
+ ctx.fillRect(2350, 995, 40, 10)
+ //ctx.fillRect(2280, -6005, 40, 10)
+
+ //statue
+ ctx.save();
+ ctx.translate(s.x, s.y);
+ //statueLeg is at the bottom, below the enemies but above the NGON function
+ statueLeg(-3, s.lineColorLight);
+ statueLeg(0, s.lineColor);
+ //head
+ ctx.rotate(s.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30 * s.scale, 0, 2 * Math.PI);
+ let grd = ctx.createLinearGradient(-30 * s.scale, 0, 30 * s.scale, 0);
+ grd.addColorStop(0, s.fillColorDark);
+ grd.addColorStop(1, s.fillColor);
+ ctx.fillStyle = grd;
+ ctx.fill();
+ ctx.arc(15 * s.scale, 0, 4 * s.scale, 0, 2 * Math.PI);
+ ctx.strokeStyle = s.lineColor;
+ ctx.lineWidth = 2 * s.scale;
+ ctx.stroke();
+ ctx.restore();
+ };
+
+ level.customTopLayer = () => {
+ //boost chute for lack of a better name
+ ctx.fillStyle = "rgba(60,60,60,0.9)";
+ ctx.fillRect(-3451, -4000, 202, 1500);
+ ctx.fillRect(2499, -170, 202, 1170);
+
+ ctx.fillStyle = "rgba(0,0,0,0.2)";
+ ctx.beginPath(); //basement
+ ctx.moveTo(2360, 1000);
+ ctx.lineTo(2120, 900);
+ ctx.lineTo(1500, 900);
+ ctx.lineTo(1500, 1500);
+ ctx.lineTo(3000, 1500);
+ ctx.lineTo(3000, 1000);
+ ctx.lineTo(2380, 1000);
+ ctx.lineTo(2870, 1500);
+ ctx.lineTo(1870, 1500);
+ ctx.lineTo(2360, 1000);
+ ctx.fill();
+ // ctx.beginPath(); //exit
+ // ctx.moveTo(1600, -6000);
+ // ctx.lineTo(1600, -5000);
+ // ctx.lineTo(3000, -5000);
+ // ctx.lineTo(3000, -6000);
+ // ctx.lineTo(2310, -6000);
+ // ctx.lineTo(2600, -5000);
+ // ctx.lineTo(2000, -5000);
+ // ctx.lineTo(2290, -6000);
+ // ctx.lineTo(1600, -6000);
+ // ctx.fill();
+
+ ctx.fillStyle = "rgba(0,0,0,0.3)";
+ ctx.fillRect(1600, -1000, 1400, 830);
+ ctx.fillRect(1600, -170, 520, 170);
+ ctx.fillRect(-1300, -200, 2200, 200); //statue base
+ ctx.fillRect(-800, -400, 1200, 200);
+ ctx.fillRect(-500, -700, 600, 300);
+ //ctx.fillRect(-4000, -6000, 2000, 1000); //left side
+ ctx.fillRect(-4000, -2500, 2000, 2500);
+ };
+
+ level.setPosToSpawn(1810, 1450);
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.x = 2700;
+ level.exit.y = -4030;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+ level.defaultZoom = 3500
+ simulation.zoomTransition(level.defaultZoom)
+
+ // powerUps.spawnStartingPowerUps(1475, -1175);
+ spawn.debris(2750, 1500, 200, 4); //16 debris per level
+ spawn.debris(1770, -350, 120, 4); //16 debris per level
+ spawn.debris(-3200, 0, 1000, 6); //16 debris per level
+
+ //boundaries
+ spawn.mapRect(-4100, 1500, 7200, 100); //base floor
+ spawn.mapRect(3000, -4000, 100, 5600); //right barrier
+ spawn.mapRect(-4100, -4000, 100, 5600); //left barrier
+ //spawn.mapRect(1600, -10000, 1500, 4000); //upper right wall
+ //spawn.mapRect(-4100, -10000, 2100, 4000); //upper left wall
+ spawn.mapRect(1600, -4000, 1500, 3000); //right wall
+ spawn.mapRect(-4100, 0, 5600, 1550); //floor
+
+ //starting room
+ spawn.mapRect(1500, 0, 700, 900);
+ spawn.mapRect(2120, -170, 380, 1170);
+ spawn.mapRect(2700, -170, 400, 1170);
+ //spawn.mapVertex(2296, 400, "0 0 0 1200 300 1200 400 0");
+ //spawn.mapVertex(2904, 400, "0 0 0 1200 -300 1200 -400 0");
+
+ //left area
+ spawn.mapRect(-3500, -300, 300, 400); //floor 1
+ spawn.mapRect(-3900, -600, 300, 100);
+ spawn.mapRect(-3500, -900, 300, 100);
+ spawn.mapRect(-3100, -1150, 1000, 150); //floor 2
+ spawn.mapRect(-2200, -2600, 200, 1600);
+ spawn.mapRect(-2700, -1450, 300, 100);
+ spawn.mapRect(-3100, -1750, 300, 100);
+ spawn.mapRect(-3500, -2050, 300, 100);
+ spawn.mapRect(-4100, -4000, 650, 1500); //floor 3
+ spawn.mapRect(-3250, -4000, 1250, 1500);
+
+ //statue base
+ spawn.mapRect(-700, -900, 1000, 200); //top
+ //left
+ spawn.mapRect(-700, -900, 200, 500);
+ spawn.mapRect(-1000, -600, 500, 200);
+ spawn.mapRect(-1000, -600, 200, 400);
+ spawn.mapRect(-1300, -300, 500, 100);
+ //right
+ spawn.mapRect(100, -900, 200, 500);
+ spawn.mapRect(100, -600, 500, 200);
+ spawn.mapRect(400, -600, 200, 400);
+ spawn.mapRect(400, -300, 500, 100);
+
+ hangingNGON(-1900, -4000, 1, 1000, 1, false, {
+ density: 0.001, //default density is 0.001
+ friction: 0.0001,
+ frictionAir: 0.001,
+ frictionStatic: 0,
+ restitution: 0,
+ isNotHoldable: true
+ });
+ hangingNGON(1900, -4600, 0.2, 300, 0.0005, false, {
+ density: 0.00005, //default density is 0.001
+ friction: 0.0001,
+ frictionAir: 0.003,
+ frictionStatic: 0,
+ restitution: 1,
+ isNotHoldable: true
+ });
+
+ // // Never gonna give you up
+ // spawn.bodyRect(-8000, -10100, 15, 100);
+ // // Never gonna let you down
+ // spawn.bodyRect(-7915, -10100, 15, 100);
+ // // Never gonna run around and desert you
+ // body[body.length] = Bodies.polygon(-7950, -10025, 0, 25, { //circle
+ // friction: 0.05,
+ // frictionAir: 0.001
+ // });
+ // // Never gonna make you cry
+ // spawn.bodyRect(6985, -10100, 15, 100);
+ // // Never gonna say goodbye
+ // spawn.bodyRect(6900, -10100, 15, 100);
+ // // Never gonna tell a lie and hurt you
+ // body[body.length] = Bodies.polygon(6950, -10025, 0, 25, { //circle
+ // friction: 0.05,
+ // frictionAir: 0.001
+ // });
+
+ //pile of blocks
+ spawn.bodyRect(1920, -400, 200, 400)
+ spawn.bodyRect(1720, -250, 200, 250)
+ spawn.bodyRect(1770, -300, 150, 50)
+ spawn.bodyRect(2120, -280, 100, 100)
+ spawn.bodyRect(1990, -500, 100, 100)
+
+ //doors under statue
+ spawn.bodyRect(850, -50, 50, 50)
+ spawn.bodyRect(850, -100, 50, 50)
+ spawn.bodyRect(850, -150, 50, 50)
+ spawn.bodyRect(850, -200, 50, 50)
+ spawn.bodyRect(-1300, -50, 50, 50)
+ spawn.bodyRect(-1300, -100, 50, 50)
+ spawn.bodyRect(-1300, -150, 50, 50)
+ spawn.bodyRect(-1300, -200, 50, 50)
+
+ // on the statue base
+ spawn.randomMob(700 + Math.random() * 100, -500 + Math.random() * 100, 1);
+ spawn.randomMob(400 + Math.random() * 100, -800 + Math.random() * 100, 0.4);
+ spawn.randomMob(100 + Math.random() * 100, -1100 + Math.random() * 100, -0.2);
+ spawn.randomGroup(-200, -1400, -0.4);
+ spawn.randomMob(-600 + Math.random() * 100, -1100 + Math.random() * 100, -0.2);
+ spawn.randomMob(-900 + Math.random() * 100, -800 + Math.random() * 100, 0.4);
+ spawn.randomMob(-1200 + Math.random() * 100, -500 + Math.random() * 100, 1);
+
+ //in the statue base
+ spawn.randomSmallMob(400 + Math.random() * 300, -150 + Math.random() * 100, 0.2);
+ spawn.randomSmallMob(-1100 + Math.random() * 300, -150 + Math.random() * 100, 0.2);
+
+ //bottom left
+ spawn.randomMob(-2600 + Math.random() * 300, -700 + Math.random() * 300, 0.6);
+ spawn.randomSmallMob(-3000 + Math.random() * 300, -400 + Math.random() * 300, 0.2);
+ spawn.randomSmallMob(-3000 + Math.random() * 300, -400 + Math.random() * 300, 0);
+ spawn.randomMob(-3900 + Math.random() * 100, -200 + Math.random() * 100, 0.6);
+ spawn.randomMob(-3400 + Math.random() * 100, -400, 0.4);
+ spawn.randomSmallMob(-3800 + Math.random() * 100, -700, -0.4);
+ spawn.randomMob(-3400 + Math.random() * 100, -1000, 0.6);
+ spawn.randomMob(-3000 + Math.random() * 100, -1850, 0);
+ spawn.randomGroup(-2700, -2000, 0.4);
+
+ //top left
+ spawn.randomSmallMob(-3800, -5800, -0.2);
+ spawn.randomSmallMob(-2400, -5200, 0.2);
+
+ //top right
+ spawn.randomGroup(2000, -5700, 0.6);
+
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ let bosses = ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "laserBoss", "growBossCulture"];
+ let abc = Math.random();
+ if (simulation.difficulty > 3) {
+ if (abc < 0.6) {
+ spawn.randomLevelBoss(-1500 + Math.random() * 250, -1100 + Math.random() * 200, bosses);
+ } else if (abc < 0.85) {
+ spawn.laserBoss(-350 + Math.random() * 300, -600 + Math.random() * 200);
+ } else {
+ spawn.randomLevelBoss(850 + Math.random() * 250, -1100 + Math.random() * 200, bosses);
+ }
+ }
+ spawn.secondaryBossChance(850 + Math.random() * 250, -1100 + Math.random() * 200)
+
+ //draw leg for statue
+ function statueLeg(shift, color) {
+ ctx.save();
+ ctx.translate(shift, shift);
+ //front leg
+ let stroke = color;
+ ctx.beginPath();
+ ctx.moveTo((s.h.x + shift) * s.scale, (s.h.y + shift) * s.scale);
+ ctx.lineTo((s.k.x + 2 * shift) * s.scale, (s.k.y + shift) * s.scale);
+ ctx.lineTo((s.f.x + shift) * s.scale, (s.f.y + shift) * s.scale);
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = 7 * s.scale;
+ ctx.stroke();
+ //toe lines
+ ctx.beginPath();
+ ctx.moveTo((s.f.x + shift) * s.scale, (s.f.y + shift) * s.scale);
+ ctx.lineTo((s.f.x - 15 + shift) * s.scale, (s.f.y + 5 + shift) * s.scale);
+ ctx.moveTo((s.f.x + shift) * s.scale, (s.f.y + shift) * s.scale);
+ ctx.lineTo((s.f.x + 15 + shift) * s.scale, (s.f.y + 5 + shift) * s.scale);
+ ctx.lineWidth = 4 * s.scale;
+ ctx.stroke();
+ //hip joint
+ ctx.beginPath();
+ ctx.arc((s.h.x + shift) * s.scale, (s.h.y + shift) * s.scale, 11 * s.scale, 0, 2 * Math.PI);
+ //knee joint
+ ctx.moveTo((s.k.x + 7 + 2 * shift) * s.scale, (s.k.y + shift) * s.scale);
+ ctx.arc((s.k.x + 2 * shift) * s.scale, (s.k.y + shift) * s.scale, 7 * s.scale, 0, 2 * Math.PI);
+ //foot joint
+ ctx.moveTo((s.f.x + 6 + shift) * s.scale, (s.f.y + shift) * s.scale);
+ ctx.arc((s.f.x + shift) * s.scale, (s.f.y + shift) * s.scale, 6 * s.scale, 0, 2 * Math.PI);
+ ctx.fillStyle = s.fillColor;
+ ctx.fill();
+ ctx.lineWidth = 2 * s.scale;
+ ctx.stroke();
+ ctx.restore();
+ }
+
+ // | | | | |
+ // n - g o n
+ //when s = 1 (scale), it's 3408 long and 800 tall (height of g)
+ function hangingNGON(x, y, s, height, stiffness, pin, properties) {
+ //makes a compound part of 3 bodyVertex parts
+ function compound3Parts(x1, y1, v1, x2, y2, v2, x3, y3, v3, properties) {
+ const part1 = Matter.Bodies.fromVertices(x1, y1, Vertices.fromPath(v1), properties);
+ const part2 = Matter.Bodies.fromVertices(x2, y2, Vertices.fromPath(v2), properties);
+ const part3 = Matter.Bodies.fromVertices(x3, y3, Vertices.fromPath(v3), properties);
+ const compoundParts = Body.create({
+ parts: [part1, part2, part3],
+ });
+ Composite.add(engine.world, [compoundParts]);
+ needGravity[needGravity.length] = compoundParts;
+ composite[composite.length] = compoundParts;
+ body[body.length] = part1;
+ body[body.length] = part2;
+ body[body.length] = part3;
+ setTimeout(function () {
+ compoundParts.collisionFilter.category = cat.body;
+ compoundParts.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map
+ }, 1000);
+ }
+
+ //for attaching the block to a point
+ function addConstraint(x, y, px, py, stiff, body, pin = false) {
+ if (pin) {
+ map[map.length] = Bodies.polygon(x, y, 0, 15); //circle above
+ }
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: x,
+ y: y
+ },
+ bodyB: body,
+ pointB: {
+ x: px,
+ y: py
+ },
+ stiffness: stiff
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ }
+
+ //I SINCERELY APOLOGIZE FOR THE ILLEGIBLE BLOCKS OF STRING CONCATENATION
+ //s is scale
+
+ //n
+ compound3Parts(
+ x + 100 * s,
+ y + 310 * s,
+ ("0 0 " + 200 * s + " 0 " + 200 * s + " " + 620 * s + " 0 " + 620 * s),
+ x + 300 * s,
+ y + 160 * s,
+ (200 * s + " " + 40 * s + " " + 400 * s + " " + 40 * s + " " + 400 * s + " " + 280 * s + " " + 200 * s + " " + 280 * s),
+ x + 499 * s,
+ y + 333.3 * s,
+ (400 * s + " " + 40 * s + " " + 540 * s + " " + 40 * s + " " + 600 * s + " " + 100 * s + " " + 600 * s + " " + 620 * s + " " + 400 * s + " " + 620 * s + " " + 400 * s + " " + 280 * s),
+ properties
+ );
+ addConstraint(x + 300 * s, y - height, 0, -10 * s, stiffness, composite[composite.length - 1], pin);
+
+ //-
+ spawn.bodyRect(x + 800 * s, y + 250 * s, 200 * s, 100 * s, 1, properties);
+ body[body.length - 1].frictionAir = 0.05 //friction to make jump easier
+ addConstraint(x + 900 * s, y - height, 0, -30 * s, stiffness, body[body.length - 1], pin);
+
+ //g
+ compound3Parts(
+ x + 1400 * s,
+ y + 300 * s,
+ ("0 0 " + 250 * s + " 0 " + 425 * s + " " + 175 * s + " " + 425 * s + " " + 450 * s + " " + 275 * s + " " + 600 * s + " 0 " + 600 * s + " " + -175 * s + " " + 425 * s + " " + -175 * s + " " + 175 * s),
+ x + 1636 * s,
+ y + 633 * s,
+ (425 * s + " " + 450 * s + " " + 425 * s + " " + 750 * s + " " + 375 * s + " " + 800 * s + " " + 275 * s + " " + 675 * s + " " + 275 * s + " " + 600 * s),
+ x + 1398 * s,
+ y + 737 * s,
+ (375 * s + " " + 800 * s + " " + -75 * s + " " + 800 * s + " " + -75 * s + " " + 675 * s + " " + 275 * s + " " + 675 * s),
+ properties
+ );
+ addConstraint(x + 1500 * s, y - height, 0, -15 * s, stiffness, composite[composite.length - 1], pin);
+
+ //o
+ spawn.bodyVertex(
+ x + 2300 * s,
+ y + 300 * s,
+ ("0 0 " + 250 * s + " 0 " + 425 * s + " " + 175 * s + " " + 425 * s + " " + 425 * s + " " + 250 * s + " " + 600 * s + " 0 " + 600 * s + " " + -175 * s + " " + 425 * s + " " + -175 * s + " " + 175 * s),
+ properties
+ );
+ addConstraint(x + 2300 * s, y - height, 0, -10 * s, stiffness, body[body.length - 1], pin);
+
+ //n
+ compound3Parts(
+ x + 2900 * s,
+ y + 310 * s,
+ ("0 0 " + 200 * s + " 0 " + 200 * s + " " + 620 * s + " 0 " + 620 * s),
+ x + 3100 * s,
+ y + 160 * s,
+ (200 * s + " " + 40 * s + " " + 400 * s + " " + 40 * s + " " + 400 * s + " " + 280 * s + " " + 200 * s + " " + 280 * s),
+ x + 3300 * s,
+ y + 333.3 * s,
+ (400 * s + " " + 40 * s + " " + 540 * s + " " + 40 * s + " " + 600 * s + " " + 100 * s + " " + 600 * s + " " + 620 * s + " " + 400 * s + " " + 620 * s + " " + 400 * s + " " + 280 * s),
+ properties
+ );
+ addConstraint(x + 3100 * s, y - height, 0, -10 * s, stiffness, composite[composite.length - 1], pin);
+ }
+ },
+ tunnel() { // by Scarlettt
+ simulation.makeTextLog(`
tunnel by
Scarlettt `);
+
+ level.custom = () => {
+ level.exit.drawAndCheck();
+
+ //enter
+ ctx.beginPath();
+ ctx.moveTo(level.enter.x, level.enter.y + 30);
+ ctx.lineTo(level.enter.x, level.enter.y - 80);
+ ctx.bezierCurveTo(level.enter.x, level.enter.y - 170, level.enter.x + 100, level.enter.y - 170, level.enter.x + 100, level.enter.y - 80);
+ ctx.lineTo(level.enter.x + 100, level.enter.y + 30);
+ ctx.lineTo(level.enter.x, level.enter.y + 30);
+ ctx.fillStyle = "#013";
+ ctx.fill();
+
+ //exit
+ ctx.beginPath();
+ ctx.moveTo(level.exit.x, level.exit.y + 30);
+ ctx.lineTo(level.exit.x, level.exit.y - 80);
+ ctx.bezierCurveTo(level.exit.x, level.exit.y - 170, level.exit.x + 100, level.exit.y - 170, level.exit.x + 100, level.exit.y - 80);
+ ctx.lineTo(level.exit.x + 100, level.exit.y + 30);
+ ctx.lineTo(level.exit.x, level.exit.y + 30);
+ ctx.fillStyle = "#9ff";
+ ctx.fill();
+
+ // hiding rooms in path to second floor
+ ctx.fillStyle = "#322";
+ ctx.fillRect(3750, -1650, 3500, 350);
+
+ // prevent the user from getting into the secreter room without defeating all mobs
+ if (m.pos.x > 1500 && m.pos.x < 2500 && m.pos.y > -4000 && m.pos.y < -3500 && mob.reduce((a, i) => {
+ return a || ((Math.sqrt((i.position.x - 3600) * (i.position.x - 3600) + (i.position.y + 3600) * (i.position.y + 3600)) < 20000) && i.isDropPowerUp);
+ }, false) && !emergencyActivated) {
+ Matter.Body.setPosition(player, {
+ x: 2800,
+ y: m.pos.y
+ });
+ }
+
+ button.query();
+ isButtonTapped = isButtonTapped || !button.isUp;
+ hazard.level(!isButtonTapped);
+ if (Matter.Query.region([player], hazard).length) m.energy -= 0.001;
+
+ buttonSec.query();
+ buttonSec.draw();
+ if (!buttonSec.isUp && !hasSecretButton) {
+ for (var i = 0; i < 5; i++) {
+ powerUps.spawn(3614, -3700, "ammo");
+ }
+ hasSecretButton = true;
+ }
+ buttonThird.query();
+ buttonThird.draw();
+ if (!buttonThird.isUp && !hasSecretButton2) {
+ for (var i = 0; i < 1; i++) powerUps.spawn(1614, -3700, "research");
+ hasSecretButton2 = true;
+ }
+ if (!buttonSec.isUp) {
+ secretAnimTrans += 2;
+ secretAnimTime = 1;
+ secretAnimTrans = Math.max(0, Math.min(secretAnimTrans, 60));
+ } else {
+ secretAnimTrans--;
+ if (secretAnimTime) secretAnimTrans += 3;
+ secretAnimTrans = Math.min(60, Math.max(secretAnimTrans, 0));
+ }
+ if (secretAnimTime > 0) {
+ secretAnimTime++;
+ if (secretAnimTime > 150) secretAnimTime = 0;
+ }
+
+ if (emergencyActivated || !buttonThird.isUp) {
+ secretAnimTrans2 += 2;
+ secretAnimTime2 = 1;
+ secretAnimTrans2 = Math.max(0, Math.min(secretAnimTrans2, 60));
+ } else {
+ secretAnimTrans2--;
+ if (secretAnimTime2) secretAnimTrans2 += 3;
+ secretAnimTrans2 = Math.min(60, Math.max(secretAnimTrans2, 0));
+ }
+ if (secretAnimTime2 > 0) {
+ secretAnimTime2++;
+ if (secretAnimTime2 > 150) secretAnimTime2 = 0;
+ }
+
+
+
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 200, 0, 2 * Math.PI);
+ ctx.fillStyle = "#ff25";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 400, 0, 2 * Math.PI);
+ ctx.fillStyle = "#ff22";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 700, 0, 2 * Math.PI);
+ ctx.fillStyle = "#ff21";
+ ctx.fill();
+ elevator.move();
+ elevator.drawTrack();
+ };
+ level.customTopLayer = () => {
+ hazard.query();
+ secretHazard.level(emergencyActivated);
+ secretHazard.query();
+ button.draw();
+
+ // Fire damage
+ let isInRange = flames.reduce((a, i) => a || Math.sqrt((m.pos.x - i[0]) * (m.pos.x - i[0]) + (m.pos.y + 90 - i[1]) * (m.pos.y + 90 - i[1])) < 50, false);
+
+ if (isInRange) {
+ fireDmgLevel++;
+ fireDmgLevel = Math.min(fireDmgLevel, 100);
+ } else {
+ fireDmgLevel--;
+ fireDmgLevel = Math.max(fireDmgLevel, -8);
+ }
+
+ if (fireDmgLevel > -8) {
+ ctx.fillStyle = "#fa0b";
+ ctx.fillRect(m.pos.x - 50, m.pos.y - 100, Math.min(fireDmgLevel * 12.5 + 100, 100), 15);
+ }
+
+ if (fireDmgLevel > 0) {
+ ctx.fillStyle = "#f00c";
+ ctx.fillRect(m.pos.x - 50, m.pos.y - 100, fireDmgLevel, 15);
+
+ m.damage(0.001 * (1.5 * isInRange + 1));
+
+ drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 + 1);
+ drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 + 1);
+ drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 + 1);
+ drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 - 1);
+ drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 - 1);
+ drawFlame(m.pos.x, m.pos.y + 90, "#d40", Math.PI / 2 - 1);
+ drawFlame(m.pos.x, m.pos.y + 90, "#f70", Math.PI / 2);
+ drawFlame(m.pos.x, m.pos.y + 90, "#f70", Math.PI / 2);
+ drawFlame(m.pos.x, m.pos.y + 90, "#f70", Math.PI / 2);
+ }
+
+ for (let j = 0; j < 5; j++) {
+ drawFlame(1130 + j * 10, -1700)
+ for (let i = 0; i < 7; i++) drawFlame(2550 + i * 200, -2800);
+ for (let i = 0; i < 10; i++) drawFlame(2800 + i * 500, -1650);
+ for (let i = 0; i < 9; i++) drawFlame(1595 + i * 95, -3860);
+ drawFlame(4850, -1300);
+ drawFlame(6350, -1300);
+ }
+ ctx.fillStyle = "#541";
+ for (let i = 0; i < 9; i++) {
+ ctx.fillRect(1592 + i * 95, -3860, 6, 70);
+ }
+
+ if (m.pos.x > 1500 && m.pos.x < 3750 && m.pos.y > -5000 && m.pos.y < -3300) {
+ secretRoomTrans -= 5;
+ secretRoomTrans = Math.max(secretRoomTrans, 85);
+ } else {
+ secretRoomTrans += 5;
+ secretRoomTrans = Math.min(secretRoomTrans, 250);
+ }
+
+
+ let hasMob = mob.reduce((a, i) => {
+ return a || ((Math.sqrt((i.position.x - 3600) * (i.position.x - 3600) + (i.position.y + 3600) * (i.position.y + 3600)) < 20000) && i.isDropPowerUp);
+ }, false) && !emergencyActivated;
+
+ door.isClosing = hasMob;
+
+ door.openClose();
+ ctx.fillStyle = "#444444" + secretRoomTrans.toString(16);
+ ctx.fillRect(1480, -5000, 2270, 1710);
+ if (hasMob) {
+ ctx.fillStyle = "#444";
+ ctx.fillRect(1480, -5000, 1070, 1710);
+ }
+
+ if (secretAnimTrans > 0) {
+ drawProject([3614, -3530], [2900, -3900], [3400, -3600], secretAnimTrans, 60);
+ if (secretAnimTrans >= 42) {
+ ctx.font = "27px monospace";
+ ctx.textAlign = "start"
+ ctx.fillStyle = "#00ffff" + Math.floor((secretAnimTrans - 40) * 12.75).toString(16);
+ ctx.fillText("Waste Discharge Interruption:", 2910, -3870);
+ ctx.fillText("Owner 'Scarlet' not found", 2910, -3830);
+ ctx.fillText("Detected user: 'm'", 2910, -3790);
+ ctx.fillStyle = (hasMob ? "#ff6644" : "#ffff44") + Math.floor((secretAnimTrans - 40) * 12.75).toString(16);
+ ctx.fillText(hasMob ? "AREA HAS MOBS." : "Area clear.", 2910, -3710);
+ ctx.fillText(hasMob ? "'openDoor' failed." : "'openDoor' complete.", 2910, -3670);
+ ctx.strokeStyle = "#00ff00" + Math.floor((secretAnimTrans - 40) * 6).toString(16);
+ ctx.beginPath();
+ ctx.arc(3300, -3730, 60, 0, 2 * Math.PI);
+ ctx.stroke();
+ ctx.arc(3330, -3730, 8, 0, 2 * Math.PI);
+ ctx.lineWidth = 4;
+ ctx.stroke();
+ ctx.textAlign = "center";
+ ctx.fillStyle = "#00ffff" + Math.floor((secretAnimTrans - 40) * 12.75).toString(16);
+ ctx.font = "30px monospace";
+ ctx.fillText("n-gon inc", 3300, -3630);
+
+ ctx.font = "25px Arial";
+ }
+ }
+ if (secretAnimTrans2 > 0) {
+ drawProject([1614, -3530], [2050, -3900], [1550, -3600], secretAnimTrans2, 60);
+ if (secretAnimTrans2 >= 42) {
+ ctx.font = "27px monospace";
+ ctx.textAlign = "start";
+ ctx.fillStyle = "#00ffff" + Math.floor((secretAnimTrans2 - 40) * 12.75).toString(16);
+ ctx.fillText("SECURITY BREACH DETECTED", 1560, -3870);
+ ctx.fillText("Entity name: m", 1560, -3830);
+ ctx.fillStyle = (tech.totalCount < 25 ? (tech.totalCount < 10 ? "#ffff44" : "#22ff22") : "#ff6644") + Math.floor((secretAnimTrans2 - 40) * 12.75).toString(16);
+ ctx.fillText("Threat level: " + (tech.totalCount < 25 ? (tech.totalCount < 10 ? "Low" : "Medium") : "HIGH"), 1560, -3790);
+ if (tech.totalCount >= 15) ctx.fillText("PROCEDURE ACTIVATED", 1560, -3750);
+ ctx.strokeStyle = "#00ff00" + Math.floor((secretAnimTrans2 - 40) * 6).toString(16);
+ ctx.beginPath();
+ ctx.arc(1950, -3730, 60, 0, 2 * Math.PI);
+ ctx.stroke();
+ ctx.arc(1980, -3730, 8, 0, 2 * Math.PI);
+ ctx.lineWidth = 4;
+ ctx.stroke();
+ ctx.textAlign = "center";
+ ctx.fillStyle = "#00ffff" + Math.floor((secretAnimTrans2 - 40) * 12.75).toString(16);
+ ctx.font = "30px monospace";
+ ctx.fillText("n-gon inc", 1950, -3630);
+
+ ctx.font = "25px Arial";
+ if (secretAnimTrans2 >= 60) {
+ if (!emergencyActivated && tech.totalCount >= 10) {
+ for (let i = 0; i < 5; i++) {
+ spawn.exploder(1614, -3900);
+ if (tech.totalCount >= 25) spawn.randomMob(1614, -3900, Infinity);
+ }
+ emergencyActivated = true;
+ }
+ }
+ }
+ }
+ };
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 8500;
+ level.exit.y = 680;
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#123";
+ // powerUps.spawnStartingPowerUps(1475, -1175);
+ // spawn.debris(750, -2200, 3700, 16); //16 debris per level
+
+ // spawn blocks
+ spawn.mapRect(-100, 0, 1050, 100);
+ spawn.mapRect(900, -300, 50, 300);
+ spawn.mapRect(700, -300, 50, 200);
+
+ // first room
+ spawn.mapRect(-100, -350, 850, 50);
+ spawn.mapRect(900, -350, 850, 50);
+ spawn.mapRect(-100, -1550, 50, 1200);
+ spawn.mapRect(1700, -1550, 50, 1200);
+ spawn.mapRect(-100, -1550, 850, 50);
+ spawn.mapRect(900, -1550, 850, 50);
+ spawn.bodyRect(700, -400, 50, 50);
+ spawn.bodyRect(900, -400, 50, 50);
+
+ spawn.mapRect(500, -650, 650, 25);
+ spawn.mapRect(200, -1000, 200, 25);
+ spawn.mapRect(1250, -1000, 200, 25);
+ spawn.mapRect(600, -1300, 450, 25);
+
+ spawn.mapRect(700, -1650, 50, 100);
+ spawn.mapRect(900, -1650, 50, 100);
+
+
+ // pathway to second room
+ spawn.mapRect(950, -1650, 3050, 50);
+ spawn.mapRect(1100, -1700, 100, 50);
+
+ // second room
+ spawn.mapRect(0, -5000, 1500, 3000);
+ spawn.mapRect(1500, -2050, 300, 50);
+ spawn.mapRect(2000, -3100, 300, 1100);
+ spawn.mapRect(1500, -5000, 2250, 1000);
+ spawn.mapRect(1500, -3500, 1050, 225);
+ spawn.mapRect(4000, -5000, 500, 3000);
+ spawn.mapRect(3748, -5000, 252, 1550);
+
+ spawn.mapRect(1700, -2400, 300, 50);
+ spawn.mapRect(1500, -2750, 300, 50);
+
+ spawn.mapRect(2300, -3000, 1700, 50);
+ spawn.mapRect(2300, -2800, 1700, 800);
+ spawn.mapRect(2450, -3300, 1300, 100);
+
+ // secret room in second room
+ spawn.mapRect(2700, -3500, 1050, 50);
+ spawn.mapRect(2549, -5000, 1201, 1000);
+
+ const buttonSec = level.button(3550, -3500);
+ const buttonThird = level.button(1550, -3500);
+ let hasSecretButton = false,
+ hasSecretButton2 = false,
+ secretAnimTrans = 0,
+ secretAnimTime = 0,
+ secretAnimTrans2 = 0,
+ secretAnimTime2 = 0;
+ let emergencyActivated = false;
+
+ const door = level.door(2450, -4000, 100, 500, 490);
+ const secretHazard = level.hazard(1500, -4000, 1000, 510, 0.01);
+
+ // hazards
+ const button = level.button(3800, -3000);
+ const hazard = level.hazard(2300, -3090, 1700, 110, 0.005);
+ let isButtonTapped = false;
+
+ // if (b.inventory.length < 5) powerUps.spawn(3800, -3200, "gun");
+ powerUps.spawn(3900, -3100, "heal", true, null, 30);
+ powerUps.spawn(3900, -3100, "heal", true, null, 30);
+
+ // path to the third room
+ spawn.mapRect(2000, -1850, 50, 200);
+ spawn.mapRect(2200, -2000, 50, 200);
+ spawn.mapRect(2400, -1850, 50, 200);
+
+ spawn.mapRect(4200, -1650, 1300, 50);
+ spawn.mapRect(5700, -1650, 1300, 50);
+ spawn.mapRect(7200, -1650, 750, 50);
+
+ spawn.mapRect(3700, -1600, 50, 350);
+ spawn.mapRect(7250, -1600, 50, 350);
+ spawn.mapRect(3750, -1300, 3500, 50);
+ spawn.mapRect(4500, -2150, 3550, 50)
+
+ // third room
+ spawn.mapRect(7900, -1600, 50, 1000);
+ spawn.mapRect(8050, -3000, 50, 2400);
+ spawn.mapRect(7000, -600, 950, 50);
+ spawn.mapRect(8050, -600, 950, 50);
+ spawn.mapRect(7000, -600, 50, 1000);
+ spawn.mapRect(8950, -600, 50, 1000);
+ spawn.mapRect(7000, 400, 950, 50);
+ spawn.mapRect(8050, 400, 950, 50);
+ spawn.mapRect(7900, 400, 50, 300);
+ spawn.mapRect(7900, 700, 1000, 50);
+
+ const elevator = level.elevator(7962.5, 500, 75, 50, -1800)
+
+
+ // fire damage
+ const flames = [];
+ flames.push([1150, -1700], [1150, -1770]);
+ for (let i = 0; i < 10; i++) flames.push([2800 + i * 500, -1650], [2800 + i * 500, -1720]);
+ flames.push([4850, -1300], [6350, -1300], [4850, -1370], [6350, -1370]);
+
+ let fireDmgLevel = -8;
+
+ let secretRoomTrans = 250;
+
+ // mobs
+ let mobList1 = [
+ [500, -750],
+ [1150, -750],
+ [825, -1100],
+ [300, -1100],
+ [1350, -1100]
+ ];
+ while (mobList1.length > 5 - Math.sqrt(simulation.difficulty * 2.5) && mobList1.length) {
+ let rand = Math.floor(Math.random() * mobList1.length);
+ spawn[["hopper", "sneaker", "striker"][Math.floor(Math.random() * 3)]](mobList1[rand][0], mobList1[rand][1], 60 + Math.random() * 10);
+ mobList1.splice(rand, 1);
+ }
+
+ let hasLaser = spawn.pickList.includes("laser");
+ if (hasLaser) spawn.pickList.splice(spawn.pickList.indexOf("laser"), 1);
+ let mobList2 = [
+ [50, -1400],
+ [1600, -450],
+ [50, -450],
+ [1600, -1400]
+ ];
+ for (let i = 0; i < 10; i++) mobList2.push([2800 + i * 500, -1800]);
+ while (mobList2.length && mob.length < -1 + 16 * Math.log10(simulation.difficulty + 1)) {
+ let rand = Math.floor(Math.random() * mobList2.length);
+ spawn.randomMob(...mobList2[rand]);
+ mobList2.splice(rand, 1);
+ }
+
+ let groupList = ["spawn.randomGroup(8250, 575);",
+ `spawn.randomGroup(3200, -3700);
+ if (simulation.difficulty > 15)
+ spawn.randomGroup(3500, -3700, 0.3);`,
+ "spawn.randomGroup(7800, -1800, 0.5);"
+ ];
+ while (groupList.length > 0) {
+ let ind = Math.floor(Math.random() * groupList.length);
+ Function(groupList[ind])();
+ groupList.splice(ind, 1);
+ }
+ if (hasLaser) spawn.pickList.push("laser");
+
+ spawn.shieldingBoss(3900, -3200, 70);
+
+ let randomBoss = Math.floor(Math.random() * 2);
+ if (simulation.difficulty > 5) spawn[["shooterBoss", "launcherBoss"][randomBoss]](7500, -150, 100, false);
+ else spawn[["shooter", "launcher"][randomBoss]](7500, -150, 150);
+ spawn[["shooter", "launcher"][randomBoss]](8500, -150, 150);
+
+ // canvas stuff
+ function drawFlame(x, y, color = "#f81", angle = Math.PI / 2) {
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 3;
+ for (let i = 0; i < 3; i++) {
+ let randAng = (Math.random() - 0.5) * 2 + angle;
+ randLen = 30 + Math.random() * 10;
+
+ x = x + Math.cos(randAng) * randLen;
+ y = y - Math.sin(randAng) * randLen;
+ ctx.lineTo(x, y);
+ }
+ ctx.stroke();
+ }
+
+ function drawProject(startPos, endPos1, endPos2, tValue, tValueM) {
+ ctx.strokeStyle = "#003";
+ ctx.fillStyle = "#0055aa" + ('0' + (tValue * 60 / tValueM).toString(16)).slice(-2);
+
+ let inter = (tValueM - tValue) / tValueM;
+ let endpos1i = endPos1.map((i, j) => (startPos[j] - i) * inter),
+ endpos2i = endPos2.map((i, j) => (startPos[j] - i) * inter);
+
+ ctx.beginPath();
+ ctx.moveTo(endPos1[0] + endpos1i[0], endPos1[1] + endpos1i[1]);
+ ctx.lineTo(...startPos);
+ ctx.lineTo(endPos2[0] + endpos2i[0], endPos1[1] + endpos1i[1]);
+ ctx.fill();
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(endPos1[0] + endpos1i[0], endPos1[1] + endpos1i[1]);
+ ctx.lineTo(...startPos);
+ ctx.lineTo(endPos1[0] + endpos1i[0], endPos2[1] + endpos2i[1]);
+ ctx.fill();
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(endPos1[0] + endpos1i[0], endPos2[1] + endpos2i[1]);
+ ctx.lineTo(...startPos);
+ ctx.lineTo(endPos2[0] + endpos2i[0], endPos2[1] + endpos2i[1]);
+ ctx.fill();
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(endPos2[0] + endpos2i[0], endPos2[1] + endpos2i[1]);
+ ctx.lineTo(...startPos);
+ ctx.lineTo(endPos2[0] + endpos2i[0], endPos1[1] + endpos1i[1]);
+ ctx.fill();
+ ctx.stroke();
+
+ if (tValue >= tValueM * 2 / 3) {
+ ctx.fillStyle = "#0055aa" + ('0' + Math.floor((tValue - tValueM * 2 / 3) * 6.25 * 60 / tValueM).toString(16)).slice(-2);
+ ctx.strokeStyle = "#000033" + ('0' + Math.floor((tValue - tValueM * 2 / 3) * 12.75 * 60 / tValueM).toString(16)).slice(-2);
+ ctx.fillRect(endPos1[0], endPos1[1], endPos2[0] - endPos1[0], endPos2[1] - endPos1[1]);
+ ctx.shadowColor = "#00aaaa" + ('0' + Math.floor((tValue - tValueM * 2 / 3) * 12.75 * 60 / tValueM).toString(16)).slice(-2);
+ ctx.shadowBlur = 10;
+ ctx.strokeRect(endPos1[0], endPos1[1], endPos2[0] - endPos1[0], endPos2[1] - endPos1[1]);
+ ctx.shadowBlur = 0;
+ ctx.shadowColor = "#0000";
+ }
+ }
+ },
+ run() {
+ simulation.makeTextLog(`
run by
iNoobBoi `);
+
+ addPartToMap = (len) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually
+ map[len].collisionFilter.category = cat.map;
+ map[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(map[len], true); //make static
+ Composite.add(engine.world, map[len]);
+ }
+
+ anotherBoss = (x, y) => {
+ if (tech.isDuplicateMobs && Math.random() < tech.duplicationChance()) {
+ tech.isScaleMobsWithDuplication = true
+ spawn.randomLevelBoss(x, y, ["historyBoss"]);
+ tech.isScaleMobsWithDuplication = false
+ } else if (tech.isResearchBoss) {
+ if (powerUps.research.count > 2) {
+ powerUps.research.changeRerolls(-3)
+ simulation.makeTextLog(`
m .
research -= 3
${powerUps.research.count}`)
+ } else {
+ tech.addJunkTechToPool(0.49)
+ }
+ spawn.randomLevelBoss(x, y, ["historyBoss"]);
+ }
+ }
+
+ const climbPad = level.boost(8200, -200, 500);
+ var climbTime = false;
+ var climbGroup = 0;
+ var initialSpawn = false;
+ var endTime = false;
+
+ let runMobList = [
+ "hopper",
+ "slasher",
+ "striker",
+ "stabber",
+ "springer",
+ "pulsar",
+ "sneaker",
+ "spinner",
+ "grower",
+ "focuser",
+ "spawner",
+ ];
+
+ let removeList = [];
+
+ level.custom = () => {
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+
+ climbPad.query();
+
+ if (m.pos.x > 8000 && climbTime === false) {
+ spawn.mapRect(7800, -900, 200, 900);
+ addPartToMap(map.length - 1);
+ simulation.draw.setPaths();
+
+ simulation.makeTextLog(`
UNKNOWN : "Well done. Now climb."`, 600);
+ simulation.makeTextLog(`
UNKNOWN : "I left a gift at the top."`, 600);
+
+ climbTime = true;
+ } //toggles on a mapRect when player passes a certain area
+
+ if (m.pos.x > 9000 && endTime === false) {
+ simulation.makeTextLog("
UNKNOWN : \"Good luck. I hope you get out of here.\"", 600);
+ endTime = true;
+ }
+
+ for (i in mob) {
+ mob[i].damageReduction = 0;
+ Matter.Body.setVelocity(mob[i], {
+ x: mob[i].velocity.x * 0.97,
+ y: mob[i].velocity.y * 0.97
+ });
+ } //makes everything slow and immune
+ };
+
+ level.customTopLayer = () => {
+ ctx.fillStyle = "#888";
+
+ if (climbGroup === 0) {
+ //toggle on fillRect: 1
+ ctx.fillRect(8000, -900, 300, 100);
+ ctx.fillRect(8500, -1800, 300, 100);
+ ctx.fillRect(8300, -2700, 300, 100);
+ ctx.fillRect(8000, -3600, 300, 100);
+ ctx.fillRect(8200, -4500, 300, 100);
+ } else if (climbGroup === 1) {
+ //toggle on fillRect: 2
+ ctx.fillRect(8300, -1200, 300, 100);
+ ctx.fillRect(8500, -2100, 300, 100);
+ ctx.fillRect(8100, -3000, 300, 100);
+ ctx.fillRect(8000, -3900, 300, 100);
+ ctx.fillRect(8200, -4800, 300, 100);
+ } else if (climbGroup === 2) {
+ //toggle on fillRect: 0
+ ctx.fillRect(8500, -600, 300, 100);
+ ctx.fillRect(8100, -1500, 300, 100);
+ ctx.fillRect(8000, -2400, 300, 100);
+ ctx.fillRect(8500, -3300, 300, 100);
+ ctx.fillRect(8500, -4200, 300, 100);
+ }
+
+ if ((simulation.cycle % 120) === 0) {
+ for (var i = 0; i < map.length; i++) {
+ if (map[i].isRemove) {
+ Matter.Composite.remove(engine.world, map[i]);
+ map.splice(i, 1);
+ }
+ }
+
+ if (climbGroup === 0) {
+ //toggle on platforms: 0
+ spawn.mapRect(8000, -900, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8500, -1800, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8300, -2700, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8000, -3600, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8200, -4500, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+
+ climbGroup = 1;
+ } else if (climbGroup === 1) {
+ //toggle on platforms: 1
+ spawn.mapRect(8300, -1200, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8500, -2100, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8100, -3000, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8000, -3900, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8200, -4800, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+
+ climbGroup = 2;
+ } else if (climbGroup === 2) {
+ //toggle on platforms: 2
+ spawn.mapRect(8500, -600, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8100, -1500, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8000, -2400, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8500, -3300, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ spawn.mapRect(8500, -4200, 300, 100);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+
+ climbGroup = 0;
+ }
+
+ simulation.draw.setPaths(); //update map graphics
+ } //every 120 cycles, first deletes previous group, then cycles through one of 3 toggle groups
+ };
+
+ if (!initialSpawn) {
+ level.defaultZoom = 1300 //was 800 I changed this
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#dcdcde";
+ //Level
+ level.setPosToSpawn(-100, -1450);
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+
+ level.exit.x = 9300;
+ level.exit.y = -5130;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+
+ //Map
+ spawn.mapRect(-1400, -2200, 1700, 200);
+ spawn.mapRect(100, -2200, 200, 1000);
+ spawn.mapRect(-600, -1400, 8600, 200);
+ spawn.mapRect(-1400, -2200, 200, 1000);
+ spawn.mapRect(-2800, -1400, 1600, 200);
+ spawn.mapRect(-2800, -1400, 200, 1400);
+ spawn.mapRect(-2800, -200, 11800, 200);
+ spawn.mapRect(-900, -600, 600, 600);
+ spawn.mapRect(200, -800, 500, 100);
+ spawn.mapRect(1300, -1400, 200, 900);
+ spawn.mapRect(1300, -600, 500, 100);
+ spawn.mapRect(2300, -800, 200, 200);
+ spawn.mapRect(2900, -400, 100, 400);
+ spawn.mapRect(3200, -600, 100, 600);
+ spawn.mapRect(3500, -800, 100, 800);
+ spawn.mapRect(4400, -900, 500, 100);
+ spawn.mapRect(4400, -600, 500, 100);
+ spawn.mapRect(4800, -900, 100, 400);
+ spawn.mapRect(5300, -550, 600, 550);
+ spawn.mapRect(5600, -900, 300, 800);
+ spawn.mapRect(6300, -300, 1100, 300);
+ spawn.mapRect(6600, -400, 500, 200);
+ spawn.mapRect(6600, -800, 500, 100);
+ spawn.mapRect(7000, -1400, 100, 700);
+ spawn.mapRect(7800, -5900, 200, 5100);
+ spawn.mapRect(7800, -5900, 1900, 200);
+ spawn.mapRect(9500, -5900, 200, 1000);
+ spawn.mapRect(8800, -5100, 900, 200);
+ spawn.mapRect(8800, -5100, 200, 5100);
+
+ //Text
+ spawn.mapRect(400, -1600, 100, 10);
+ spawn.mapRect(400, -1600, 10, 100);
+ spawn.mapRect(490, -1600, 10, 40);
+ spawn.mapRect(400, -1570, 100, 10);
+ spawn.mapRect(400, -1540, 100, 10);
+ spawn.mapRect(490, -1540, 10, 40);
+
+ spawn.mapRect(600, -1600, 10, 100);
+ spawn.mapRect(600, -1510, 100, 10);
+ spawn.mapRect(690, -1600, 10, 100);
+
+ spawn.mapRect(800, -1600, 100, 10);
+ spawn.mapRect(800, -1600, 10, 100);
+ spawn.mapRect(890, -1600, 10, 100);
+
+ spawn.mapRect(0, 0, 1, 1); //dont ask why i have these
+ spawn.mapRect(1, 0, 1, 1); //dont ask why i have these
+ spawn.mapRect(0, 1, 1, 1); //dont ask why i have these
+ spawn.mapRect(1, 1, 1, 1); //dont ask why i have these
+ spawn.mapRect(-1, 0, 1, 1); //dont ask why i have these
+ spawn.mapRect(0, -1, 1, 1); //dont ask why i have these
+ spawn.mapRect(-1, -1, 1, 1); //dont ask why i have these
+ spawn.mapRect(1, -1, 1, 1); //dont ask why i have these
+ spawn.mapRect(-1, 1, 1, 1); //dont ask why i have these
+
+ //Mob Spawning
+ setTimeout(() => {
+ simulation.makeTextLog("
UNKNOWN : \"You cannot kill them.\"", 600);
+ }, 2000);
+
+ setTimeout(() => {
+ simulation.makeTextLog("
UNKNOWN : \"But I have slowed them down for you.\"", 600);
+ }, 6000);
+
+
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](200, -400);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](1800, -1000);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](3200, -1000);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](6200, -400);
+
+ if (simulation.difficulty > 10) {
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](1000, -400);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](2400, -400);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](4000, -400);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](6600, -1000);
+
+ setTimeout(() => {
+ simulation.makeTextLog("
UNKNOWN : \"Run.\"", 600);
+ }, 10000);
+ } //some of the mobs
+ if (simulation.difficulty > 20) {
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](1000, -1000);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](3100, -300);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](4200, -1000);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](7400, -800);
+
+ setTimeout(() => {
+ simulation.makeTextLog("
UNKNOWN : \"RUN!\"", 600);
+ }, 11000);
+ } //most of the mobs
+ if (simulation.difficulty > 30) {
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](200, -1000);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](3400, -300);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](5200, -800);
+ spawn[runMobList[Math.floor(Math.random() * runMobList.length)]](7500, -300);
+
+ setTimeout(() => {
+ simulation.makeTextLog("
UNKNOWN : \"GET OUT OF HERE.\"", 600);
+ }, 12000);
+ } //all the mobs
+
+ //Boss Spawning
+ if (simulation.difficulty > 5) {
+ spawn.randomLevelBoss(-2200, -700, ["powerUpBossBaby", "blockBoss", "revolutionBoss"]);
+
+ setTimeout(() => {
+ simulation.makeTextLog("
UNKNOWN : \"They are coming for you.\"", 600);
+ }, 14000);
+ }
+ anotherBoss(-1800, -700); //custom second boss spawn
+
+ //Blocks
+ spawn.bodyRect(1300, -500, 200, 100);
+ spawn.bodyRect(1400, -500, 200, 100);
+ spawn.bodyRect(1500, -500, 200, 100);
+
+ spawn.bodyRect(5700, -1200, 100, 100);
+ spawn.bodyRect(5700, -1100, 100, 100);
+ spawn.bodyRect(5700, -1000, 100, 100);
+
+ spawn.bodyRect(6800, -700, 100, 100);
+ spawn.bodyRect(6800, -600, 100, 100);
+ spawn.bodyRect(6800, -500, 100, 100);
+
+ spawn.debris(4400, -300, 500, 16);
+ spawn.debris(3300, -600, 200, 6);
+ spawn.debris(3000, -500, 20, 6);
+ spawn.debris(2300, -300, 200, 6);
+ spawn.debris(200, -300, 500, 16);
+
+ //Powerups
+ if (simulation.difficulty > 10) {
+ powerUps.spawn(1600, -700, "tech");
+ }
+ powerUps.spawnRandomPowerUp(1700, -700);
+
+ // if (simulation.difficulty > 20) {
+ // powerUps.spawn(4600, -700, "tech");
+ // }
+ powerUps.spawnRandomPowerUp(4700, -700);
+
+ // if (simulation.difficulty > 30) {
+ // powerUps.spawn(6800, -1000, "tech");
+ // }
+ powerUps.spawnRandomPowerUp(6900, -1000);
+
+ powerUps.spawn(9200, -5400, "tech");
+
+ if (simulation.difficulty > 10) {
+ powerUps.spawn(9200, -5500, "tech");
+ }
+ // if (simulation.difficulty > 20) {
+ // powerUps.spawn(9200, -5600, "tech");
+ // }
+ // if (simulation.difficulty > 30) {
+ // powerUps.spawn(9200, -5700, "tech");
+ // }
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ initialSpawn == true;
+ }
+ },
+ islands() {
+ simulation.makeTextLog(`
islands by
Richard0820 `);
+
+ const boost1 = level.boost(58500, -18264, 1300);
+ let portal2, portal3;
+ // const removeIndex1 = map.length - 1;
+ const drip1 = level.drip(59300, -18975, -18250, 100); // drip(x, yMin, yMax, period = 100, color = "hsla(160, 100%, 35%, 0.5)") {
+ const drip2 = level.drip(60000, -18953, -18250, 150);
+ const drip3 = level.drip(60905, -18652, -18250, 70);
+ const slimePit1 = level.hazard(58850, -18300, 2275, 100, 0.01); //hazard(x, y, width, height, damage = 0.003) spawn.mapRect(58850, -18300, 2275, 100);
+ const slimePit2 = level.hazard(74400, -18075, 350, 100, 0.01);
+ let isSpawnedBoss = false;
+ level.custom = () => {
+ level.exit.drawAndCheck();
+ boost1.query();
+ level.enter.draw();
+ drip1.draw();
+ drip2.draw();
+ drip3.draw();
+ // portal[2].query();
+ // portal[3].query();
+ // portal[0].draw();
+ // portal[1].draw();
+ // portal[2].draw();
+ // portal[3].draw();
+ portal2[2].query();
+ portal2[3].query();
+ portal2[0].draw();
+ portal2[1].draw();
+ portal2[2].draw();
+ portal2[3].draw();
+ portal3[2].query();
+ portal3[3].query();
+ portal3[0].draw();
+ portal3[1].draw();
+ portal3[2].draw();
+ portal3[3].draw();
+ };
+ level.customTopLayer = () => {
+ slimePit1.query();
+ slimePit2.query();
+ ctx.fillStyle = `rgba(68, 68, 68, ${Math.max(0.3, Math.min((-17650 - m.pos.y) / 100, 0.99))})`;
+ ctx.fillRect(58390, -17655, 1490, 740);
+ };
+ document.body.style.backgroundColor = "hsl(138, 3%, 74%)";
+ level.setPosToSpawn(57680, -18330);
+ level.exit.x = 76343;
+ level.exit.y = -18020;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 30);
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 30);
+ level.defaultZoom = 2000;
+ simulation.zoomTransition(level.defaultZoom);
+ // spawn.setSpawnList = [
+ // "hopper",
+ // "slasher",
+ // "striker",
+ // "stabber",
+ // "springer",
+ // "pulsar",
+ // "sneaker",
+ // "spinner",
+ // "grower",
+ // "focuser",
+ // "spawner",
+ // ];
+ spawn.mapRect(57800, -18550, 50, 100);
+ spawn.mapRect(57500, -18550, 50, 275);
+ spawn.mapRect(66900, -18675, 300, 200);
+ spawn.mapRect(66925, -19050, 125, 225);
+ spawn.mapRect(67825, -16975, 125, 100);
+ spawn.mapRect(74900, -18075, 225, 100);
+ spawn.mapRect(73925, -18225, 150, 275);
+ spawn.mapRect(76200, -18325, 50, 125);
+ spawn.mapRect(76525, -18325, 75, 400);
+ spawn.mapRect(61325, -18350, 50, 25);
+ spawn.mapRect(61450, -18425, 50, 25);
+ spawn.mapRect(61475, -18450, 25, 25);
+ spawn.mapRect(58725, -18350, 125, 50);
+ spawn.mapRect(58675, -18275, 50, 75);
+ spawn.mapRect(58600, -18275, 75, 75);
+ spawn.mapRect(58675, -18325, 50, 50);
+ spawn.mapRect(58250, -16925, 1825, 1050);
+ spawn.mapRect(57500, -18200, 4475, 550);
+ spawn.mapRect(61500, -18475, 475, 275);
+ spawn.mapRect(62175, -18575, 325, 400);
+ spawn.mapRect(62900, -18850, 525, 375);
+ spawn.mapRect(63900, -18925, 450, 400);
+ spawn.mapRect(64725, -19000, 625, 500);
+ spawn.mapRect(65825, -19050, 675, 400);
+ spawn.mapRect(66800, -18950, 400, 400);
+ spawn.mapRect(68775, -18850, 525, 400);
+ spawn.mapRect(67375, -16900, 1800, 1450);
+ spawn.mapRect(67375, -17475, 325, 575);
+ spawn.mapRect(68900, -17500, 250, 500);
+ spawn.mapRect(69425, -17050, 500, 475);
+ spawn.mapRect(70400, -17150, 425, 175);
+ spawn.mapRect(71175, -17325, 450, 325);
+ spawn.mapRect(72000, -17425, 325, 300);
+ spawn.mapRect(72725, -17450, 350, 275);
+ spawn.mapRect(70050, -18800, 550, 350);
+ spawn.mapRect(67750, -19400, 375, 1200);
+ spawn.mapRect(67750, -18200, 1425, 700);
+ spawn.mapRect(66800, -18550, 575, 1650);
+ spawn.mapRect(66800, -16900, 575, 1450);
+ spawn.mapRect(67350, -18175, 250, 750);
+ spawn.mapRect(71050, -18450, 725, 275);
+ spawn.mapRect(72100, -18150, 475, 200);
+ spawn.mapRect(73325, -17975, 3275, 475);
+ spawn.mapRect(73175, -17775, 150, 300);
+ spawn.mapRect(72975, -17675, 225, 250);
+ spawn.mapRect(76200, -18325, 400, 75);
+ spawn.mapRect(76525, -18250, 75, 275);
+ spawn.mapRect(76200, -18250, 50, 50);
+ spawn.mapRect(57500, -17675, 900, 1800);
+ spawn.mapRect(59875, -17675, 1975, 1800);
+ spawn.mapRect(57550, -18275, 225, 75);
+ spawn.mapRect(61375, -18375, 50, 50);
+ spawn.mapRect(61100, -18350, 75, 50);
+ spawn.mapRect(61175, -18325, 50, 25);
+ spawn.mapRect(61850, -16525, 250, 175);
+ spawn.mapRect(57500, -18500, 50, 325);
+ spawn.mapRect(57500, -18550, 350, 50);
+ spawn.mapRect(57800, -18500, 50, 50);
+ spawn.mapRect(61275, -18325, 375, 125);
+ spawn.mapRect(61425, -18400, 200, 75);
+ spawn.mapRect(62125, -18575, 125, 75);
+ spawn.mapRect(62250, -18200, 175, 125);
+ spawn.mapRect(62850, -18725, 100, 75);
+ spawn.mapRect(63075, -18550, 225, 225);
+ spawn.mapRect(62800, -18275, 75, 75);
+ spawn.mapRect(62500, -18475, 75, 50);
+ spawn.mapRect(63825, -18900, 150, 50);
+ spawn.mapRect(63950, -18575, 150, 125);
+ spawn.mapRect(64200, -18550, 100, 250);
+ spawn.mapRect(64925, -18525, 200, 275);
+ spawn.mapRect(64625, -18425, 75, 125);
+ spawn.mapRect(65225, -18675, 150, 175);
+ spawn.mapRect(65350, -18950, 75, 100);
+ spawn.mapRect(65950, -18575, 75, 150);
+ spawn.mapRect(66000, -18725, 225, 175);
+ spawn.mapRect(66275, -18675, 75, 125);
+ spawn.mapRect(66275, -18550, 75, 75);
+ spawn.mapRect(66150, -18550, 100, 50);
+ spawn.mapRect(66225, -18875, 25, 150);
+ spawn.mapRect(66200, -18750, 75, 25);
+ spawn.mapRect(66925, -19100, 125, 150);
+ spawn.mapRect(66000, -19100, 75, 50);
+ spawn.mapRect(65000, -19075, 100, 75);
+ spawn.mapRect(66750, -18625, 100, 100);
+ spawn.mapRect(68050, -18500, 350, 350);
+ spawn.mapRect(68125, -18975, 150, 475);
+ spawn.mapRect(69850, -18675, 150, 200);
+ spawn.mapRect(70000, -18625, 150, 50);
+ spawn.mapRect(68850, -18575, 325, 225);
+ spawn.mapRect(69100, -18400, 75, 100);
+ spawn.mapRect(70150, -18525, 125, 200);
+ spawn.mapRect(70425, -18525, 125, 200);
+ spawn.mapRect(70250, -18350, 175, 225);
+ spawn.mapRect(70325, -18475, 50, 150);
+ spawn.mapRect(70275, -18450, 150, 150);
+ spawn.mapRect(71175, -18250, 525, 250);
+ spawn.mapRect(71050, -18200, 150, 375);
+ spawn.mapRect(70925, -18300, 200, 250);
+ spawn.mapRect(71425, -18525, 175, 150);
+ spawn.mapRect(70225, -18950, 275, 250);
+ spawn.mapRect(70475, -17050, 225, 175);
+ spawn.mapRect(70625, -17250, 100, 150);
+ spawn.mapRect(71300, -17150, 200, 350);
+ spawn.mapRect(71100, -17250, 125, 100);
+ spawn.mapRect(71550, -17400, 150, 150);
+ spawn.mapRect(67675, -17150, 225, 300);
+ spawn.mapRect(68225, -17000, 100, 125);
+ spawn.mapRect(67900, -16975, 375, 100);
+ spawn.mapRect(68275, -16950, 150, 50);
+ spawn.bodyRect(76200, -18200, 50, 200);
+ spawn.mapRect(76200, -18000, 50, 25);
+ spawn.bodyRect(57800, -18450, 50, 175);
+ spawn.mapRect(68725, -17600, 300, 250);
+ spawn.mapRect(68625, -17550, 175, 100);
+ spawn.mapRect(68850, -17400, 150, 125);
+ spawn.mapRect(69325, -16900, 200, 225);
+ spawn.mapRect(69575, -16625, 175, 275);
+ spawn.mapRect(69850, -16875, 250, 200);
+ spawn.mapRect(69875, -16650, 150, 300);
+ spawn.mapRect(69825, -16800, 375, 325);
+ spawn.mapRect(69650, -16775, 325, 475);
+ spawn.mapRect(71975, -17325, 100, 125);
+ spawn.mapRect(72075, -17200, 150, 150);
+ spawn.mapRect(72275, -17350, 150, 150);
+ spawn.mapRect(72325, -17275, 150, 225);
+ spawn.mapRect(72225, -18050, 200, 225);
+ spawn.mapRect(71925, -18150, 250, 175);
+ spawn.mapRect(72075, -18275, 125, 175);
+ spawn.mapRect(72500, -18025, 125, 175);
+ spawn.mapRect(72400, -17975, 150, 175);
+ spawn.mapRect(73925, -18225, 350, 275);
+ spawn.mapRect(74750, -18125, 275, 175);
+ spawn.mapRect(74250, -18100, 150, 75);
+ spawn.mapRect(74275, -18050, 200, 75);
+ spawn.mapRect(73750, -18100, 275, 125);
+ spawn.mapRect(73075, -17475, 3525, 300);
+ spawn.mapRect(73275, -17600, 3325, 225);
+ spawn.mapRect(57775, -18250, 150, 50);
+ spawn.mapRect(57775, -18275, 75, 25);
+ spawn.mapRect(57925, -18225, 50, 25);
+ spawn.debris(68300, -17000, 3700, 16);
+ spawn.mapRect(62000, -16525, 100, 200);
+ spawn.mapRect(59125, -19125, 325, 200);
+ spawn.mapRect(59925, -19175, 350, 225);
+ spawn.mapRect(60800, -18850, 275, 200);
+ spawn.mapRect(75025, -18075, 200, 100);
+ spawn.mapRect(75225, -18025, 100, 50);
+ spawn.bodyRect(74300, -18150, 50, 25);
+ spawn.bodyRect(73850, -18150, 75, 75);
+ spawn.bodyRect(74700, -18000, 75, 50);
+ spawn.bodyRect(74250, -18325, 25, 25);
+ spawn.bodyRect(74275, -18325, 25, 25);
+ spawn.bodyRect(74275, -18325, 25, 25);
+ spawn.bodyRect(74300, -18325, 100, 25);
+ // portal = level.portal(
+ // {
+ // x: 58625,
+ // y: -16925,
+ // },
+ // 1.5 * Math.PI,
+ // {
+ // //right
+ // x: 58625,
+ // y: -17650,
+ // },
+ // 2.5 * Math.PI
+ // ); //right
+ portal2 = level.portal({
+ x: 61920,
+ y: -16525,
+ },
+ 1.5 * Math.PI, {
+ //right
+ x: 58400,
+ y: -17325,
+ },
+ 2 * Math.PI
+ );
+ portal3 = level.portal({
+ x: 59865,
+ y: -17300,
+ },
+ 3 * Math.PI, {
+ //right
+ x: 60820,
+ y: -31130,
+ },
+ 2.5 * Math.PI
+ );
+
+ spawn.mapRect(60275, -32250, 975, 400);
+ spawn.mapRect(60375, -31925, 275, 225);
+ spawn.mapRect(61025, -31950, 175, 300);
+ spawn.mapRect(60825, -31725, 100, 350);
+ spawn.mapRect(60675, -31875, 200, 225);
+ spawn.mapRect(60225, -31950, 100, 725);
+ spawn.mapRect(60250, -31525, 250, 375);
+ spawn.mapRect(60675, -31475, 425, 350);
+ spawn.mapRect(60625, -32500, 225, 300);
+ spawn.mapRect(61025, -32325, 125, 175);
+ spawn.mapRect(60375, -32325, 175, 150);
+ spawn.mapRect(60250, -19075, 100, 100);
+ spawn.randomMob(59850, -18825, Infinity);
+ spawn.randomMob(62325, -18800, Infinity);
+ spawn.randomMob(61725, -18800, Infinity);
+ spawn.randomMob(63050, -19025, Infinity);
+ spawn.randomMob(64100, -19200, Infinity);
+ spawn.randomMob(64225, -19100, Infinity);
+ spawn.randomMob(64875, -19300, Infinity);
+ spawn.randomMob(65125, -19325, Infinity);
+ spawn.randomMob(65850, -19275, Infinity);
+ spawn.randomMob(66200, -19300, Infinity);
+ spawn.randomMob(65975, -19425, Infinity);
+ spawn.randomMob(67925, -19600, Infinity);
+ spawn.randomMob(66975, -19275, Infinity);
+ spawn.randomMob(67550, -18750, Infinity);
+ spawn.randomMob(69625, -17275, Infinity);
+ spawn.randomMob(70550, -17350, Infinity);
+ spawn.randomMob(71375, -17475, Infinity);
+ spawn.randomMob(72200, -17600, Infinity);
+ spawn.randomMob(73000, -18025, Infinity);
+ spawn.randomMob(73850, -18350, Infinity);
+ spawn.randomMob(75725, -18300, Infinity);
+ spawn.randomMob(75875, -18275, Infinity);
+ spawn.randomMob(75700, -18200, Infinity);
+ spawn.randomMob(75550, -18275, Infinity);
+ spawn.randomMob(75825, -18150, Infinity);
+ spawn.randomMob(75575, -18150, Infinity);
+ spawn.randomGroup(75575, -18150, 0);
+ level.chain(67250, -19325, 0, true, 14, 20);
+ spawn.mapRect(58725, -18300, 125, 100);
+ spawn.mapRect(61100, -18300, 175, 100);
+ spawn.mapRect(67175, -19375, 100, 100);
+ spawn.mapRect(59125, -19125, 325, 200);
+ spawn.mapRect(59925, -19175, 350, 225);
+ spawn.mapRect(60800, -18850, 275, 200);
+ spawn.mapRect(60850, -18725, 50, 200);
+ spawn.mapRect(60950, -18675, 50, 200);
+ spawn.mapRect(59975, -19025, 50, 250);
+ spawn.mapRect(60125, -19025, 50, 400);
+ spawn.mapRect(60075, -19025, 50, 450);
+ spawn.mapRect(59425, -19075, 100, 100);
+ spawn.mapRect(59175, -19000, 100, 225);
+ spawn.mapRect(59325, -19000, 75, 450);
+ spawn.mapRect(59050, -19000, 100, 100);
+ spawn.mapRect(61050, -18775, 100, 75);
+ spawn.mapRect(60725, -18850, 125, 125);
+ spawn.bodyRect(61850, -16525, 250, 175);
+ if (simulation.difficulty > 1) {
+ spawn.randomGroup(75575, -18150, 0);
+ spawn.randomLevelBoss(68450, -17300);
+ }
+ if (!isSpawnedBoss) {
+ isSpawnedBoss = true;
+ if (Math.random() < 0.33) {
+ for (
+ let i = 0, len = Math.min(simulation.difficulty / 20, 6); i < len;
+ ++i
+ )
+ spawn.bounceBoss(59025, -17325, 50, false);
+ } else if (Math.random() < 0.5) {
+ for (
+ let i = 0, len = Math.min(simulation.difficulty / 9, 8); i < len;
+ ++i
+ )
+ spawn.sprayBoss(59025, -17325, 50, false);
+ } else {
+ for (
+ let i = 0, len = Math.min(simulation.difficulty / 6, 10); i < len;
+ ++i
+ )
+ spawn.mineBoss(59025, -17325, 50, false);
+ }
+ powerUps.spawn(59352, -17115, "tech");
+ // for (let i = 0, len = 3 + simulation.difficulty / 20; i < len; ++i) spawn.mantisBoss(1487 + 300 * i, -1525, 35, false)
+ }
+ simulation.fallHeight = -15000;
+ powerUps.addResearchToLevel();
+ powerUps.spawn(3000, -230, "heal");
+ // level.difficultyIncrease(60)
+ },
+ temple() {
+ simulation.makeTextLog(`
temple by
Scar1337 `);
+
+ const V = Vector;
+ const Equation = (function () {
+ function Equation(a, b, c) {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ }
+ Equation.prototype.getXfromY = function (y) {
+ return (-this.b * y - this.c) / this.a;
+ }
+ Equation.prototype.getYfromX = function (x) {
+ return (-this.a * x - this.c) / this.b;
+ }
+ Equation.fromPoints = function (v1, v2) {
+ if (v1.x === v2.x) return new Equation(1, 0, -v1.x);
+ if (v1.y === v2.y) return new Equation(0, 1, -v1.y);
+ const d = (v2.y - v1.y) / (v2.x - v1.x);
+ return new Equation(-d, 1, d * v1.x - v1.y);
+ };
+ return Equation;
+ })();
+ const Rect = (function () {
+ function Rect(x, y, w, h) {
+ this.pos = {
+ x,
+ y
+ };
+ this.width = w;
+ this.height = h;
+ }
+ Rect.prototype.has = function ({
+ x,
+ y
+ }) {
+ return x >= this.pos.x && x <= this.pos.x + this.width &&
+ y >= this.pos.y && y <= this.pos.y + this.height;
+ }
+ Rect.prototype.hasLine = function (eq) {
+ const leftInter = eq.getYfromX(this.pos.x);
+ const rightInter = eq.getYfromX(this.pos.x + this.width);
+ const topInter = eq.getXfromY(this.pos.y);
+ return (leftInter >= this.pos.y && leftInter <= this.pos.y + this.height) ||
+ (rightInter >= this.pos.y && rightInter <= this.pos.y + this.height) ||
+ (topInter >= this.pos.x && topInter <= this.pos.x + this.width);
+ }
+ Rect.prototype.addToMap = function () {
+ spawn.mapRect(this.pos.x, this.pos.y, this.width, this.height);
+ }
+ Object.defineProperty(Rect.prototype, "midPos", {
+ get() {
+ return V.add(this.pos, {
+ x: this.width / 2,
+ y: this.height / 2
+ });
+ }
+ });
+ Rect.fromBounds = function (min, max) {
+ return new Rect(min.x, min.y, max.x - min.x, max.y - min.y);
+ }
+ Rect.prototype.isCollidingWith = function (other) {
+ const tc = {
+ p1: [this.pos.x, this.pos.y],
+ p2: [this.pos.x + this.width, this.pos.y + this.height]
+ };
+ const oc = {
+ p1: [other.pos.x, other.pos.y],
+ p2: [other.pos.x + other.width, other.pos.y + other.height]
+ };
+
+ // If one rectangle is on left side of other
+ if (tc.p1[0] >= oc.p2[0] || oc.p1[0] >= tc.p2[0])
+ return false;
+
+ // If one rectangle is above other
+ if (tc.p1[1] >= oc.p2[1] || oc.p1[1] >= tc.p2[1])
+ return false;
+
+ return true;
+ }
+ return Rect;
+ })();
+
+ function isInBound(bound) {
+ return bound.has(player.bounds.min) || bound.has(player.bounds.max);
+ }
+
+ function addWIMP(x, y) {
+ spawn.WIMP(x, y);
+ const me = mob[mob.length - 1];
+ me.isWIMP = true;
+ }
+
+ function relocateWIMPs(x, y) {
+ for (const i of mob) {
+ if (i.isWIMP) {
+ setPos(i, {
+ x: x + 300 * (Math.random() - 0.5),
+ y: y + 300 * (Math.random() - 0.5)
+ });
+ }
+ }
+ }
+
+ function secondRoomSuckerBoss(x, y, isDark = false, radius = 25) {
+ mobs.spawn(x, y, 12, radius, isDark ? "#000" : "#fff");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.isDark = isDark;
+
+ me.stroke = "transparent";
+ me.eventHorizon = 500; // How family friendly content much do I have to reduce this
+ me.seeAtDistance2 = 5e6; // Basically just see at all times, in the context it's given
+ me.accelMag = 0.00003 * simulation.accelScale;
+ me.collisionFilter.mask = cat.player | cat.bullet;
+ me.memory = 1600;
+ me.randomPRNGMult = Math.random() * 500;
+
+ me.attackCycle = 0;
+ me.lastAttackCycle = 0;
+ Matter.Body.setDensity(me, 0.012); // extra dense, normal is 0.001 // makes effective life much larger
+ me.onDeath = function () {
+ // applying forces to player doesn't seem to work inside this method, not sure why
+ powerUps.spawn(this.position.x + 20, this.position.y, "ammo");
+ if (Math.random() > 0.5) powerUps.spawn(this.position.x, this.position.y, "ammo");
+ if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, null, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5));
+ };
+ me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1);
+ me.do = function () {
+ // keep it slow, to stop issues from explosion knock backs
+ if (this.speed > 1) {
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * 0.95,
+ y: this.velocity.y * 0.95
+ });
+ }
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ if (this.distanceToPlayer2() < this.seeAtDistance2) { // ignore cloak for black holes
+ this.locatePlayer();
+ if (!this.seePlayer.yes) this.seePlayer.yes = true;
+ } else if (this.seePlayer.recall) {
+ this.lostPlayer();
+ }
+ }
+ this.checkStatus();
+ if (this.seePlayer.recall) {
+ // accelerate towards the player
+ const forceMag = this.accelMag * this.mass;
+ const dx = this.seePlayer.position.x - this.position.x
+ const dy = this.seePlayer.position.y - this.position.y
+ const mag = Math.sqrt(dx * dx + dy * dy)
+ this.force.x += forceMag * dx / mag;
+ this.force.y += forceMag * dy / mag;
+
+ // eventHorizon waves in and out
+ const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008));
+
+ // draw darkness
+ ctx.fillStyle = this.isDark ? "rgba(0,20,40,0.6)" : "rgba(225,215,255,0.6)";
+ DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.2, 0, 2 * Math.PI);
+ ctx.fillStyle = this.isDark ? "rgba(0,20,40,0.4)" : "rgba(225,215,255,0.4)";
+ DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.4, 0, 2 * Math.PI);
+ ctx.fillStyle = this.isDark ? "rgba(0,20,40,0.3)" : "rgba(225,215,255,0.3)";
+ DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.6, 0, 2 * Math.PI);
+ ctx.fillStyle = this.isDark ? "rgba(0,20,40,0.2)" : "rgba(225,215,255,0.2)";
+ DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.8, 0, 2 * Math.PI);
+ ctx.fillStyle = this.isDark ? "rgba(0,0,0,0.05)" : "rgba(255,255,255,0.05)";
+ DrawTools.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI);
+ // when player is inside event horizon
+ if (distance(this.position, player.position) < eventHorizon) {
+ if (this.isDark) {
+ // Standard black hole stuff
+ if (m.immuneCycle < m.cycle) {
+ if (m.energy > 0) m.energy -= 0.003;
+ if (m.energy < 0.1) m.damage(0.00015 * simulation.dmgScale);
+ }
+ const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
+ player.force.x -= 0.0005 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1);
+ player.force.y -= 0.0005 * Math.sin(angle) * player.mass;
+ // draw line to player
+ ctx.lineWidth = Math.min(60, this.radius * 2);
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ DrawTools.line([this.position, m.pos]);
+ ctx.fillStyle = "rgba(0,0,0,0.3)";
+ DrawTools.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ } else {
+ // Lightning attacks
+ this.attackCycle++;
+ if (this.attackCycle >= 30) {
+ this.attackCycle = 0;
+ this.lastAttackCycle = simulation.cycle;
+ Matter.Body.setVelocity(player, V.add(player.velocity, {
+ x: 0,
+ y: -10
+ }));
+ if (m.immuneCycle < m.cycle) {
+ if (m.energy > 0) m.energy -= 0.03;
+ m.damage(0.005 * simulation.dmgScale);
+ }
+ }
+ DrawTools.lightning(this.position, m.pos, this.lastAttackCycle, this.randomPRNGMult);
+ ctx.fillStyle = `rgba(255,240,127,${0.12 * Math.max(15 - simulation.cycle + this.lastAttackCycle, 0)})`;
+ DrawTools.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ }
+ }
+ }
+ }
+ };
+
+ function secondRoomPlacerBoss(x, y, isDark = false, size = 70) {
+ mobs.spawn(x, y, isDark ? 3 : 4, size, isDark ? "#0008" : "#fff8");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.isDark = isDark;
+
+ me.stroke = isDark ? "#000" : "#fff";
+ me.seeAtDistance2 = 5e6; // Basically just see at all times, in the context it's given
+ me.accelMag = 0.0001 * simulation.accelScale;
+ me.collisionFilter.mask = cat.player | cat.bullet;
+ me.memory = 1600;
+ me.randomPRNGMult = Math.random() * 500;
+
+ me.attackCycle = 0;
+ me.maxAttackCycle = isDark ? 90 : 240;
+ Matter.Body.setDensity(me, 0.006); // extra dense, normal is 0.001 // makes effective life much larger
+ me.onDeath = function () {
+ powerUps.spawn(this.position.x + 20, this.position.y, "ammo");
+ if (Math.random() > 0.5) powerUps.spawn(this.position.x, this.position.y, "ammo");
+ if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, null, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5));
+ };
+ me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1);
+ me.do = function () {
+ // keep it slow, to stop issues from explosion knock backs
+ if (this.speed > 2) {
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * 0.95,
+ y: this.velocity.y * 0.95
+ });
+ }
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ if (this.distanceToPlayer2() < this.seeAtDistance2) { // ignore cloak
+ this.locatePlayer();
+ if (!this.seePlayer.yes) this.seePlayer.yes = true;
+ } else if (this.seePlayer.recall) {
+ this.lostPlayer();
+ }
+ }
+ this.checkStatus();
+ if (this.seePlayer.recall) {
+ // accelerate towards the player
+ const forceMag = this.accelMag * this.mass;
+ const dx = this.seePlayer.position.x - this.position.x
+ const dy = this.seePlayer.position.y - this.position.y
+ const mag = Math.sqrt(dx * dx + dy * dy)
+ this.force.x += forceMag * dx / mag;
+ this.force.y += forceMag * dy / mag;
+ this.attackCycle++;
+ if (this.attackCycle > this.maxAttackCycle) {
+ this.attackCycle = 0;
+ secondRoomObstacle(this.position.x, this.position.y, this.isDark, size);
+ }
+ }
+ }
+ };
+
+ function secondRoomObstacle(x, y, isDark = false, size = 70) {
+ mobs.spawn(x, y, isDark ? 3 : 4, size, isDark ? "#0004" : "#fff4");
+ let me = mob[mob.length - 1];
+
+ me.stroke = isDark ? "#000b" : "#fffb";
+ me.collisionFilter.mask = isDark ? cat.player | cat.bullet : 0;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.leaveBody = false;
+ me.timeLeft = 1200;
+ me.isObstacle = true;
+ me.damageReduction = isDark ? 0.5 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) : 0;
+ if (!isDark) {
+ me.isBadTarget = true;
+ me.attackCycle = 0;
+ me.maxAttackCycle = 10;
+ me.inertia = Infinity;
+ }
+ me.do = isDark ? function () {
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * 0.95,
+ y: this.velocity.y * 0.95
+ });
+ } : function () {
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * 0.95,
+ y: this.velocity.y * 0.95
+ });
+ if (Rect.fromBounds(this.bounds.min, this.bounds.max).isCollidingWith(Rect.fromBounds(player.bounds.min, player.bounds.max))) {
+ this.attackCycle++;
+ this.attackCycle = Math.min(this.attackCycle, 10);
+ } else {
+ this.attackCycle--;
+ this.attackCycle = Math.max(this.attackCycle, 0);
+ }
+ if (this.attackCycle > 0) {
+ ctx.beginPath();
+ const vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ if (this.attackCycle >= 10) {
+ ctx.shadowBlur = 10;
+ ctx.shadowColor = "rgb(255, 210, 64)";
+ }
+ ctx.fillStyle = `rgba(255, 210, 64, ${this.attackCycle / 15})`;
+ ctx.fill();
+ ctx.shadowBlur = 0;
+ if (this.attackCycle >= 10) {
+ DrawTools.lightning(this.position, m.pos, simulation.cycle);
+ m.damage(0.003 * simulation.dmgScale);
+ }
+ }
+ this.timeLimit();
+ }
+ }
+
+ function mobGrenade(...args) {
+ spawn.grenade(...args);
+ const pulseRadius = args[3] || Math.min(550, 250 + simulation.difficulty * 3)
+ let me = mob[mob.length - 1];
+ me.fill = "#ace";
+ me.damageReduction = 0;
+ me.onDeath = function () {
+ //damage player if in range
+ if (distance(player.position, this.position) < pulseRadius && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage
+ m.damage(0.02 * simulation.dmgScale);
+ }
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: pulseRadius,
+ color: "rgba(170,204,238,0.3)",
+ time: simulation.drawTime
+ });
+ };
+ me.do = function () {
+ this.timeLimit();
+ ctx.beginPath(); //draw explosion outline
+ ctx.arc(this.position.x, this.position.y, pulseRadius * (1.01 - this.timeLeft / this.lifeSpan), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ ctx.fillStyle = "rgba(170,204,238,0.1)";
+ ctx.fill();
+ };
+ }
+ // Todo: nerf ThirdRoomBoss a bit?
+ function thirdRoomBoss(x, y) {
+ mobs.spawn(x, y, 6, 60, "#000");
+ let me = mob[mob.length - 1];
+ // Fix in place
+ me.constraint = Constraint.create({
+ pointA: {
+ x: me.position.x,
+ y: me.position.y
+ },
+ bodyB: me,
+ stiffness: 1,
+ damping: 1
+ });
+ Composite.add(engine.world, me.constraint);
+ me.isBoss = true;
+
+ me.stroke = "transparent";
+ me.eventHorizon = 900;
+ me.collisionFilter.mask = cat.player | cat.bullet | cat.body;
+
+ me.memory = Infinity;
+ me.attackCycle = 0;
+ me.lastAttackCycle = 0;
+ me.spawnCycle = 0;
+ Matter.Body.setDensity(me, 0.08); //extra dense //normal is 0.001 //makes effective life much larger
+ me.onDeath = function () {
+ for (let j = 0; j < 8; j++) { //in case some mobs leave things after they die
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (mob[i] !== this) {
+ if (mob[i].isInvulnerable) { //disable invulnerability
+ mob[i].isInvulnerable = false
+ mob[i].damageReduction = 1
+ }
+ mob[i].damage(Infinity, true);
+ }
+ }
+ }
+ // You earned it: One more tech
+ powerUps.spawn(this.position.x, this.position.y, "tech");
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y);
+ templePlayer.room3ToEndAnim = 1;
+ };
+ me.nextHealthThreshold = 0.75;
+ me.trapCycle = 0;
+ me.onDamage = function () {
+ if (this.health < this.nextHealthThreshold) {
+ this.health = this.nextHealthThreshold - 0.01
+ this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
+ this.trapCycle = 1;
+ this.isInvulnerable = true;
+ this.damageReduction = 0;
+ }
+ };
+ me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1);
+ me.rings = [{
+ colour: "#65f",
+ radius: 300,
+ id: 0
+ }, {
+ colour: "#0f0",
+ radius: 400,
+ id: 1
+ }, {
+ colour: "#f00",
+ radius: 500,
+ id: 2
+ }];
+ me.ring = function () {
+ if (this.isInvulnerable) return;
+ ctx.lineWidth = 10;
+ for (const ring of this.rings) {
+ const radius = ring.radius * (1 + 0.3 * Math.sin(simulation.cycle / 60 * (ring.id + 2)));
+ if (Math.abs(distance(player.position, this.position) - radius) < 60 && m.immuneCycle < simulation.cycle) {
+ m.damage(0.4 / radius);
+ }
+ ctx.strokeStyle = ring.colour;
+ DrawTools.arcOut(this.position.x, this.position.y, radius, 0, Math.PI * 2);
+ }
+ }
+ me.horizon = function () {
+ if (this.isInvulnerable) return this.fill = "#f00";
+ // eventHorizon waves in and out
+ const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008));
+
+ const charge = this.attackCycle / 90;
+ this.fill = `rgb(${charge * 255},${charge * 255},${charge * 255})`;
+ // draw darkness
+ ctx.fillStyle = `rgba(${charge * 225},${20 + charge * 195},${40 + charge * 215},0.6)`;
+ DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.2, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(${charge * 225},${20 + charge * 195},${40 + charge * 215},0.4)`;
+ DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.4, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(${charge * 225},${20 + charge * 195},${40 + charge * 215},0.3)`;
+ DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.6, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(${charge * 225},${20 + charge * 195},${40 + charge * 215},0.2)`;
+ DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.8, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(${charge * 255},${charge * 255},${charge * 255},0.05)`;
+ DrawTools.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI);
+
+ // when player is inside event horizon
+ if (V.magnitude(V.sub(this.position, player.position)) < eventHorizon) {
+ // Standard black hole stuff
+ if (m.immuneCycle < m.cycle) {
+ if (m.energy > 0) m.energy -= 0.004;
+ if (m.energy < 0.1) m.damage(0.0002 * simulation.dmgScale);
+ }
+ const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
+ player.force.x -= 0.001 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1);
+ player.force.y -= 0.001 * Math.sin(angle) * player.mass;
+ // draw line to player
+ ctx.lineWidth = Math.min(60, this.radius * 2);
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ DrawTools.line([this.position, m.pos]);
+ ctx.fillStyle = "rgba(0,0,0,0.3)";
+ DrawTools.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ // Lightning attacks
+ this.attackCycle++;
+ if (this.attackCycle >= 90) {
+ this.attackCycle = 0;
+ this.lastAttackCycle = simulation.cycle;
+ Matter.Body.setVelocity(player, V.add(player.velocity, {
+ x: 0,
+ y: -20
+ }));
+ if (m.immuneCycle < m.cycle) {
+ m.damage(0.012 * simulation.dmgScale);
+ }
+ }
+ const lightningCycle = simulation.cycle * 2 / 3 + this.lastAttackCycle / 3;
+ DrawTools.lightning(this.position, m.pos, lightningCycle, 1, 12);
+ DrawTools.lightning(this.position, m.pos, lightningCycle, 2, 12);
+ ctx.fillStyle = `rgba(255,240,127,${0.12 * Math.max(15 - simulation.cycle + this.lastAttackCycle, 0)})`;
+ DrawTools.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ }
+ }
+ me.periodicSpawns = function () {
+ if (this.isInvulnerable) return;
+ this.spawnCycle++;
+ // Spawn annoying purple thing(s) that chases the player
+ if (!(this.spawnCycle % 180)) {
+ spawn.seeker(this.position.x, this.position.y, 15 * (0.7 + 0.5 * Math.random()), 7);
+ spawn.seeker(this.position.x, this.position.y, 4 * (0.7 + 0.5 * Math.random()), 7);
+ spawn.seeker(this.position.x, this.position.y, 4 * (0.7 + 0.5 * Math.random()), 7);
+ }
+ // Spawn the annoying pink (now blue) exploder that doesn't chase the player
+ if (!(this.spawnCycle % 300)) {
+ for (let i = 0; i < 3; i++) {
+ mobGrenade(1100 + 700 * i, -13030, undefined, Math.min(700, 300 + simulation.difficulty * 4), 10);
+ setVel(mob[mob.length - 1], {
+ x: 0,
+ y: -10
+ });
+ mobGrenade(1100 + 700 * i, -14370, undefined, Math.min(700, 300 + simulation.difficulty * 4), 10);
+ setVel(mob[mob.length - 1], {
+ x: 0,
+ y: 10
+ });
+ }
+ }
+ // Spawn a bunch of mobs
+ if (simulation.difficulty > 10 && !(this.spawnCycle % 600)) {
+ // This is just ripped off of spawn.nodeGroup because I don't want the shield
+ const nodes = 3;
+ const radius = Math.ceil(Math.random() * 10) + 18;
+ const sideLength = Math.ceil(Math.random() * 100) + 70;
+ const stiffness = Math.random() * 0.03 + 0.005;
+ spawn.allowShields = false; //don't want shields on individual group mobs
+ const angle = 2 * Math.PI / nodes
+ for (let i = 0; i < nodes; ++i) {
+ spawn.focuser(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius);
+ }
+ spawn.constrainAllMobCombos(nodes, stiffness);
+ spawn.allowShields = true;
+ }
+ }
+ me.invulnerableTrap = function () {
+ if (this.trapCycle < 1) return;
+ this.trapCycle++;
+ // 24 is just an arbitrarily large number
+ const spawnCycles = Math.min(24, Math.max(6, 4 + Math.floor(simulation.difficulty / 3)));
+ // I have no idea how to balance at all, please help me
+ const spawnDelay = Math.floor(5 + 10 / (1 + Math.sqrt(simulation.difficulty) / 5));
+ if (this.trapCycle >= 90) {
+ const cycle = this.trapCycle - 90;
+ if (!(cycle % spawnDelay)) {
+ const radius = Math.min(500, 200 + simulation.difficulty * 3);
+ mobGrenade(600, -13050, 30, radius);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: 35,
+ y: 0
+ });
+ mobGrenade(3000, -13050, 30, radius);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: -35,
+ y: 0
+ });
+ mobGrenade(600, -14350, 30, radius);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: 35,
+ y: 0
+ });
+ mobGrenade(3000, -14350, 30, radius);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: -35,
+ y: 0
+ });
+ if (Math.floor(cycle / spawnDelay) >= spawnCycles - 1) {
+ this.trapCycle = 0;
+ this.isInvulnerable = false;
+ this.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1);
+ }
+ }
+ }
+ ctx.font = "100px Arial";
+ ctx.fillStyle = "#f00";
+ ctx.shadowBlur = 10;
+ ctx.shadowColor = "#f00";
+ ctx.textAlign = "center";
+ ctx.textBaseLine = "middle";
+ ctx.fillText("!", 900, -13050);
+ ctx.fillText("!", 900, -14350);
+ ctx.fillText("!", 1800, -13050);
+ ctx.fillText("!", 1800, -14350);
+ ctx.fillText("!", 2700, -13050);
+ ctx.fillText("!", 2700, -14350);
+ ctx.shadowBlur = 0;
+ }
+ me.do = function () {
+ this.checkStatus();
+ this.horizon();
+ this.ring();
+ this.periodicSpawns();
+ this.invulnerableTrap();
+ }
+ };
+ let oldNextLevel = level.nextLevel;
+ const oldFallHeight = simulation.fallHeight;
+ level.nextLevel = () => {
+ color.map = "#444";
+ m.death = m.oldDeath;
+ canvas.style.filter = "";
+ level.nextLevel = oldNextLevel;
+ simulation.fallHeight = oldFallHeight;
+ oldNextLevel();
+ }
+ let bounds = [];
+ let mobPositionsQueue = Array.from(Array(10), () => []);
+ m.oldDeath = m.death;
+ m.death = function () {
+ if (!tech.isImmortal) {
+ requestAnimationFrame(() => color.map = "#444");
+ m.death = m.oldDeath;
+ canvas.style.filter = "";
+ level.nextLevel = oldNextLevel;
+ simulation.fallHeight = oldFallHeight;
+ m.oldDeath();
+ } else {
+ m.switchWorlds();
+ Matter.Body.setPosition(player, {
+ x: level.enter.x + 50,
+ y: level.enter.y - 20
+ });
+ makeLore("How did you not die?");
+ setTimeout(() => makeLore("I'll let you off this one time."), 2000);
+ tech.isImmortal = false;
+ }
+ }
+ let name = "⥟ᘊ5⪊Ыᳪៗⱕ␥ዘᑧ⍗";
+ addPartToMap = (len = map.length - 1) => {
+ map[len].collisionFilter.category = cat.map;
+ map[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(map[len], true); // make static
+ Composite.add(engine.world, map[len]);
+ }
+ level.setPosToSpawn(50, -50); // normal spawn
+ // Make the level exit really far away so WIMP powerups don't show up at all
+ level.exit.x = 1e6;
+ level.exit.y = -1e6;
+ Promise.resolve().then(() => {
+ // Clear all WIMPS and their research
+ for (let i = 0; i < mob.length; i++) {
+ while (mob[i] && !mob[i].isMACHO) {
+ mob[i].replace(i);
+ }
+ }
+ for (let i = 0; i < powerUp.length; i++) {
+ while (powerUp[i] && powerUp[i].name === "research") {
+ Matter.Composite.remove(engine.world, powerUp[i]);
+ powerUp.splice(i, 1);
+ }
+ }
+ level.exit.x = 1500;
+ level.exit.y = -30;
+ });
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ spawn.mapRect(1500, -10, 100, 20);
+ level.defaultZoom = 1800
+ simulation.setZoom(1200);
+ document.body.style.backgroundColor = "#daa69f";
+ color.map = "#600";
+
+ function box(x, y, w, h, s) {
+ spawn.mapRect(x, y, w, s);
+ spawn.mapRect(x, y, s, h);
+ spawn.mapRect(x + w - s, y, s, h);
+ spawn.mapRect(x, y + h - s, w, s);
+ }
+
+ function diamond(x, y, s) {
+ spawn.mapVertex(x, y, `0 -${s} -${s} 0 0 ${s} ${s} 0`);
+ }
+
+ // Fake level
+ bounds.push(new Rect(-200, -500, 2000, 600));
+ box(-200, -500, 2000, 600, 100);
+
+ // Actual level, Room 1
+ const firstRoomBounds = new Rect(-200, -4000, 5000, 2100);
+ bounds.push(firstRoomBounds);
+
+ box(-200, -4000, 5000, 2100, 100);
+ spawn.mapRect(-200, -2500, 1300, 100);
+ spawn.mapRect(3500, -2500, 1300, 100);
+ spawn.mapRect(-200, -4000, 1000, 1600);
+ spawn.mapRect(3800, -4000, 1000, 1600);
+ // Enter and Exit platforms
+ spawn.mapRect(0, -2010, 100, 20);
+ spawn.mapRect(4500, -2010, 100, 20);
+
+ // Altar of Room 1
+ spawn.mapRect(2100, -2200, 100, 300);
+ spawn.mapRect(2400, -2200, 100, 300);
+ spawn.mapRect(2070, -2200, 460, 20);
+
+ spawn.debris(1700, -2100, 300, 10);
+ spawn.debris(2500, -2100, 300, 10);
+
+ // Actual level, Room 2
+ const secondRoomBounds = new Rect(-1500, -10500, 3000, 3600);
+ bounds.push(secondRoomBounds);
+
+ box(-1500, -10500, 3000, 3600, 100);
+ spawn.mapRect(-2000, -8500, 1600, 1600);
+ spawn.mapRect(400, -8500, 1600, 1600);
+ // Enter and Exit platforms
+ spawn.mapRect(-50, -7010, 100, 20);
+ spawn.mapRect(-50, -10010, 100, 20);
+
+ // Hazard traversing
+ spawn.mapRect(-300, -7320, 800, 20);
+ spawn.mapRect(175, -7600, 325, 20);
+ spawn.mapRect(200, -7775, 300, 20);
+ spawn.mapRect(-500, -7600, 325, 20);
+ spawn.mapRect(-500, -7775, 300, 20);
+ spawn.mapRect(-500, -7950, 800, 20);
+ spawn.mapRect(-300, -8100, 800, 20);
+ spawn.mapRect(-500, -8250, 800, 20);
+ for (let i = 0; i < 2; i++) spawn.mapRect(-250, -8400 + 150 * i, 500, 60);
+ const room2SlimePit = level.hazard(-400, -8410, 800, 1090);
+ room2SlimePit.logic = function () {
+ if (this.height > 0 && Matter.Query.region([player], this).length) {
+ if (m.immuneCycle < m.cycle) {
+ // Trolled
+ const hasCPT = tech.isRewindAvoidDeath;
+ tech.isRewindAvoidDeath = false;
+ const DRAIN = 0.002 * (tech.isRadioactiveResistance ? 0.25 : 1) + 0.001;
+ if (m.energy > DRAIN && !tech.isEnergyHealth) {
+ m.energy -= DRAIN;
+ }
+ m.damage(0.00015 * (tech.isRadioactiveResistance ? 0.25 : 1));
+ if (tech.isEnergyHealth) {
+ const previousEnergy = m.energy;
+ m.regenEnergy();
+ const energyRegenerated = m.energy - previousEnergy;
+ if (energyRegenerated > 0) {
+ m.energy = previousEnergy;
+ m.damage(energyRegenerated);
+ }
+ }
+ tech.isRewindAvoidDeath = hasCPT;
+ }
+ player.force.y -= 0.3 * player.mass * simulation.g;
+ setVel(player, Vector.sub(player.velocity, {
+ x: 0,
+ y: player.velocity.y * 0.02
+ }));
+ }
+ // Float power ups
+ powerUpCollide = Matter.Query.region(powerUp, this)
+ for (let i = 0, len = powerUpCollide.length; i < len; i++) {
+ const diameter = 2 * powerUpCollide[i].size
+ const buoyancy = 1 - 0.2 * Math.max(0, Math.min(diameter, this.min.y - powerUpCollide[i].position.y + powerUpCollide[i].size)) / diameter
+ powerUpCollide[i].force.y -= buoyancy * 1.14 * powerUpCollide[i].mass * simulation.g;
+ setVel(powerUpCollide[i], {
+ x: powerUpCollide[i].velocity.x,
+ y: 0.96 * powerUpCollide[i].velocity.y
+ });
+ }
+ }
+ room2SlimePit.draw = function () {
+ if (this.isOn) {
+ ctx.fillStyle = "hsla(160, 100%, 35%, 0.75)";
+ ctx.fillRect(this.min.x, this.min.y, this.width, this.height);
+ }
+ }
+ // Room 2 spawning bounds
+ const secondRoomSpawnBounds = new Rect(-1500, -10500, 3000, 2000);
+ spawn.mapRect(-700, -8700, 150, 20);
+ spawn.mapRect(550, -8700, 150, 20);
+ spawn.mapRect(-400, -8900, 800, 20);
+ diamond(-600, -9800, 30);
+ diamond(0, -9800, 30);
+ diamond(600, -9800, 30);
+
+ spawn.mapRect(-1000, -10000, 2000, 30);
+
+ // Actual level, Room 3 (Final Boss?)
+ const thirdRoomBounds = new Rect(-200, -14500, 4000, 1600);
+ bounds.push(thirdRoomBounds);
+ box(-200, -14500, 4000, 1600, 100);
+ spawn.mapRect(-200, -14500, 800, 1100);
+ spawn.mapRect(3000, -14500, 800, 1100);
+ // Enter and Exit platforms
+ spawn.mapRect(0, -13110, 100, 20);
+ spawn.mapRect(-200, -13100, 800, 200);
+ spawn.mapRect(3500, -13110, 100, 20);
+ spawn.mapRect(3000, -13100, 800, 200);
+ for (let i = 0; i < 4; i++) spawn.bodyRect(570, -13400 + i * 75, 30, 75);
+
+ for (let i = 0; i < 3; i++) {
+ diamond(1100 + 700 * i, -13000, 30, 30);
+ diamond(1100 + 700 * i, -14400, 30, 30);
+ }
+
+ const Objects = {
+ altar: {
+ get isHeal() {
+ return simulation.cycle % 600 >= 300;
+ },
+ pos: {
+ x: 2300,
+ y: -2200
+ },
+ get isActive() {
+ const roughPlayerCentre = V.add(m.pos, {
+ x: 0,
+ y: 40
+ });
+ return distance(roughPlayerCentre, this.pos) < 240 &&
+ (Math.abs(angle(roughPlayerCentre, this.pos) - Math.PI / 2) < 1);
+ },
+ logic() {
+ if (!this.isActive) return;
+ if (this.isHeal) {
+ m.energy += 0.005;
+ } else {
+ m.energy = Math.max(m.energy - 0.006, 0);
+ if (m.energy <= 0.01 && m.immuneCycle < m.cycle) m.damage(0.002);
+ }
+ },
+ drawTop() {
+ if (!isInBound(firstRoomBounds)) return;
+ const colour = this.isHeal ? m.fieldMeterColor : "#f00";
+ DrawTools.flame([2300, -2200, 26, 4, colour], 7);
+ ctx.fillStyle = colour;
+ ctx.fillRect(2200, -2200, 200, 200);
+ },
+ drawBottom() {
+ ctx.fillStyle = this.isHeal ? "#fff5" : "#0005";
+ for (const radius of [230, 180, 130, 80, 30]) {
+ DrawTools.arc(2300, -2200, radius, 0, Math.PI, true);
+ }
+ }
+ },
+ room2Initiator: {
+ pos: {
+ x: 0,
+ y: -9050
+ },
+ get distance() {
+ return distance(player.position, this.pos);
+ },
+ range: 120,
+ rings: [{
+ colour: [102, 85, 255],
+ radius: 200
+ }, {
+ colour: [0, 255, 0],
+ radius: 300
+ }, {
+ colour: [255, 0, 0],
+ radius: 400
+ }],
+ get ringNumber() {
+ return this.rings.length;
+ },
+ get cap() {
+ return (this.ringNumber + 1) * 90 + 240;
+ },
+ get capped() {
+ return templePlayer.room2.spawnInitiatorCycles > this.cap;
+ },
+ logic() {
+ if (this.distance < this.range) {
+ templePlayer.room2.spawnInitiatorCycles++;
+ }
+ },
+ draw() {
+ Promise.resolve().then(() => {
+ const cycle = templePlayer.room2.spawnInitiatorCycles;
+ if (!this.capped && this.distance < 400) {
+ ctx.fillStyle = `rgba(0, 0, 0, ${Math.min(1, (400 - this.distance) / (400 - this.range)) * 0.9})`;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ }
+ ctx.save();
+ simulation.camera();
+ if (this.distance < this.range && !this.capped) {
+ DrawTools.lightning(V.sub(this.pos, {
+ x: 300,
+ y: 300
+ }), V.add(this.pos, {
+ x: 300,
+ y: 300
+ }), simulation.cycle - 5);
+ DrawTools.lightning(V.add(this.pos, {
+ x: -300,
+ y: 300
+ }), V.add(this.pos, {
+ x: 300,
+ y: -300
+ }), simulation.cycle - 5);
+ }
+ if (!this.capped && cycle >= this.cap - 200) {
+ const multCoeff = (cycle - this.cap + 200) * 0.4
+ ctx.translate((Math.random() - 0.5) * multCoeff, (Math.random() - 0.5) * multCoeff);
+ }
+ ctx.shadowBlur = 20;
+ ctx.lineWidth = 12;
+ ctx.strokeStyle = (templePlayer.room2.cycles % 60 < 30) ? "#fff" : "#000";
+ ctx.shadowColor = (templePlayer.room2.cycles % 60 < 30) ? "#fff" : "#000";
+ DrawTools.arcOut(this.pos.x, this.pos.y, 100, 0, Math.PI * 2);
+ if (templePlayer.room2.cycles <= 100) {
+ for (let i = 0; i < this.ringNumber; i++) {
+ if (cycle < i * 90 + 90) break;
+ const ring = this.rings[i];
+ ctx.shadowColor = `rgb(${ring.colour.join(",")})`;
+ const opacity = this.capped ? 1 - 0.01 * templePlayer.room2.cycles : (cycle / 180 - i / 2 - 0.5);
+ ctx.strokeStyle = `rgba(${ring.colour.join(",")}, ${Math.min(opacity, 1)})`;
+ const radius = (this.capped ? 1 + 0.07 * templePlayer.room2.cycles : Math.sin(Math.min(cycle - i * 90 - 90, 45) / 90 * Math.PI)) * ring.radius;
+ DrawTools.arcOut(this.pos.x, this.pos.y, radius, 0, Math.PI * 2);
+ }
+ }
+ ctx.restore();
+ });
+ }
+ },
+ room2Lightning: {
+ one: [{
+ x: -1400,
+ y: -10400
+ }, {
+ x: 1400,
+ y: -8500
+ }],
+ two: [{
+ x: -1400,
+ y: -8500
+ }, {
+ x: 1400,
+ y: -10400
+ }],
+ get isHeal() {
+ return simulation.cycle % 360 < 180;
+ },
+ get oneEq() {
+ return Equation.fromPoints(this.one[0], this.one[1]);
+ },
+ get twoEq() {
+ return Equation.fromPoints(this.two[0], this.two[1]);
+ },
+ logic() {
+ if (!isInBound(secondRoomSpawnBounds) || !templePlayer.room2.cycles) return;
+
+ const playerbounds = Rect.fromBounds(player.bounds.min, player.bounds.max);
+ if (playerbounds.hasLine(this.oneEq) || playerbounds.hasLine(this.twoEq)) {
+ if (this.isHeal) {
+ m.energy += 0.003;
+ } else if (m.immuneCycle < m.cycle) {
+ m.energy -= 0.003;
+ }
+ }
+ },
+ draw() {
+ if (!isInBound(secondRoomBounds) || !templePlayer.room2.cycles) return;
+
+ const colour = this.isHeal ? undefined : [0, 0, 0];
+ DrawTools.lightning(...this.one, Math.floor(simulation.cycle / 15) * 15, 1, 9, colour);
+ DrawTools.lightning(...this.two, Math.floor(simulation.cycle / 15) * 15, 2, 9, colour);
+ }
+ },
+ room2GeneratedPath: {
+ rects: (function () {
+ const rects = [];
+ for (let i = 0; i < 4; i++) {
+ rects.push(new Rect(-1405 + (i & 1) * 200, -9700 + i * 300, 205, 30));
+ rects.push(new Rect(1200 - (i & 1) * 200, -9700 + i * 300, 205, 30));
+ }
+ return rects;
+ })(),
+ logic() {
+ if (templePlayer.room2.readyPathCycle && simulation.cycle - templePlayer.room2.readyPathCycle === 180) {
+ for (const r of this.rects) {
+ r.addToMap();
+ addPartToMap();
+ simulation.draw.setPaths();
+ }
+ }
+ },
+ draw() {
+ if (templePlayer.room2.readyPathCycle && simulation.cycle - templePlayer.room2.readyPathCycle < 180) {
+ ctx.fillStyle = "#fe79";
+ for (const r of this.rects) {
+ ctx.fillRect(r.pos.x, r.pos.y, r.width, r.height);
+ }
+ } else if (simulation.cycle - templePlayer.room2.readyPathCycle < 195) {
+ for (const r of this.rects) {
+ DrawTools.lightning(Objects.room2Initiator.pos, r.midPos, templePlayer.room2.readyPathCycle + 180);
+ }
+ }
+ }
+ },
+ room3Rotors: {
+ rotor1: (function () {
+ const rotor = level.spinner(900, -13700, 200, 30);
+ rotor.rotate = function () {
+ Matter.Body.setAngularVelocity(this.bodyB, (this.bodyB.angularVelocity + 0.01) * 0.9)
+ }
+ return rotor;
+ })(),
+ rotor2: (function () {
+ const rotor = level.spinner(2700, -13700, 200, 30);
+ rotor.rotate = function () {
+ Matter.Body.setAngularVelocity(this.bodyB, (this.bodyB.angularVelocity - 0.01) * 0.9)
+ }
+ return rotor;
+ })(),
+ logic() {
+ this.rotor1.rotate();
+ this.rotor2.rotate();
+ }
+ },
+ room3SlimePits: {
+ pit1: level.hazard(-100, -13400, 0, 0, 0.004),
+ pit2: level.hazard(3700, -13400, 0, 0, 0.004),
+ logic() {
+ if (templePlayer.room2ToRoom3Anim >= 1320 && templePlayer.room2ToRoom3Anim <= 1570) {
+ this.pit1.height = this.pit2.height = 300;
+ this.pit1.max.y = this.pit2.max.y = -13100;
+ this.pit1.width = this.pit2.width = templePlayer.room2ToRoom3Anim * 2 - 2640;
+ this.pit1.max.x = this.pit1.min.x + this.pit1.width;
+ this.pit2.min.x = this.pit2.max.x - this.pit2.width;
+ }
+ if (templePlayer.room3ToEndAnim) {
+ this.pit1.height = this.pit1.width = 0;
+ this.pit2.height = this.pit2.width = 0;
+ }
+ },
+ draw() {
+ this.pit1.query();
+ this.pit2.query();
+ }
+ }
+ };
+ let templePlayer = {
+ room1: {
+ cycles: 300
+ },
+ room2: {
+ spawnInitiatorCycles: 0,
+ cycles: 0,
+ readyPathCycle: 0
+ },
+ stage: 1,
+ startAnim: 0,
+ room1ToRoom2Anim: 0,
+ room2ToRoom3Anim: 0,
+ room3ToEndAnim: 0,
+ initialTrapY: 0,
+ clearedCycle: 0,
+ drawExit: true
+ };
+
+ const RoomTransitionHandler = {
+ room0() {
+ if (templePlayer.startAnim <= 0) return;
+ templePlayer.startAnim++;
+ if (templePlayer.startAnim == 120) {
+ makeLore("Not so fast.");
+ }
+ if (templePlayer.startAnim < 360) {
+ trapPlayer(1000, templePlayer.initialTrapY);
+ } else {
+ level.exit.x = 4500;
+ level.exit.y = -2030;
+ relocateTo(50, -2050);
+ simulation.fallHeight = -1000;
+ simulation.setZoom(1800);
+ templePlayer.startAnim = -1;
+ templePlayer.drawExit = false;
+ }
+ },
+ room1() {
+ if (templePlayer.room1ToRoom2Anim <= 0) return;
+ if (templePlayer.room1ToRoom2Anim === 1) {
+ level.exit.x = -50;
+ level.exit.y = -10030;
+ makeLore("Pathetic.");
+ }
+ if (templePlayer.room1ToRoom2Anim === 121) {
+ makeLore("You will never succeed.");
+ }
+ if (templePlayer.room1ToRoom2Anim >= 360 && templePlayer.room1ToRoom2Anim <= 720) {
+ const factor = 200 - 200 * Math.cos((templePlayer.room1ToRoom2Anim / 120 - 3) * Math.PI);
+ ctx.translate(factor, factor);
+ Promise.resolve().then(() => {
+ ctx.save();
+ ctx.globalCompositeOperation = "color-burn";
+ ctx.fillStyle = DrawTools.randomColours;
+ DrawTools.updateRandomColours(5);
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ ctx.restore();
+ });
+ }
+ if (templePlayer.room1ToRoom2Anim === 720) {
+ makeLore("You are trying too hard.");
+ relocateTo(0, -7050);
+ simulation.fallHeight = -6000;
+ templePlayer.stage = 2;
+ }
+ if (templePlayer.room1ToRoom2Anim === 960) {
+ makeLore("I have mastered the understandings of the universe.");
+ }
+ if (templePlayer.room1ToRoom2Anim === 1200) {
+ // Congrats, you discovered the actual words by looking at the source code. Are you happy now?
+ const x = (
+ ["a speck of dust", "an insignificant hindrance", "a tiny obstacle"]
+ )[Math.floor(Math.random() * 3)].split("");
+ for (let i = 0; i < x.length / 1.6; i++) {
+ const randomIndex = Math.floor(Math.random() * x.length);
+ if (x[randomIndex] !== " ") {
+ x[randomIndex] = String.fromCharCode(Math.floor(Math.random() * 50) + 192);
+ }
+ };
+ makeLore(`You are no more than ${x.join("")} to me.`);
+ relocateWIMPs(0, -10030);
+ }
+ templePlayer.room1ToRoom2Anim++;
+ },
+ room2() {
+ if (templePlayer.room2ToRoom3Anim <= 0) return;
+ if (templePlayer.room2ToRoom3Anim === 1) {
+ level.exit.x = 3500;
+ level.exit.y = -13130;
+ makeLore("Do not try me.");
+ }
+ if (templePlayer.room2ToRoom3Anim === 180) {
+ makeLore("I have absolute power over you.");
+ canvas.style.filter = "hue-rotate(90deg)";
+ }
+ if (templePlayer.room2ToRoom3Anim === 360) {
+ makeLore("You will not succeed...");
+ canvas.style.filter = "invert(0.2)";
+ }
+ if (templePlayer.room2ToRoom3Anim === 420) {
+ makeLore("
... ");
+ canvas.style.filter = "invert(0.4)";
+ }
+ if (templePlayer.room2ToRoom3Anim > 480 && templePlayer.room2ToRoom3Anim <= 660) {
+ canvas.style.filter = `sepia(${(templePlayer.room2ToRoom3Anim - 480) / 180}) invert(${0.5 + (templePlayer.room2ToRoom3Anim - 480) / 180})`;
+ }
+ if (templePlayer.room2ToRoom3Anim === 780) {
+ makeLore("Do not interfere with me.");
+ templePlayer.stage = 3;
+ relocateTo(50, -13150);
+ simulation.fallHeight = -10000;
+ simulation.zoomTransition(1800);
+ templePlayer.startAnim = -1;
+ // Might be a bit harsh to the player if the WIMPs are involved in the third level
+ for (let i = 0; i < mob.length; i++) {
+ while (mob[i] && !mob[i].isWIMP) {
+ mob[i].replace(i);
+ }
+ }
+ }
+ if (templePlayer.room2ToRoom3Anim > 780 && templePlayer.room2ToRoom3Anim <= 960) {
+ canvas.style.filter = `sepia(${(960 - templePlayer.room2ToRoom3Anim) / 180}) invert(${(960 - templePlayer.room2ToRoom3Anim) / 180})`;
+ }
+ templePlayer.room2ToRoom3Anim++;
+ },
+ room3() {
+ if (templePlayer.room3ToEndAnim <= 0) return;
+ if (templePlayer.room3ToEndAnim === 1) {
+ makeLore("No.");
+ }
+ if (templePlayer.room3ToEndAnim === 120) {
+ makeLore("This cannot be.");
+ }
+ if (templePlayer.room3ToEndAnim === 240) {
+ makeLore("Has my power failed me?");
+ }
+ if (templePlayer.room3ToEndAnim === 360) {
+ makeLore("Was it worth it, destroying this place?");
+ }
+ if (templePlayer.room3ToEndAnim === 600) {
+ makeLore("No one is greater than me.");
+ }
+ const text = "noone-";
+ for (let i = 0; i < 12; i++) {
+ if (templePlayer.room3ToEndAnim === 720 + i * 20) {
+ name = name.slice(0, -1);
+ simulation.makeTextLog(`
${name}: ${text[i % 6]}`);
+ canvas.style.filter = `brightness(${1 - i / 22})`;
+ }
+ }
+ if (templePlayer.room3ToEndAnim === 1060) {
+ templePlayer.drawExit = true;
+ for (let i = 0; i < 5 * tech.wimpCount; i++) {
+ powerUps.spawn(level.exit.x + 100 * (Math.random() - 0.5), level.exit.y - 100 + 100 * (Math.random() - 0.5), "research", false);
+ }
+ canvas.style.filter = "";
+ }
+ templePlayer.room3ToEndAnim++;
+ },
+ end() {
+ if (!templePlayer.clearedCycle) return;
+ Promise.resolve().then(() => {
+ ctx.save();
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.fillStyle = `rgba(0, 0, 0, ${(simulation.cycle - templePlayer.clearedCycle) / 300})`;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ ctx.restore();
+ });
+ if (simulation.cycle - templePlayer.clearedCycle > 420) level.nextLevel();
+ }
+ };
+ const LogicHandler = {
+ bounds() {
+ let isInBounds = false;
+ for (const b of bounds) {
+ if (isInBound(b)) {
+ isInBounds = true;
+ break;
+ }
+ }
+ if (!isInBounds) {
+ m.damage(0.1 * simulation.difficultyMode);
+ trapPlayer(level.enter.x, level.enter.y);
+ simulation.makeTextLog("
" + name + " : You thought I could let you get away with that?");
+ }
+ },
+ room0() {
+ // Block the player from entering the first seemingly innocuous exit
+ if ((m.pos.x > 1000) && templePlayer.startAnim === 0) {
+ spawn.mapRect(1200, -500, 100, 600);
+ templePlayer.initialTrapY = Math.min(player.position.y, -75);
+ trapPlayer(1000, templePlayer.initialTrapY);
+
+ addPartToMap();
+ simulation.draw.setPaths();
+ templePlayer.startAnim = 1;
+ }
+ },
+ room1() {
+ WaveHandler.room1();
+ Objects.altar.logic();
+ },
+ room2() {
+ room2SlimePit.logic();
+ Objects.room2Initiator.logic();
+ Objects.room2Lightning.logic();
+ Objects.room2GeneratedPath.logic();
+ WaveHandler.room2();
+ },
+ room3() {
+ Objects.room3Rotors.logic();
+ Objects.room3SlimePits.logic();
+ WaveHandler.room3();
+ },
+ exit() {
+ if (!templePlayer.drawExit) return;
+ if (player.position.x > level.exit.x &&
+ player.position.x < level.exit.x + 100 &&
+ player.position.y > level.exit.y - 150 &&
+ player.position.y < level.exit.y - 40 &&
+ player.velocity.y < 0.1 &&
+ level.exitCount + (input.down ? 8 : 2) > 100) {
+ if (templePlayer.stage === 1) {
+ templePlayer.drawExit = false;
+ level.exitCount = 0;
+ templePlayer.room1ToRoom2Anim = 1;
+ } else if (templePlayer.stage === 2) {
+ templePlayer.drawExit = false;
+ templePlayer.room2ToRoom3Anim = 1;
+ level.exitCount = 0;
+ } else {
+ level.exitCount = 99 - (input.down ? 8 : 2);
+ if (!templePlayer.clearedCycle) templePlayer.clearedCycle = simulation.cycle;
+ }
+ }
+ }
+ };
+ const DrawHandler = {
+ // Bottom layer
+ base() {
+ // Draw base red background
+ ctx.save();
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.fillStyle = color.map;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ ctx.restore();
+
+ // Draw the normal bg on the bounds
+ ctx.fillStyle = "#eab6af";
+ for (const b of bounds) {
+ if (isInBound(b)) ctx.fillRect(b.pos.x + 2, b.pos.y + 2, b.width - 4, b.height - 4);
+ }
+ },
+ entrance() {
+ ctx.beginPath();
+ ctx.moveTo(level.enter.x, level.enter.y + 30);
+ ctx.lineTo(level.enter.x, level.enter.y - 80);
+ ctx.bezierCurveTo(level.enter.x, level.enter.y - 170, level.enter.x + 100, level.enter.y - 170, level.enter.x + 100, level.enter.y - 80);
+ ctx.lineTo(level.enter.x + 100, level.enter.y + 30);
+ ctx.lineTo(level.enter.x, level.enter.y + 30);
+ ctx.fillStyle = "#fca";
+ ctx.fill();
+ },
+ room1() {
+ if (!isInBound(firstRoomBounds)) return;
+
+ // Draw Cross
+ ctx.fillStyle = "#fed";
+ ctx.fillRect(2200, -3300, 200, 800);
+ ctx.fillRect(2000, -3100, 600, 200);
+
+ // Final boss-like spawn fire thing. Was it necessary? No!
+ const spawnFlameAngle = Math.min(Math.min(templePlayer.room1.cycles, 2520) % 600, 120) * Math.PI / 30 + Math.PI / 2;
+ DrawTools.flame([2300, -3000, 26, 4, "#f60", spawnFlameAngle], 7);
+
+ Objects.altar.drawBottom();
+ },
+ room2() {
+ if (!isInBound(secondRoomBounds)) return;
+
+ if (templePlayer.room2.cycles) {
+ ctx.fillStyle = "#0006";
+ ctx.fillRect(secondRoomBounds.pos.x + 2, secondRoomBounds.pos.y + 2, secondRoomBounds.width - 4, secondRoomBounds.height - 4);
+ }
+ room2SlimePit.draw();
+ },
+ room3() {
+ if (!isInBound(thirdRoomBounds)) return;
+ ctx.fillStyle = "#0006";
+ ctx.fillRect(thirdRoomBounds.pos.x + 2, thirdRoomBounds.pos.y + 2, thirdRoomBounds.width - 4, thirdRoomBounds.height - 4);
+ Objects.room3SlimePits.draw();
+ },
+ // Top layer
+ mobTrails() {
+ if (simulation.cycle % 4 === 0) {
+ let newMobPositions = [];
+ for (const i of mob) {
+ if (!(i.isMACHO || i.isWIMP || i.isObstacle)) newMobPositions.push({
+ x: i.position.x,
+ y: i.position.y
+ });
+ }
+ mobPositionsQueue.shift();
+ mobPositionsQueue.push(newMobPositions);
+ }
+ // Draw "holy" trails for mobs for no particular reason at all
+ ctx.strokeStyle = "#bae";
+ ctx.lineWidth = 3;
+ for (let i = 0; i < 10; i++) {
+ const p = mobPositionsQueue[i];
+ for (const m of p) {
+ DrawTools.holy(m.x, m.y, i / 2 + 10);
+ }
+ }
+ ctx.shadowBlur = 0;
+ },
+ waveTimer() {
+ const roomConditions = [
+ isInBound(firstRoomBounds) && templePlayer.room1.cycles < 2400,
+ isInBound(secondRoomBounds) && templePlayer.room2.cycles > 0 && templePlayer.room2.cycles < 2160,
+ isInBound(thirdRoomBounds) && templePlayer.room2ToRoom3Anim < 1320
+ ];
+ Promise.resolve(roomConditions).then(roomConditions => {
+ // First Room
+ if (roomConditions[0]) {
+ ctx.save();
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.fillStyle = "#0004";
+ ctx.fillRect(canvas.width2 - 288, 50, 576, 20);
+ ctx.fillStyle = "#0cf";
+ ctx.fillRect(canvas.width2 - 288, 50, 0.96 * (600 - templePlayer.room1.cycles % 600), 20);
+ ctx.restore();
+ }
+ // Second Room
+ if (roomConditions[1]) {
+ ctx.save();
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.fillStyle = "#0004";
+ ctx.fillRect(canvas.width2 - 288, 50, 576, 20);
+ ctx.fillStyle = (Math.ceil(templePlayer.room2.cycles / 720) & 1) ? "#000" : "#e1d7ff";
+ ctx.fillRect(canvas.width2 - 288, 50, 0.8 * (720 - templePlayer.room2.cycles % 720), 20);
+ ctx.restore();
+ }
+ // Third Room
+ if (roomConditions[2]) {
+ ctx.save();
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.fillStyle = "#0004";
+ ctx.fillRect(canvas.width2 - 288, 50, 576, 20);
+ ctx.fillStyle = "#000";
+ ctx.fillRect(canvas.width2 - 288, 50, 1.6 * (1320 - templePlayer.room2ToRoom3Anim), 20);
+ ctx.restore();
+ }
+ });
+ },
+ room2Top() {
+ if (!isInBound(secondRoomBounds)) return;
+ Objects.room2Lightning.draw();
+ Objects.room2GeneratedPath.draw();
+ Objects.room2Initiator.draw();
+ }
+ };
+ const WaveHandler = {
+ room1() {
+ if (!isInBound(firstRoomBounds)) return;
+ if (templePlayer.room1.cycles === 0) powerUps.spawnStartingPowerUps(0, -2050);
+ templePlayer.room1.cycles++;
+ if (templePlayer.room1.cycles === 2400) {
+ spawn.secondaryBossChance(2300, -2800);
+ powerUps.addResearchToLevel();
+ }
+ if (templePlayer.room1.cycles % 600 === 0 && templePlayer.room1.cycles <= 2400) {
+ const spawnAmt = Math.min(3 + Math.pow(simulation.difficulty / 1.7, 0.6), 10) + Math.floor(templePlayer.room1.cycles / 720);
+ for (let i = 0; i < spawnAmt; i++) {
+ if (Math.random() < 0.5 + 0.07 * simulation.difficulty) {
+ spawn.randomMob(800 + Math.random() * 3e3, -2400 - Math.random() * 600, Infinity);
+ }
+ }
+ spawn.randomMob(800 + Math.random() * 3e3, -2400 - Math.random() * 600, Infinity);
+ }
+ if (templePlayer.room1.cycles === 2520) {
+ templePlayer.drawExit = true;
+ }
+ },
+ room2() {
+ if (!isInBound(secondRoomBounds)) return;
+ if (templePlayer.room2.spawnInitiatorCycles > Objects.room2Initiator.cap) {
+ const randomSecondRoomBoss = [secondRoomSuckerBoss, secondRoomPlacerBoss];
+ if (templePlayer.room2.cycles % 720 === 0 && templePlayer.room2.cycles <= 2160) {
+ const isOdd = Math.floor(templePlayer.room2.cycles / 720) & 1;
+ randomSecondRoomBoss[Math.floor(randomSecondRoomBoss.length * Math.random())](-600, -9800, isOdd);
+ randomSecondRoomBoss[Math.floor(randomSecondRoomBoss.length * Math.random())](600, -9800, isOdd);
+ randomSecondRoomBoss[Math.floor(randomSecondRoomBoss.length * Math.random())](0, -9800, !isOdd);
+ }
+ templePlayer.room2.cycles++;
+ if (templePlayer.room2.cycles === 2400) {
+ templePlayer.drawExit = true;
+ templePlayer.room2.readyPathCycle = simulation.cycle;
+ }
+ }
+ },
+ room3() {
+ if (templePlayer.room2ToRoom3Anim === 1320) {
+ thirdRoomBoss(1800, -13700);
+ for (let i = 0; i < 3; i++) {
+ powerUps.spawn(m.spawnPos.x, m.spawnPos.y, "heal");
+ }
+ }
+ }
+ };
+ const DrawTools = {
+ get randomColours() {
+ return `rgb(${this._randomColours.join(",")})`
+ },
+ _randomColours: [Math.random() * 255, Math.random() * 255, Math.random() * 255],
+ updateRandomColours(x = 0.8) {
+ for (let i = 0; i < this._randomColours.length; i++) {
+ this._randomColours[i] = Math.max(Math.min(this._randomColours[i] + (this.randFact() * x * 2) - x, 255), 0);
+ }
+ },
+ randFact() {
+ return Math.random() * 0.8 + Math.sin(Date.now() / 300) * 0.2;
+ },
+
+ line(vecs) {
+ ctx.beginPath();
+ ctx.moveTo(vecs[0].x, vecs[0].y);
+ for (const v of vecs.slice(1)) ctx.lineTo(v.x, v.y);
+ ctx.stroke();
+ },
+ arc(...x) {
+ ctx.beginPath();
+ ctx.arc(...x);
+ ctx.fill();
+ },
+ arcOut(...x) {
+ ctx.beginPath();
+ ctx.arc(...x);
+ ctx.stroke();
+ },
+ flame(props, repeat) {
+ for (let i = 0; i < repeat; i++) this.singleFlame(...props);
+ },
+ singleFlame(x, y, size = 10, repeat = 3, color = "#f00", angle = Math.PI / 2) {
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 3;
+ const path = [{
+ x,
+ y
+ }];
+ for (let i = 0; i < repeat; i++) {
+ const randAng = (Math.random() - 0.5) * 2 + angle;
+ const randLen = 2 * size + Math.random() * size;
+
+ x += Math.cos(randAng) * randLen;
+ y -= Math.sin(randAng) * randLen;
+ path.push({
+ x,
+ y
+ })
+ }
+ DrawTools.line(path);
+ },
+ lightning(from, to, cycle, randomPRNGMult = 1, width = 8, color = [255, 240, 127]) {
+ const diff = simulation.cycle - cycle;
+ if (diff >= 15) return;
+ ctx.strokeStyle = `rgba(${color.join(",")},${(1 - diff / 15) * 255})`;
+ ctx.lineWidth = width * (1 - diff / 15);
+ ctx.shadowColor = `rgb(${color.join(",")})`;
+ ctx.shadowBlur = 20;
+ const path = [{
+ x: from.x,
+ y: from.y
+ }];
+ let vector = {
+ x: from.x,
+ y: from.y
+ };
+ let distanceLeft = V.magnitude(V.sub(from, to));
+ const d = distanceLeft > 800 ? distanceLeft / 40 : 20;
+ const normalised = V.normalise(V.sub(to, from));
+ while (1) {
+ const randOffset = rotateVector({
+ y: RNG(Math.floor(cycle * randomPRNGMult + distanceLeft)) * 2 * d - d,
+ x: 0
+ }, normalised);
+ const randLen = RNG(Math.floor(cycle * (randomPRNGMult + 1) + distanceLeft)) * d + d;
+ distanceLeft -= randLen;
+ if (distanceLeft <= 0) {
+ path.push({
+ x: to.x,
+ y: to.y
+ });
+ break;
+ }
+ vector = V.add(vector, V.mult(normalised, randLen));
+ path.push({
+ x: vector.x + randOffset.x,
+ y: vector.y + randOffset.y
+ });
+ }
+ DrawTools.line(path);
+ ctx.shadowBlur = 0;
+ },
+ holy(x, y, size = 12) {
+ this.line([{
+ x,
+ y: y - size
+ }, {
+ x: x - size,
+ y
+ },
+ {
+ x,
+ y: y + size
+ }, {
+ x: x + size,
+ y
+ }, {
+ x,
+ y: y - size
+ }
+ ]);
+ }
+ };
+
+ function RNG(x) {
+ x += Math.seed;
+ let start = Math.pow(x % 97, 4.3) * 232344573;
+ const a = 15485863;
+ const b = 521791;
+ start = (start * a) % b;
+ for (let i = 0; i < (x * x) % 90 + 90; i++) {
+ start = (start * a) % b;
+ }
+ return start / b;
+ }
+
+ function rotateVector(v, ang) {
+ const c = typeof ang === "number" ? {
+ x: Math.cos(ang),
+ y: Math.sin(ang)
+ } : V.normalise(ang);
+ return {
+ x: v.x * c.x - v.y * c.y,
+ y: v.y * c.x + v.x * c.y
+ };
+ }
+
+ function trapPlayer(x, y) {
+ setPosAndFreeze(player, {
+ x,
+ y
+ });
+ const bLen = bullet.length;
+ for (let i = 0; i < bLen; i++) {
+ if (bullet[i].botType) setPosAndFreeze(bullet[i], V.add(player.position, {
+ x: 100 * (RNG(i) - 0.5),
+ y: 100 * (RNG(i + bLen) - 0.5)
+ }));
+ }
+ }
+
+ function relocateTo(x, y) {
+ level.setPosToSpawn(x, y);
+ trapPlayer(x, y);
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].isMACHO) {
+ setPos(mob[i], {
+ x,
+ y
+ });
+ break;
+ }
+ }
+ m.resetHistory();
+ }
+ const distance = (a, b) => V.magnitude(V.sub(a, b));
+ const angle = (a, b) => Math.atan2(b.y - a.y, a.x - b.x);
+ const setPos = (a, b) => Matter.Body.setPosition(a, b);
+ const setVel = (a, b) => Matter.Body.setVelocity(a, b);
+ const freeze = a => setVel(a, {
+ x: 0,
+ y: 0
+ });
+ const setPosAndFreeze = (a, b) => {
+ setPos(a, b);
+ freeze(a);
+ };
+ const makeLore = (x, t) => simulation.makeTextLog(`
${name}: ${x} `, t);
+ level.custom = () => {
+ // All the logic gets handled here. How nice!
+ for (const i in LogicHandler) {
+ LogicHandler[i]();
+ }
+
+ // Animations and lore for things that seem like exits
+ for (const i in RoomTransitionHandler) {
+ RoomTransitionHandler[i]();
+ }
+
+ // Bottom layer graphics
+ DrawHandler.base();
+ DrawHandler.room1();
+ DrawHandler.room2();
+ DrawHandler.room3();
+ DrawHandler.entrance();
+ if (templePlayer.drawExit) level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ // Top layer graphics
+ DrawHandler.mobTrails();
+ Objects.altar.drawTop();
+ DrawHandler.waveTimer();
+ DrawHandler.room2Top();
+ };
+ },
+ dripp() {
+ simulation.makeTextLog(`
dripp by
M. B. `);
+
+ const door = level.door(780, -350, 15, 400, 265);
+ const buttonDoor = level.button(420, -10);
+ const boost = level.boost(130, -445);
+ const hazard = level.hazard(690, -1050, 10, 700, 0.4)
+ const hazard2 = level.hazard(2470, -1515, 162, 14, 0.4)
+ const hazard3 = level.hazard(740, -1050, 10, 700, 0.4)
+ const hazard4 = level.hazard(3400, -380, 350, 6, 0.2)
+ const hazard5 = level.hazard(3425, -1420, 400, 8, 0.2)
+ const slimePit = level.hazard(2250, -100, 2700, 200, 0.004)
+ const door2 = level.door(3131, -898, 40, 520, 522)
+ const buttonDoor2 = level.button(2495, -270)
+ const toggle = level.toggle(1463, -708, true)
+ const elevator = level.elevator(4310, -150, 200, 50, -1443, 0.0025, {
+ up: 0.1,
+ down: 0.2
+ })
+ const portal = level.portal({ //main portals
+ x: 2117,
+ y: -1560
+ }, -2 * Math.PI, { //up
+ x: -80,
+ y: -475
+ }, -Math.PI / 100) //up
+
+ const drip1 = level.drip(4100 + 1000 * Math.random(), -1900, 50, 100) // drip(x, yMin, yMax, period = 100, color = "hsla(160, 100%, 35%, 0.5)") {
+ const drip2 = level.drip(4100 + 1000 * Math.random(), -1900, 50, 207) // drip(x, yMin, yMax, period = 100, color = "hsla(160, 100%, 35%, 0.5)") {
+ const drip3 = level.drip(4100 + 1000 * Math.random(), -1900, 50, 133) // drip(x, yMin, yMax, period = 100, color = "hsla(160, 100%, 35%, 0.5)") {
+ const drip4 = level.drip(4100 + 1000 * Math.random(), -1900, 50, 157) // drip(x, yMin, yMax, period = 100, color = "hsla(160, 100%, 35%, 0.5)") {
+
+ level.custom = () => {
+ level.exit.drawAndCheck();
+
+ drip1.draw()
+ drip2.draw()
+ drip3.draw()
+ drip4.draw()
+ buttonDoor.query();
+ buttonDoor.draw();
+ if (buttonDoor.isUp) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+
+ buttonDoor2.query();
+ buttonDoor2.draw();
+ if (buttonDoor2.isUp) {
+ door2.isClosing = true
+ } else {
+ door2.isClosing = false
+ }
+ door2.openClose();
+
+ // shadow/shades builds
+ ctx.fillStyle = "rgba(0, 0, 0, 0.05)"
+ ctx.fillRect(3169, -900, 891, 580)
+ ctx.fillRect(417, -1057, 380, 730)
+ ctx.fillRect(930, -515, 207, 520)
+ ctx.fillRect(930, -1280, 207, 760)
+ ctx.fillRect(1220, -1280, 54, 800)
+ ctx.fillRect(1221, -1394, 451, 1398)
+ ctx.fillRect(1924, -800, 219, 674)
+ ctx.fillRect(2264, -1488, 214, 1550)
+ ctx.fillRect(2631, -1488, 201, 1550)
+ ctx.fillRect(2889, -930, 237, 1090)
+ ctx.fillRect(3124, -311, 957, 360)
+ ctx.fillRect(1919, -1480, 220, 700)
+ // ctx.fillRect(1768, -1200, 71, 500)
+ level.enter.draw();
+ elevator.move();
+ toggle.query();
+ };
+ level.customTopLayer = () => {
+ boost.query();
+ hazard.opticalQuery();
+ hazard2.opticalQuery();
+ hazard3.opticalQuery();
+ hazard4.opticalQuery();
+ hazard5.opticalQuery();
+ slimePit.query();
+ // slimePit.draw();
+ hazard.isOn = toggle.isOn
+ hazard3.isOn = toggle.isOn
+ portal[0].draw();
+ portal[1].draw();
+ portal[2].draw();
+ portal[2].query()
+ portal[3].query()
+ };
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 1400;
+ level.exit.y = -1500;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d8dadf";
+
+ //builds
+ spawn.mapRect(-100, 0, 1485, 100);
+ spawn.mapRect(-279, -750, 200, 850);
+ spawn.mapRect(1781, -125, 375, 75);
+ spawn.mapRect(1670, -100, 590, 200);
+ spawn.mapRect(2261, 50, 3100, 50);
+ spawn.mapRect(2420, -260, 300, 50);
+ spawn.bodyRect(235, -240, 50, 50, 1, spawn.propSLide)
+ spawn.mapRect(410, -1100, 400, 50);
+ spawn.mapRect(1220, -1470, 420, 80)
+ spawn.mapRect(927, -1325, 220, 50);
+ spawn.mapRect(4950, -200, 425, 375);
+ spawn.bodyRect(5200, -300, 100, 100);
+
+ //random builds
+ spawn.mapRect(2150, 50, 225, 50);
+
+ //large border walls
+ spawn.mapRect(-300, -2375, 6075, 475);
+ spawn.mapRect(-951, -2374, 675, 2476);
+ spawn.mapRect(-950, 100, 6950, 500);
+ spawn.mapRect(5300, -2374, 700, 2700);
+
+ // create enemies
+ spawn.randomMob(3000, -300, 0.5);
+ spawn.randomMob(1900, -1000, 0.5);
+ spawn.randomMob(2960, -800, 0.6)
+ spawn.randomMob(3500, -1700, 0.4)
+ spawn.randomMob(800, -1700, 0.6)
+ spawn.randomMob(100, -1150, 0.6)
+ spawn.randomMob(1095, -700, 0.6)
+
+ //powerUps
+ powerUps.spawn(590, -200, "ammo")
+ powerUps.spawn(600, -200, "heal")
+ // powerUps.spawn(590, -200, "gun")
+ powerUps.spawnStartingPowerUps(590, -200);
+
+ // more builds
+ spawn.blockDoor(1230, -1490)
+ // spawn.blockDoor(728, -1130);
+ spawn.mapRect(-100, -380, 900, 50);
+ spawn.mapRect(-279, -1400, 200, 650);
+ spawn.mapRect(-279, -1900, 200, 650);
+ // spawn.mapRect(-100, -1900, 2300, 75);
+ // spawn.mapRect(2200, -1900, 1025, 75);
+ // spawn.mapRect(2700, -1900, 2000, 75);
+ spawn.mapRect(2270, -1530, 199, 50);
+ spawn.mapRect(2633, -1530, 199, 50)
+ // spawn.mapRect(4570, -1825, 125, 1925);
+ spawn.mapRect(3106, -400, 300, 50)
+ spawn.mapRect(3750, -400, 330, 50)
+ spawn.mapRect(3130, -1030, 930, 130);
+ spawn.mapRect(4015, -900, 46, 275);
+ spawn.blockDoor(4016, -400)
+ spawn.mapRect(3168, -1440, 290, 50);
+ spawn.mapRect(3771, -1440, 294, 50);
+ spawn.mapRect(3106, -355, 974, 42);
+ spawn.mapRect(3228, -1395, 834, 380);
+ spawn.mapRect(3129, -1350, 100, 325);
+ spawn.mapRect(3129, -1400, 175, 100);
+ spawn.mapRect(3129, -1437, 125, 75);
+ spawn.mapRect(1382, 0, 295, 100);
+ spawn.mapRect(1600, -50, 560, 85);
+ spawn.mapRect(2264, -945, 220, 50);
+ spawn.mapRect(1925, -800, 220, 50);
+ spawn.mapRect(1390, -700, 260, 50);
+ spawn.mapRect(927, -520, 220, 50);
+ spawn.mapRect(2894, -948, 300, 50)
+ spawn.mapRect(1230, -1825, 440, 81);
+ spawn.mapRect(1616, -1750, 54, 360);
+ spawn.mapRect(3128, -1440, 50, 50);
+ spawn.mapRect(1705, -120, 125, 75);
+ spawn.mapRect(1550, -25, 150, 50);
+ spawn.mapRect(1628, -75, 100, 50);
+ spawn.mapRect(1729, -130, 650, 75);
+ //ground for blue portal
+ spawn.mapRect(1917, -1484, 300, 50);
+ spawn.mapRect(1917, -1950, 200, 325);
+ spawn.mapRect(1917, -1825, 50, 375);
+
+ //split
+ spawn.mapRect(1221, -1420, 57, 465);
+ spawn.mapRect(1221, -634, 57, 450);
+ spawn.bodyRect(1227, -105, 42, 189, 1, spawn.propSlide)
+ // spawn.mapRect(1770, -1900, 70, 750);
+ spawn.mapRect(1770, -780, 70, 400)
+ spawn.bodyRect(1783, -289, 38, 250, 1, spawn.propSlide)
+ if (simulation.difficulty > 1) spawn.randomLevelBoss(4800, -750);
+ spawn.secondaryBossChance(4700, -1500)
+
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ biohazard() {
+ // MAP BY INOOBBOI AND THESHWARMA
+ simulation.makeTextLog(`
biohazard by
INOOBBOI and
THESHWARMA `);
+
+ // set here for the cutscene later
+ level.setPosToSpawn(-2800, -150)
+
+ // set up cutscenes
+ simulation.cutscene = (locations, speed, stay, xPos = m.pos.x, yPos = m.pos.y) => {
+ // locations: an array of location vectors, reversed for the pop ahead
+ locations.reverse()
+ // speed: the speed of the cutscene transition (0 to 1)
+ // stay: how much to stay in the destination (ticks)
+ // xPos & yPos: the initial location, also used as the current location
+
+ // start by disabling the default camera draw. Don't worry, it's backed up
+ const camera = simulation.camera
+ // create a new camera function
+ simulation.camera = () => {
+ ctx.save()
+ ctx.translate(canvas.width2, canvas.height2) //center
+ ctx.scale(simulation.zoom, simulation.zoom)
+ const xScaled = canvas.width2 - xPos
+ const yScaled = canvas.height2 - yPos
+ ctx.translate(-canvas.width2 + xScaled, -canvas.height2 + yScaled) //translate
+ }
+
+ // and set a restoring function
+ const restore = () => (simulation.camera = camera)
+
+ // then choose the next destination. There should be always at least one destination,
+ // if there isn't there's no point checking, the game should and will crash
+ let dest = locations.pop()
+ // animate the camera
+ const lerp = (first, second, percent) => first * (1 - percent) + second * percent
+ const speedDelta = speed / 5
+ // wait timer
+ let wait = 0
+ // polls the animation, should be called every tick
+ const poll = () => {
+ // update position
+ xPos = lerp(xPos, dest.x, speedDelta)
+ yPos = lerp(yPos, dest.y, speedDelta)
+ // if position is close enough, wait and go to the next position
+ const TOO_CLOSE = 100
+ if (Math.abs(dest.x - xPos) < TOO_CLOSE && Math.abs(dest.y - yPos) < TOO_CLOSE) {
+ // wait for a bit
+ if (++wait > stay) {
+ // if there is another target, reset the wait timer and go there
+ // otherwise end the cutscene
+ wait = 0
+ if (!(dest = locations.pop())) {
+ // no more locations! End
+ restore()
+ return true
+ }
+ }
+ }
+ // early return if the player skips by fielding
+ if (input.field) {
+ restore()
+ return true
+ }
+ return false
+ }
+ return poll
+ }
+
+ const boost1 = level.boost(-1400, -100, 900)
+ const boost2 = level.boost(500, -900, 2500)
+ const boost3 = level.boost(4200, -100, 900)
+ const boost4 = level.boost(2200, -900, 2500)
+
+ const toggle = level.toggle(1340, -600, false, true)
+
+ let bossInit = false
+
+ const cutscenePoll = simulation.cutscene([{
+ x: 230,
+ y: -2700
+ }, {
+ x: 3500,
+ y: -1400
+ }, {
+ x: 1450,
+ y: -1150
+ }, m.pos], 0.1, 10)
+ let hasEnded = false
+
+ // ** PROPS **
+ // create some drips
+ const rndInRange = (min, max) => Math.random() * (max - min) + min
+
+ const amount = Math.round(5 + 20 * Math.random())
+ const drips = []
+ for (let i = 0; i < amount; i++) {
+ const locX = rndInRange(-2000, 4800)
+ drips.push(level.drip(locX, -3100, 1500, 200 + Math.random() * 500))
+ }
+
+ // a barrel of radioactive waste, which can drop ammo and heals
+ const barrelMob = (x, y, dirVector) => {
+ const MAX_WIDTH = 150
+ const personalWidth = MAX_WIDTH / 2
+ mobs.spawn(x, y, 4, personalWidth, 'rgb(232, 191, 40)')
+ const me = mob[mob.length - 1]
+ // steal some vertices
+ const betterVertices = Matter.Bodies.rectangle(x, y, personalWidth, personalWidth * 1.7).vertices
+ me.vertices = betterVertices
+ me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.mob | cat.bullet
+ me.g = simulation.g
+ me.leaveBody = me.isDropPowerUp = false
+ me.do = function () {
+ this.gravity()
+ // apply shock damage when touching the map, if it's fast
+ if (this.speed > 5) {
+ const collision = Matter.Query.collides(this, map)
+ if (collision.length > 0) {
+ // on collision reduce health
+ this.health = this.health - this.speed / 250
+ // die when it's too low, doesn't register for some reason
+ }
+ }
+ // becomes more radioactive as it gets damaged!
+ this.fill = `rgb(${232 * this.health}, 191, 40)`
+ }
+
+ me.onDeath = function () {
+ const END = Math.floor(input.down ? 10 : 7)
+ const totalBullets = 10
+ const angleStep = (input.down ? 0.4 : 1.3) / totalBullets
+ let dir = m.angle - (angleStep * totalBullets) / 2
+ for (let i = 0; i < totalBullets; i++) {
+ //5 -> 7
+ dir += angleStep
+ const me = bullet.length
+ bullet[me] = Bodies.rectangle(
+ this.position.x + 50 * Math.cos(this.angle),
+ this.position.y + 50 * Math.sin(this.angle),
+ 17,
+ 4,
+ b.fireAttributes(dir)
+ )
+ const end = END + Math.random() * 4
+ bullet[me].endCycle = 2 * end + simulation.cycle
+ const speed = (25 * end) / END
+ const dirOff = dir + (Math.random() - 0.5) * 3
+ Matter.Body.setVelocity(bullet[me], {
+ x: speed * Math.cos(dirOff),
+ y: speed * Math.sin(dirOff)
+ })
+ bullet[me].onEnd = function () {
+ b.explosion(
+ this.position,
+ 150 + (Math.random() - 0.5) * 40
+ ) //makes bullet do explosive damage at end
+ }
+ bullet[me].beforeDmg = function () {
+ this.endCycle = 0 //bullet ends cycle after hitting a mob and triggers explosion
+ }
+ bullet[me].do = function () { }
+ Composite.add(engine.world, bullet[me]) //add bullet to world
+ }
+ // barrels drop a ton of ammo and some heals, scales up with difficulty because I have mercy
+ const amount = ~~(5 * Math.random() * simulation.difficulty / 10)
+ for (let i = 0; i < amount; i++) {
+ powerUps.spawn(this.position.x, this.position.y, 'ammo', true)
+ if (Math.random() > 0.7) {
+ powerUps.spawn(this.position.x, this.position.y, 'heal', true)
+ }
+ }
+ }
+ Matter.Body.rotate(me, Math.random() * Math.PI)
+ Matter.Body.setVelocity(me, dirVector)
+ }
+
+ // creates a platform with shadow
+ const platformShadow = (x, y, width, height, shadowList) => {
+ // faster than making manual shadows... Why not just calculate them semi-realsitically?
+ // the shadows are calculated on the object creation, so if you add map blocks it won't update.
+ // shadowList is an array of shadows that'll be rendered. When the platform shadow is ready,
+ // it is added to the list.
+ // some helper functions first
+ const perpCollision = point => {
+ // takes a point, and finds a collision with the map downwards
+ // the end of the ray, 3000 units down
+ const lowerPoint = Vector.add(point, {
+ x: 0,
+ y: 3000
+ })
+ // the destination point. If a collision was not found, then it defaults to some
+ // arbiterary point 3000 units down.
+ let dest = lowerPoint
+ for (const mapBody of map) {
+ const check = simulation.checkLineIntersection(point, lowerPoint, mapBody.vertices[0], mapBody.vertices[1])
+ // a collision was found
+ if (check.onLine1 && check.onLine2) {
+ dest = {
+ x: check.x,
+ y: check.y
+ }
+ break
+ }
+ }
+ return dest
+ }
+ const boundsToRectangle = (firstBound, secondBound) => {
+ // takes two bounds and returns an (x, y, width, height) rectangle. The first one
+ // must be the top left, and the second one must be the bottom right
+ // sub to find the width and height
+ const width = Math.abs(firstBound.x - secondBound.x)
+ const height = Math.abs(firstBound.y - secondBound.y)
+ // compile to an object
+ return {
+ x: firstBound.x,
+ y: firstBound.y,
+ width,
+ height
+ }
+ }
+ // create the actual platform
+ spawn.mapRect(x, y, width, height)
+ const me = map[map.length - 1]
+ // the bottom vertices are the third and fourth ones
+ const first = me.vertices[3]
+ const second = me.vertices[2]
+ // cast shadows to find the last shadow location.
+ // iterate over all map objects, and check for collisions between a perpendicular ray
+ // cast from the vertex down to the map object's top panel
+ // const firstDown = perpCollision(first) // not needed in a rectangle settings
+ const secondDown = perpCollision(second)
+ // possible TODO: make it multirect for efficiency
+ // create a single rectangle and return
+ shadowList.push(boundsToRectangle(first, secondDown))
+ }
+
+ // cages with mobs, One of them holds the boss pre mutation
+ const cage = (x, y, maxChainLength, drawList, mobType = null, isTheBoss = false) => {
+ // the drawList is an array that the drawing function is added to
+ // if the cage containing the boss it has a 50% chance to just not spawn. Spices things a bit
+ if (!isTheBoss && Math.random() > 0.5) {
+ return
+ }
+ if (!mobType) {
+ // if mob type is null, then it picks a random mob
+ mobType = spawn.fullPickList[~~(Math.random() * spawn.fullPickList.length)]
+ }
+ // create the chain length, must take into account the radius of the mob.
+ // therefore, it'll create a pseudo mob of that type, take it radius and instantly kill it
+ const chainLength = maxChainLength / 5 + maxChainLength * Math.random()
+
+ // spawn and insantly kill a mob of the same type to get the radius.
+ // this is used to prevent spawning the mob too short, it's a horrible
+ // solution but it works
+ spawn[mobType](0, 0)
+ mob[mob.length - 1].leaveBody = mob[mob.length - 1].isDropPowerUp = false
+ const radius = mob[mob.length - 1].radius
+ mob[mob.length - 1].alive = false
+ // spawn the mob. Disable shields first
+ spawn.allowShields = false
+ spawn[mobType](x, y + chainLength + radius * 2)
+ const trappedMob = mob[mob.length - 1]
+ // destroy its mind so it won't attack
+ trappedMob.do = () => { }
+ // spawn the cage
+ mobs.spawn(x, y + chainLength + radius * 2, 4, trappedMob.radius + 50, 'rgba(150, 255, 150, 0.3)')
+ const cage = mob[mob.length - 1]
+ cage.g = simulation.g
+ cage.do = function () {
+ this.gravity()
+ }
+ // label it
+ cage.label = 'Cage'
+ // a special orb when hit
+ let damageTick = 0
+ cage.onDamage = (dmg) => {
+ // add some damage ticks, if the trapped mob is still alive.
+ // activating the boss by this method is almost impossible, since you need 10x damage
+ if (trappedMob.alive) damageTick += ~~(isTheBoss ? 5 * dmg : 50 * dmg)
+ }
+ // collision filter
+ trappedMob.collisionFilter.mask = cage.collisionFilter.mask = cat.player | cat.map | cat.bullet
+ // constrain together
+ spawn.constrain2AdjacentMobs(2, 0.05, false)
+ // move them to be together
+ trappedMob.position = Vector.clone(cage.position) // make sure you clone... Otherwise........
+ // invincibility, make homing bullets not hit these, remove health bar
+ trappedMob.health = cage.health = Infinity
+ trappedMob.isBadTarget = cage.isBadTarget = true
+ trappedMob.showHealthBar = cage.showHealthBar = false
+ trappedMob.leaveBody = trappedMob.isDropPowerUp = cage.leaveBody = trappedMob.isDropPowerUp = false
+ // cross all edges of the cage with the rope, and see where it collides. Attach the rope there
+ const verts = cage.vertices
+ // the crossing location, doesn't stay null
+ let cross = null
+ for (let i = 0; i < verts.length; i++) {
+ // iterate over all vertices to form lines
+ const v1 = verts[i]
+ const v2 = verts[(i + 1) % verts.length]
+ const result = simulation.checkLineIntersection(cage.position, {
+ x,
+ y
+ }, v1, v2)
+ if (result.onLine1 && result.onLine2) {
+ // both lines cross!
+ cross = result
+ break
+ }
+ }
+
+ if (!cross) {
+ // for some odd reason, sometimes it never finds a collision. I have no idea why
+ // just default to the center then
+ console.error("Couldn't find a cross... Origin: ", {
+ x,
+ y
+ }, " center: ", cage.position, ' vertices: ', cage.vertices)
+ cross = cage.position
+ }
+ // create the rope
+ const rope = Constraint.create({
+ pointA: {
+ x,
+ y
+ },
+ // offset the point be in the attachment point
+ pointB: Vector.sub(cross, cage.position),
+ bodyB: cage,
+ // the longer the rope, the looser it is
+ stiffness: Math.max(0.0005 - chainLength / 10000000, 0.00000001),
+ length: chainLength
+ })
+ Matter.Composite.add(engine.world, rope)
+ // create and return a function for drawing the rope
+ const draw = () => {
+ // draw a little recantagle at the base
+ ctx.fillStyle = color.map
+ ctx.fillRect(x - 20, y - 5, 40, 25)
+ // if the cage was destroyed... Do nothing beyond
+ if (!cage.alive) {
+ return
+ }
+ // draw the rope
+ ctx.beginPath()
+ ctx.moveTo(x, y)
+ // line to the crossing point
+ // ctx.lineTo(cons[i].bodyB.position.x, cons[i].bodyB.position.y);
+ ctx.lineTo(cage.position.x + rope.pointB.x, cage.position.y + rope.pointB.y);
+ ctx.lineWidth = 7
+ ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)'
+ ctx.stroke()
+ // now draw a mystic hit orb if touched
+ if (damageTick) damageTick-- // reduce the ticks
+ ctx.beginPath()
+ ctx.arc(cage.position.x, cage.position.y, cage.radius + 30, 0, Math.PI * 2)
+ ctx.lineWidth = 10
+ ctx.fillStyle = `rgba(255, 0, 0, ${Math.min(1, damageTick / 2000)})`
+ ctx.strokeStyle = `rgba(255, 100, 0, ${Math.min(1, damageTick / 1000)})`
+ ctx.setLineDash([125 * Math.random(), 125 * Math.random()])
+ ctx.stroke()
+ ctx.setLineDash([])
+ ctx.fill()
+ // if it's the boss, draw sucking arcs
+ if (isTheBoss && bossInit) {
+ for (const entity of mob) {
+ // suck the health of all mobs
+ // I hate string manipulation in control flow but heh
+ if (entity.alive) {
+ ctx.beginPath()
+ ctx.moveTo(entity.position.x, entity.position.y)
+ ctx.lineTo(trappedMob.position.x, trappedMob.position.y)
+ ctx.lineWidth = 10
+ ctx.strokeStyle = 'rgba(38, 0, 255, 0.67)'
+ ctx.stroke()
+ // damage the mob
+ entity.damage(1)
+ // damage itself bonus
+ cage.damage(1)
+ }
+ }
+ cage.damage(5)
+ }
+
+ // ok if it's too much, explode
+ if (damageTick > 2000) {
+ b.explosion(cage.position, cage.radius * 10)
+ // die a silent death
+ trappedMob.alive = cage.alive = false
+ damageTick = 0
+ if (isTheBoss) {
+ // become the real boss
+ geneticBoss(trappedMob.position.x, trappedMob.position.y)
+ }
+ }
+ }
+ // restore the shields
+ spawn.allowShields = true
+ // add the drawing function
+ drawList.push(draw)
+ }
+
+ // platform shadows
+ const shadows = []
+ // cages
+ const cages = []
+
+ level.custom = () => {
+ level.exit.drawAndCheck() //draws the exit
+ level.enter.draw() //draws the entrance
+
+ player.force.y -= player.mass * simulation.g * 0.25 //this gets rid of some gravity on player
+
+ // if the cutscene is yet to end, continue polling
+ if (!hasEnded) {
+ hasEnded = cutscenePoll()
+ }
+
+ for (const drip of drips) drip.draw()
+ // throw some barrels after the boss spawns
+ if (Math.random() > 0.999 && bossInit && !hasEnded) {
+ const spawnLocs = [-1415, -30, 1345, 2815, 4285]
+ // const randVec = Vector.mult({ x: Math.cos(randAngle), y: Math.sin(randAngle) }, Math.random() * 15)
+ barrelMob(spawnLocs[~~(spawnLocs.length * Math.random())], -4200, {
+ x: 0,
+ y: 0
+ })
+ }
+
+ // platform shadow
+ ctx.beginPath()
+ for (const shadow of shadows) {
+ ctx.rect(shadow.x, shadow.y, shadow.width, shadow.height)
+ }
+ ctx.fillStyle = 'rgba(0,10,30,0.1)'
+ ctx.fill()
+
+ // player pressed lever
+ if (toggle.isOn && !bossInit) {
+ bossInit = true
+ }
+ // draw the cage
+ } //for dynamic stuff that updates while playing that is one Z layer below the player
+
+ level.customTopLayer = () => {
+ boost1.query()
+ boost2.query()
+ boost3.query()
+ boost4.query()
+ toggle.query()
+
+ // shadow holes
+ ctx.fillStyle = 'rgba(68, 68, 68,0.95)'
+ ctx.fillRect(-1450 - 10, -4350, 150 + 20, 1250)
+ ctx.fillRect(-50 - 10, -4350, 150 + 20, 1250)
+ ctx.fillRect(1325 - 10, -4350, 150 + 20, 1250)
+ ctx.fillRect(2800 - 10, -4350, 150 + 20, 1250)
+ ctx.fillRect(4275 - 10, -4350, 150 + 20, 1250)
+
+ for (const drawCage of cages) {
+ drawCage()
+ }
+ } //for dynamic stuff that updates while playing that is one Z layer above the player
+
+ const anotherBoss = (x, y) => {
+ if (tech.isDuplicateMobs && Math.random() < tech.duplicationChance()) {
+ tech.isScaleMobsWithDuplication = true
+ spawn.historyBoss(x, y)
+ tech.isScaleMobsWithDuplication = false
+ } else if (tech.isResearchBoss) {
+ if (powerUps.research.count > 2) {
+ powerUps.research.changeRerolls(-3)
+ simulation.makeTextLog(
+ `
m .
research -= 3
${powerUps.research.count}`
+ )
+ } else {
+ tech.addJunkTechToPool(0.49)
+ }
+ spawn.historyBoss(x, y)
+ }
+ }
+
+ //GENETICBOSS
+ function drawEnergyBar(mob) {
+ if (mob.seePlayer.recall && mob.energy > 0) {
+ const h = mob.radius * 0.3
+ const w = mob.radius * 2
+ const x = mob.position.x - w / 2
+ const y = mob.position.y - w * 0.9
+ ctx.fillStyle = 'rgba(100, 100, 100, 0.3)'
+ ctx.fillRect(x, y, w, h)
+ ctx.fillStyle = '#0cf'
+ ctx.fillRect(x, y, w * mob.energy, h)
+ }
+ }
+
+ function generateGenome() {
+ // creates a random genome and returns it
+ const genome = {
+ density: Math.random() * 0.001,
+ size: 15 + Math.random() * 15,
+ speed: Math.random() * 0.1,
+ // color and vertex properties are "trash" genes as they don't really contribute to the orb
+ color: [Math.random() * 255, Math.random() * 255, Math.random() * 255, 50 + Math.random() * 205],
+ vertexCount: Math.floor(Math.random() * 5) + 3,
+ // TODO fix possible concaving
+ vertexOffset: null // placeholder
+ }
+ // initialized here as it depends on vertexCount. I could use `new function()` but nah.
+ genome.vertexOffset = Array(genome.vertexCount)
+ .fill()
+ .map(() => ({
+ x: Math.random() - 0.5,
+ y: Math.random() - 0.5
+ }))
+ return genome
+ }
+
+ function mutateGenome(genome) {
+ // takes an existing genome and applies tiny changes
+ const randomInRange = (min, max) => Math.random() * (max - min) + min
+ const tinyChange = x => randomInRange(-x, x)
+
+ const vertexMutator = x => ({
+ x: x.x + tinyChange(0.5),
+ y: x.y + tinyChange(0.5)
+ })
+ // mutates a genome and returns the mutated version.
+ const newGenome = {
+ density: genome.density + tinyChange(0.0005),
+ size: genome.size + tinyChange(5),
+ speed: genome.speed + tinyChange(0.05),
+ color: genome.color.map(x => (x + tinyChange(10)) % 255), // wrap around
+ vertexCount: Math.max(genome.vertexCount + Math.round(tinyChange(1)), 3),
+ vertexOffset: genome.vertexOffset.map(vertexMutator)
+ }
+ if (genome.vertexOffset.length < newGenome.vertexCount) {
+ const vo = newGenome.vertexOffset
+ vo.push(vertexMutator(vo[~~(vo.length * Math.random())]))
+ } else if (genome.vertexOffset.length > newGenome.vertexCount) {
+ newGenome.vertexOffset.pop()
+ }
+
+ return newGenome
+ }
+
+ function calculateGenomeCost(genome) {
+ // calculates the cost of a genome and returns it. The cost is used to
+ // determine how "costly" the genome is to make, and after the orb's life ends it
+ // is used together with the orb success score to determine the fittest orb.
+ const score = (1 / (genome.density * genome.size * genome.speed)) * 0.000001
+ return score
+ }
+ // distance functions
+ const dist2 = (a, b) => (a.x - b.x) ** 2 + (a.y - b.y) ** 2
+ const dist = (a, b) => Math.sqrt(dist2(a, b))
+
+ // ** MAP SPECIFIC MOBS **
+ function energyTransferBall(origin, target, boss, charge) {
+ // transports energy to the boss
+ // when the boss is hit by it, how much of the energy stored the boss actually recives
+ const ENERGY_TRANSFER_RATE = 80 /*%*/
+ // add 1 to the active ball list
+ boss.activeBalls++
+ const color = `rgba(${150 + 105 * charge}, 81, 50, 0.6)`
+ mobs.spawn(origin.x, origin.y, 12, 20 + 20 * charge, color)
+ const me = mob[mob.length - 1]
+ me.end = function () {
+ simulation.drawList.push({
+ // some nice graphics
+ x: this.position.x,
+ y: this.position.y,
+ radius: this.radius,
+ color: '#f3571d',
+ time: ~~(Math.random() * 20 + 10)
+ })
+ // on death spawn and explode a bomb
+ if (Math.random() > 0.95) {
+ spawn.bomb(this.position.x, this.position.y, this.radius, this.vertices.length)
+ mob[mob.length - 1].death()
+ }
+ // remove 1 from the active ball list
+ boss.activeBalls--
+ this.death()
+ }
+ me.collisionFilter.mask = cat.player | cat.map
+ // me.onHit = this.end
+ me.life = 0
+ me.isDropPowerUp = false
+ me.leaveBody = false
+ me.do = function () {
+ // die on collision with the map
+ if (Matter.Query.collides(this, map).length > 0) {
+ this.end()
+ }
+ // die if too much time passes. Stronger bullets explode earlier
+ if (++this.life > 200 - charge * 100) {
+ this.end()
+ }
+ // if the orb collides with the boss, die but give energy to the boss
+ if (Matter.Query.collides(this, [boss]).length > 0) {
+ boss.energy = Math.min(charge * (ENERGY_TRANSFER_RATE / 100) + boss.energy, 1)
+ // also make the boss fire once regardless of energy
+ boss.spawnOrbs()
+ this.end()
+ }
+ const movement = Vector.normalise(Vector.sub(target, origin))
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x + movement.x,
+ y: this.velocity.y + movement.y
+ })
+ // nice graphics
+ simulation.drawList.push({
+ x: this.position.x,
+ y: this.position.y,
+ radius: this.radius,
+ color: '#e81e1e',
+ time: 3
+ })
+ simulation.drawList.push({
+ x: this.position.x,
+ y: this.position.y,
+ radius: this.radius,
+ color: '#e87f1e',
+ time: 6
+ })
+ simulation.drawList.push({
+ x: this.position.x,
+ y: this.position.y,
+ radius: this.radius,
+ color: '#e8e41e',
+ time: 9
+ })
+ }
+ me.onDamage = me.end
+ }
+
+ function energyBeacon(x, y, parentBoss) {
+ // an unmoving beacon that charges the genetic boss with energy either stolen
+ // from the player or generated. That energy is used to create stronger mobs.
+ mobs.spawn(x, y, 3, 50, '') // default color, changed an instant later
+ const me = mob[mob.length - 1]
+ me.laserRange = 500
+ me.leaveBody = false
+ me.isDropPowerUp = false
+ // custom variables
+ // max energy is 1
+ me.energy = 0
+ me.seed = simulation.cycle // seed to make sure this mob is unique render wise
+ me.chargeTicks = 0 // used to time charging the boss
+ me.bossPos = null // the position that the mob remembers when charging
+ me.density = me.density * 2
+ Matter.Body.setDensity(me, 0.0022 * 3 + 0.0002 * Math.sqrt(simulation.difficulty)) //extra dense
+ me.do = function () {
+ // if the boss is dead, die
+ if (!parentBoss.alive) {
+ this.death()
+ }
+ // slowly rotate
+ Matter.Body.setAngularVelocity(this, 0.01)
+ this.fill = `rgba(${this.energy * 255}, 29, 136, 0.80)`
+ this.seePlayerCheck()
+ // steal energy from player
+ // this.harmZone() // regular harmZone
+ // custom effects on top of that
+ if (this.distanceToPlayer() < this.laserRange) {
+ if (m.immuneCycle < m.cycle) {
+ // suck extra energy from the player if it's in range
+ if (m.energy > 0.1 && this.energy < 1 - 0.012) {
+ m.energy -= 0.012
+ this.energy += 0.012
+ }
+ // special "sucking" graphics
+ ctx.beginPath()
+ ctx.moveTo(this.position.x, this.position.y)
+ ctx.lineTo(m.pos.x, m.pos.y)
+ ctx.lineWidth = 3 + Math.abs(Math.sin((simulation.cycle + this.seed) / 100)) * 2
+ ctx.strokeStyle = `rgb(${(
+ Math.abs(Math.sin((simulation.cycle + this.seed + 100) / 100)) * 255
+ ).toFixed(3)}, 204, 255)`
+ ctx.setLineDash([125 * Math.random(), 125 * Math.random()])
+ ctx.stroke()
+ ctx.setLineDash([])
+ }
+ }
+ // if the mob's energy is at least 50% full, try to send that energy to the boss.
+ // don't send that energy yet if more than 5 other transfer balls are active
+ if (this.energy > 0.5 && parentBoss.energy < 1 && parentBoss.activeBalls <= 5 && this.chargeTicks === 0) {
+ const seesBoss = Matter.Query.ray(map, this.position, parentBoss.position).length === 0
+ if (seesBoss) {
+ this.chargeTicks = 100
+ this.bossPos = Vector.clone(parentBoss.position)
+ }
+ }
+ if (this.chargeTicks > 0) {
+ if (--this.chargeTicks === 0) {
+ // spawn the orb
+ const location = Vector.add(
+ Vector.mult(Vector.normalise(Vector.sub(this.bossPos, this.position)), this.radius * 3),
+ this.position
+ )
+ energyTransferBall(location, this.bossPos, parentBoss, this.energy)
+ this.energy = 0
+ }
+ // create a beam and aim it at the bossPos
+ ctx.beginPath()
+ ctx.moveTo(this.position.x, this.position.y)
+ ctx.lineTo(this.bossPos.x, this.bossPos.y)
+ ctx.lineWidth = 10 + Math.abs(Math.sin((simulation.cycle + this.seed) / 100)) * 5
+ ctx.strokeStyle = `rgb(${(
+ Math.abs(Math.sin((simulation.cycle + this.seed + 100) / 100)) * 255
+ ).toFixed(3)}, 204, 255)`
+ ctx.setLineDash([125 * Math.random(), 125 * Math.random()])
+ ctx.stroke()
+ ctx.setLineDash([])
+ }
+ // generate (0.15 * difficulty / 4)% energy per tick
+ if (this.energy < 1) this.energy += 0.0015 * (simulation.difficulty / 4)
+ // draw energy bar
+ drawEnergyBar(this)
+ }
+ me.onDeath = function () {
+ // remove itself from the list
+ const beacons = parentBoss.energyBeacons
+ beacons.splice(beacons.indexOf(this), 1)
+ // explode with the strength of its energy!
+ this.alive = false // to prevent retriggering infinitly
+ b.explosion(this.position, this.energy * this.radius * 15)
+ // when it dies, it reduces some of the boss' energy
+ parentBoss.energy -= 0.025
+ // and stuns it
+ mobs.statusStun(parentBoss, 70 + ~~(100 / simulation.difficulty))
+ }
+ }
+
+ function geneticSeeker(x, y, genome, parentBoss) {
+ // special bullets that get score based on their performance.
+ mobs.spawn(x, y, genome.vertexCount, genome.size, '#' + genome.color.map(it => (~~it).toString(16)).join(''))
+ const me = mob[mob.length - 1]
+ // apply genome
+ Matter.Body.setDensity(me, genome.density)
+ me.accelMag = genome.speed
+ // apply vertex offset
+ for (let i = 0; i < me.vertices.length; i++) {
+ const vertex = me.vertices[i]
+ const offset = genome.vertexOffset[i]
+ if (!offset) console.log(genome, me)
+ vertex.x += offset.x
+ vertex.y += offset.y
+ }
+
+ me.stroke = 'transparent'
+ Matter.Body.setDensity(me, 0.00001) //normal is 0.001
+ // increased if the orb done things that are deemed successful
+ me.score = 30
+ me.timeLeft = 9001 / 9
+ me.accelMag = 0.00017 * simulation.accelScale //* (0.8 + 0.4 * Math.random())
+ me.frictionAir = 0.01
+ me.restitution = 0.5
+ me.leaveBody = false
+ me.isDropPowerUp = false
+ me.isBadTarget = true
+ me.isMobBullet = true
+ me.showHealthBar = false
+ me.collisionFilter.category = cat.mobBullet
+ me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet
+ me.do = function () {
+ this.alwaysSeePlayer()
+ this.attraction()
+ this.timeLimit()
+
+ if (Matter.Query.collides(this, map).length > 0) {
+ // colliding with the map gives a score reduction, 0.5 per tick
+ this.score -= 0.5
+ }
+ // default score is slowly reduced every tick to give mobs that reached the player faster a benefit
+ this.score -= 0.05
+ if (this.score < 0) {
+ this.alive = false // no point continuing if this orb is that bad! Silent death
+ }
+ // give a bonus if some projectile is nearby or the mouse position is close (like laser pointing)
+ // if a mob survives this for long, then it gets a score benefit.
+ const bulletCloseToOrb = bullet.some(it => dist2(this.position, it.position) < 10000 /* 100 ^ 2 */)
+ // player shoots and aims close
+ const mouseCloseToOrb = dist2(this.position, simulation.mouseInGame) < 10000 && input.fire
+ if (bulletCloseToOrb || mouseCloseToOrb) {
+ this.score += 1
+ }
+ // die if too far from the boss... It would be incredibly difficult to dodge otherwise
+ if (dist2(this.position, parentBoss.position) > 2000 * 2000) {
+ this.alive = false
+ }
+ // DEBUG score printer
+ // ctx.font = '48px sans-serif'
+ // ctx.fillStyle = 'rgba(252, 0, 143, 1)'
+ // ctx.fillText(~~this.score, this.position.x - this.radius, this.position.y - this.radius)
+ }
+ me.onHit = function () {
+ // hitting the player gives a 50 points score bonus
+ this.score += 50
+ this.score += this.mass * 2 // bigger mass = bigger damage, add that too
+ // a marker for later
+ this.hitPlayer = true
+ this.explode(this.mass)
+ }
+ me.onDeath = function () {
+ if (!this.hitPlayer) {
+ // if it didn't hit the player, give it a score based on its distance
+ this.score += 10000 / this.distanceToPlayer()
+ }
+ // 3% chance to drop ammo
+ if (Math.random() > 0.97) {
+ powerUps.spawn(this.position.x, this.position.y, 'ammo', true)
+ }
+ parentBoss.deadOrbs.push({
+ genome: genome,
+ score: this.score
+ })
+ }
+ }
+
+ function geneticBoss(x, y, radius = 130, spawnBossPowerUp = true) {
+ // a modified orb shooting boss that evolves its orbs.
+ // the way this boss works is different from the regular orb shooting boss,
+ // because the orbs have evolving properties via a "machine learning" scoring algorithm.
+ const MAX_BEACONS = Math.round(3 + Math.random() * simulation.difficulty / 3)
+ mobs.spawn(x, y, 8, radius, 'rgb(83, 32, 58)')
+ let me = mob[mob.length - 1]
+ me.isBoss = true
+
+ me.accelMag = 0.0001 * simulation.accelScale
+ me.fireFreq = Math.floor((330 * simulation.CDScale) / simulation.difficulty)
+ me.frictionStatic = 0
+ me.friction = 0
+ me.frictionAir = 0.02
+ me.memory = (420 / 69) * 42 // 🧌
+ me.repulsionRange = 1000000
+ me.energyBeacons = []
+ me.activeBalls = 0
+ // starts by random, or by the stored genomes if they exist
+ const init = () => ({
+ genome: generateGenome(),
+ score: 0
+ })
+ me.fittestOrbs = (localStorage && localStorage.genome) ? JSON.parse(localStorage.genome) : [init(), init(), init()] // best genomes so far. Size of three
+ // when an orb died it's moved here. When a new spawn cycle starts, their scores get calculated
+ // and they get put in the fittest orbs array, if they are better than the old ones.
+ me.deadOrbs = []
+ me.energy = 1
+ // this boss has no orbitals, because it's not meant to ever attack on its own
+ me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ // has a shield and sustains that shield
+ spawn.shield(me, x, y, Infinity)
+ me.fireFreq = 30
+ me.ionizeFreq = 20
+ me.ionized = []
+ me.laserRange = radius * 4
+
+ Matter.Body.setDensity(me, 0.0022 * 4 + 0.0002 * Math.sqrt(simulation.difficulty)) //extra dense //normal is 0.001 //makes effective life much larger
+ me.onDeath = function () {
+ if (spawnBossPowerUp) {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ const amount = ~~(5 * Math.random() * simulation.difficulty / 10) * 2
+ for (let i = 0; i < amount; i++) {
+ powerUps.spawn(this.position.x, this.position.y, 'ammo', true)
+ if (Math.random() > 0.7) {
+ powerUps.spawn(this.position.x, this.position.y, 'heal', true)
+ }
+ }
+ }
+ // keep the best genome and use it next fight...
+ if (localStorage) {
+ localStorage.setItem("genome", JSON.stringify(this.fittestOrbs))
+ }
+
+ // stop spawning barrels
+ bossInit = false
+ }
+ me.onDamage = function () { }
+ me.spawnBeacon = function () {
+ // the vertex to spawn the beacon from
+ const vert = this.vertices[~~(Math.random() * this.vertices.length)]
+ // the position should be a little to the side to prevent crashing into the boss
+ // TODO check for collisions with the wall
+ const spawnPos = Vector.add(vert, Vector.mult(Vector.normalise(Vector.sub(this.position, vert)), -60))
+ // some velocity
+ const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, vert)), -5)
+ energyBeacon(spawnPos.x, spawnPos.y, this) // spawn the beacon, a bit ahead
+ const beacon = mob[mob.length - 1]
+ this.energyBeacons.push(beacon)
+ Matter.Body.setVelocity(beacon, {
+ x: this.velocity.x + velocity.x,
+ y: this.velocity.y + velocity.y
+ })
+ }
+ me.spawnOrbs = function () {
+ Matter.Body.setAngularVelocity(this, 0.11)
+ // sort the vertices by the distance to the player
+ const sorted = [...this.vertices].sort(dist2)
+ // spawn the bullets based on how close they are to the player.
+ // the way it works is it picks the fittest three orbs and clones them.
+ // but start by taking old mobs and checking if they are better than the new ones
+ let next
+ while ((next = this.deadOrbs.pop())) {
+ // material costs are calculated as a contra to the score
+ const cost = calculateGenomeCost(next.genome) * 500 // normalize via multiplication
+ const totalScore = next.score - cost
+ // try to insert itself into the best orbs, if it can
+ for (let i = 0; i < this.fittestOrbs.length; i++) {
+ const fitEntry = this.fittestOrbs[i]
+ if (fitEntry.score < totalScore) {
+ this.fittestOrbs[i] = next
+ break
+ }
+ }
+ }
+ // finally sort them using their score
+ this.fittestOrbs.sort((a, b) => a.score - b.score)
+ // only take the genome, the score doesn't matter here
+ const bestOrbs = this.fittestOrbs.map(it => it.genome)
+ for (let vertex of sorted) {
+ // pick a random fit orb and try to spawn it. If the cost is too high, it'll attempt
+ // to generate a new random orb instead. If that orb is too expensive too, just ignore this vertex.
+ // the evolution part comes here, as the genome is mutated first.
+ let randGenome = mutateGenome(bestOrbs[~~(Math.random() * bestOrbs.length)])
+ const cost = calculateGenomeCost(randGenome) * 2
+ if (this.energy - cost < 0) {
+ // okay this orb is too expensive for the boss to spawn,
+ // make a new orb from scratch
+ randGenome = generateGenome()
+ const secondCost = calculateGenomeCost(randGenome)
+ if (this.energy - secondCost < 0) {
+ // that was too expensive too, heh
+ continue
+ }
+ } else {
+ // alright the boss can afford that
+ this.energy -= Math.abs(cost) // TODO: Fix this, why the heck can it even be negative??
+ }
+
+ geneticSeeker(vertex.x, vertex.y, randGenome, this)
+ // give the bullet a rotational velocity as if they were attached to a vertex
+ const velocity = Vector.mult(
+ Vector.perp(Vector.normalise(Vector.sub(this.position, vertex))),
+ -10
+ )
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + velocity.x,
+ y: this.velocity.y + velocity.y
+ })
+ }
+ }
+ me.do = function () {
+ this.seePlayerCheck()
+ this.checkStatus()
+ this.attraction()
+ this.repulsion()
+ // draw laser arcs if it sees the player
+ this.harmZone()
+ //
+ const regularChance = Math.random() > 0.99
+ const biggerChance = Math.random() > 0.95 && this.energy > 0.25
+ // start by making sure there is always at least one beacon
+ if (this.energyBeacons.length === 0) {
+ this.spawnBeacon()
+ }
+ // then, spawn some energy beacons if there are less than the maximum.
+ // small chance if there's no energy, bigger chance if there is at least 10% (which is drained)
+ if ((this.energyBeacons.length < MAX_BEACONS && biggerChance) || regularChance) {
+ if (biggerChance) {
+ // if the spawn was a selection of bigger chance, reduce 10% energy
+ this.energy -= 0.10
+ }
+ this.spawnBeacon()
+ }
+ // then, spawn genetic seekers
+ if (this.seePlayer.recall && !(simulation.cycle % this.fireFreq)) {
+ // fire a bullet from each vertex if there's enough energy
+ if (this.energy > 0.15) {
+ this.spawnOrbs()
+ }
+ }
+
+ if (this.energy > 1) {
+ // clean excess energy
+ this.energy -= 0.003
+ } else {
+ // or slowly generate energy
+ this.energy += 0.001
+ }
+ // the boss will ionize every bullet in its radius, but that will cause its energy to deplete
+ if (!(simulation.cycle % this.ionizeFreq)) {
+ for (let i = 0; i < bullet.length; i++) {
+ const it = bullet[i]
+ // if it's not a bot and it's close
+ if (!it.botType && dist(this.position, it.position) < this.laserRange) {
+ // add it to the ionized list
+ this.ionized.push({
+ target: it,
+ ticks: 0
+ })
+ }
+ }
+ }
+
+ for (let i = 0; i < this.ionized.length; i++) {
+ const entry = this.ionized[i]
+
+ // skip if there's not enough energy
+ if (this.energy <= 0) break
+
+ // terminate if it's no longer in the radius
+ if (dist(this.position, entry.target.position) > this.laserRange) {
+ this.ionized.splice(i, 1)
+ continue
+ }
+ // terminate after some ticks
+ if (++entry.ticks === 10) {
+ entry.target.endCycle = 0
+ // draw nice popping graphics
+ simulation.drawList.push({
+ x: entry.target.position.x,
+ y: entry.target.position.y,
+ radius: 5,
+ color: '#f24',
+ time: ~~(Math.random() * 20 + 10)
+ })
+ // and remove
+ this.ionized.splice(i, 1)
+ continue
+ }
+ // draw line
+ ctx.beginPath()
+ ctx.moveTo(this.position.x, this.position.y)
+ ctx.lineTo(entry.target.position.x, entry.target.position.y)
+ ctx.lineWidth = 7
+ ctx.strokeStyle = `rgb(${60 - entry.ticks * 2}, 50, 50)`
+ ctx.stroke()
+ // reduce energy, as it's hard to ionize
+ this.energy -= entry.target.mass / 25
+ }
+
+ // if it has energy, shield itself and drain energy
+ if (!this.isShielded && this.energy > 0.5) {
+ spawn.shield(this, this.position.x, this.position.y, Infinity)
+ this.energy -= 0.25
+ }
+ drawEnergyBar(this)
+ // change fill color
+ this.fill = `rgb(${((Math.sin(simulation.cycle / 100) + 1) / 2) * 100}, 32, 58)`
+ }
+ // start by spawning several beacons to gain initial energy
+ const amount = Math.ceil(2 + Math.random() * simulation.difficulty / 5)
+ for (let i = 0; i < amount; i++)
+ me.spawnBeacon()
+ }
+
+ // LEVEL SETUP
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20) //don't change this
+
+ level.exit.x = 5700 //you exit at x
+ level.exit.y = -130 //you exit at y
+ spawn.mapRect(5800, -110, -100, 10)
+
+ level.defaultZoom = 2000 //how far out you want the image to be zoomed at (lower = zoom in, higher = zoom out)
+ simulation.zoomTransition(level.defaultZoom) //makes the level transition to have the zoom at the start of a level
+ document.body.style.backgroundColor = 'hsl(138, 3%, 74%)' //sets background color
+
+ //LEVEL STRUCTURE
+ spawn.mapRect(-3100, -100, 9200, 100)
+ spawn.mapRect(-3100, -600, 100, 500)
+ spawn.mapRect(-3100, -600, 1100, 100)
+ spawn.mapRect(-2100, -3100, 100, 2700)
+ spawn.mapRect(4800, -3100, 100, 2600)
+ spawn.mapRect(4800, -600, 1300, 100)
+ spawn.mapRect(6000, -600, 100, 600)
+
+ spawn.mapRect(400, -200, 2000, 100)
+ spawn.mapRect(600, -300, 1600, 100)
+ spawn.mapRect(800, -400, 1200, 100)
+ spawn.mapRect(1000, -500, 800, 100)
+ spawn.mapRect(1200, -600, 400, 100)
+ // roof
+ spawn.mapRect(-2100, -4350, 650, 1250)
+ spawn.mapRect(-1300, -4350, 1250, 1250)
+ spawn.mapRect(100, -4350, 1225, 1250)
+ spawn.mapRect(1475, -4350, 1325, 1250)
+ spawn.mapRect(2950, -4350, 1325, 1250)
+ spawn.mapRect(4425, -4350, 475, 1250)
+
+ // arc
+ // spawn.mapVertex(1400, -892, '700, -800, 700, -900, 1000, -1000, 1800, -1000, 2100, -900, 2100, -800')
+
+
+ //PLATFORMS
+ platformShadow(-1200, -500, 300, 100, shadows)
+ platformShadow(-400, -700, 300, 100, shadows)
+ platformShadow(400, -900, 300, 100, shadows)
+ platformShadow(-2000, -800, 300, 100, shadows)
+ platformShadow(-1000, -1000, 300, 100, shadows)
+ platformShadow(-400, -1300, 300, 100, shadows)
+ platformShadow(-1600, -1300, 300, 100, shadows)
+ platformShadow(-1300, -1600, 300, 100, shadows)
+ platformShadow(-2000, -1700, 300, 100, shadows)
+ platformShadow(-700, -1800, 300, 100, shadows)
+ platformShadow(-1500, -2100, 300, 100, shadows)
+ platformShadow(-600, -2200, 300, 100, shadows)
+ platformShadow(-2000, -2500, 300, 100, shadows)
+ platformShadow(-1100, -2400, 300, 100, shadows)
+ platformShadow(-500, -2700, 300, 100, shadows)
+ platformShadow(100, -2400, 300, 100, shadows)
+ platformShadow(700, -2700, 300, 100, shadows)
+
+ platformShadow(3700, -500, 300, 100, shadows)
+ platformShadow(2900, -700, 300, 100, shadows)
+ platformShadow(2100, -900, 300, 100, shadows)
+ platformShadow(4500, -800, 300, 100, shadows)
+ platformShadow(3500, -1000, 300, 100, shadows)
+ platformShadow(4100, -1300, 300, 100, shadows)
+ platformShadow(2900, -1300, 300, 100, shadows)
+ platformShadow(3800, -1600, 300, 100, shadows)
+ platformShadow(4500, -1700, 300, 100, shadows)
+ platformShadow(3200, -1800, 300, 100, shadows)
+ platformShadow(4000, -2100, 300, 100, shadows)
+ platformShadow(3100, -2200, 300, 100, shadows)
+ platformShadow(4500, -2500, 300, 100, shadows)
+ platformShadow(3600, -2400, 300, 100, shadows)
+ platformShadow(3000, -2700, 300, 100, shadows)
+ platformShadow(2400, -2400, 300, 100, shadows)
+ platformShadow(1800, -2700, 300, 100, shadows)
+
+ // cages
+ cage(-1492, -1200, 100, cages)
+ cage(-875, -2300, 300, cages)
+ cage(-1600, -3100, 1000, cages)
+ cage(225, -2300, 1000, cages)
+ cage(-750, -3100, 700, cages)
+ cage(-625, -1700, 1200, cages)
+ cage(2200, -3100, 500, cages)
+ cage(3275, -1700, 500, cages)
+ cage(3650, -900, 300, cages)
+ cage(2500, -2300, 300, cages)
+ cage(3625, -2300, 300, cages)
+ cage(3875, -1500, 300, cages)
+ cage(4025, -3100, 300, cages)
+
+ // boss cage
+ platformShadow(1275, -2150, 250, 100, shadows)
+ cage(1400, -2050, 500, cages, 'starter', true)
+ map[map.length] = Bodies.trapezoid(1400, -2193, 250, 100, 0.5)
+ //DEBRIS
+ //idk just put the debris wherever you want
+ spawn.debris(-550, -225, 100)
+ spawn.debris(-1150, -1725, 75)
+ spawn.debris(-275, -1400, 50)
+ spawn.debris(2850, -2075, 150)
+ spawn.debris(4250, -2250, 150)
+ //BOSS
+ // geneticBoss(1400, -3800)
+ anotherBoss(0, 0) //will only spawn historyBoss if there is an additional boss
+ },
+ stereoMadness() {
+ simulation.makeTextLog(`
stereoMadness by
Richard0820 `);
+ let totalCoin = 0;
+ const hunter = function (x, y, radius = 30) { //doesn't stop chasing until past 105000
+ mobs.spawn(x, y, 6, radius, "black");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.collisionFilter.mask = cat.player | cat.bullet;
+ me.accelMag = 0.0006 * Math.min(simulation.difficulty + 1, 4);
+ me.showHealthBar = false;
+ me.isUnblockable = true;
+ me.isShielded = true;
+ me.memory = Infinity;
+ me.seeAtDistance2 = Infinity;
+ Matter.Body.setDensity(me, 1)
+ simulation.makeTextLog(`
Ω: Intruder Detected `);
+ me.boost = 10;
+ me.do = function () {
+ if (me.boost == 1 && m.fieldMode == 3 || m.fieldMode == 9 && me.boost == 1) {
+ me.accelMag *= 1.5;
+ me.boost--;
+ }
+ this.attraction();
+ this.checkStatus();
+ this.repelBullets();
+ this.locatePlayer();
+ this.alwaysSeePlayer()
+ if (player.position.x > 105000) {
+ this.death()
+ }
+ };
+ me.onHit = function () {
+ for (let i = 0; i < 10; i++) {
+ spawn.spawns(this.position.x + Math.random() * 1000 - Math.random() * 1000, this.position.y - Math.random() * 1000)
+ }
+ }
+ }
+ const coin = function (x, y, radius = 50) {
+ mobs.spawn(x, y, 40, radius, "yellow");
+ let me = mob[mob.length - 1];
+ me.stroke = "#00000055"
+ me.isShielded = true;
+ me.leaveBody = false;
+ me.isBadTarget = true;
+ me.isUnblockable = true;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.collisionFilter.category = 0;
+ Matter.Body.setDensity(me, 0.0045);
+ me.onDeath = function () {
+ totalCoin++;
+ };
+ me.damageReduction = 0.35 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.do = function () {
+ ctx.save()
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.PI / 2 + 0.5)
+ ctx.strokeStyle = "#000000";
+ ctx.beginPath()
+ ctx.arc(0, 0, 30, -1, Math.PI, false)
+ ctx.moveTo(20, -5)
+ ctx.arc(0, 0, 20, -1, Math.PI, false)
+ ctx.lineWidth = 5;
+ ctx.stroke()
+ ctx.restore()
+ if (!simulation.isTimeSkipping) {
+ const sine = Math.sin(simulation.cycle * 0.015)
+ this.radius = 50 * (1 + 0.1 * sine)
+ const sub = Vector.sub(player.position, this.position)
+ const mag = Vector.magnitude(sub)
+ const force = Vector.mult(Vector.normalise(sub), 0.000000003)
+ if (mag < this.radius) { //heal player when inside radius
+ if (m.health < 0.7) {
+ m.damage(-0.001);
+ } else if (m.health == 0.7 || m.health > 0.7) {
+ this.death()
+ }
+ ctx.strokeStyle = "#00FFDD55";
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 34, 0, 2 * Math.PI);
+ ctx.lineWidth = 6;
+ ctx.stroke();
+ }
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, this.radius + 15, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#000"
+ ctx.lineWidth = 1;
+ ctx.stroke();
+ };
+ }
+ }
+ const spike = function (x, y, angle = Math.PI * 0.5, radius = 50) {
+ mobs.spawn(x, y, 3, radius, "#454545");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ Matter.Body.setDensity(me, 50)
+ me.collisionFilter.mask = cat.player | cat.mob | cat.bullet;
+ me.constraint = Constraint.create({
+ pointA: {
+ x: me.position.x,
+ y: me.position.y
+ },
+ bodyB: me,
+ stiffness: 0,
+ damping: 0
+ });
+ me.do = function () {
+ if (this.health < 1) {
+ this.health += 0.001; //regen
+ simulation.drawList.push({
+ x: this.position.x,
+ y: this.position.y,
+ radius: this.radius / 1.5,
+ color: `rgba(0, 255, 20, ${Math.random() * 0.1})`,
+ time: simulation.drawTime
+ });
+ }
+ this.checkStatus();
+ Matter.Body.setAngle(me, angle);
+ };
+ me.onHit = function () {
+ m.damage(0.01) //extra damage
+ me.collisionFilter.mask = 0;
+ setTimeout(() => {
+ me.collisionFilter.mask = cat.player | cat.mob | cat.bullet;
+ }, 1000);
+ }
+ me.onDeath = function () {
+ tech.addJunkTechToPool(0.1)
+ }
+ Composite.add(engine.world, me.constraint);
+ }
+
+ function drawStar(cx, cy, spikes, outerRadius, innerRadius) {
+ outerRadius *= (1 + 0.1 * Math.sin(simulation.cycle * 0.15));
+ innerRadius *= (1 + 0.1 * Math.sin(simulation.cycle * 0.15));
+ var rot = Math.PI / 2 * 3;
+ var xs = cx;
+ var y = cy;
+ var step = Math.PI / spikes;
+
+ ctx.strokeSyle = "#000";
+ ctx.beginPath();
+ ctx.moveTo(cx, cy - outerRadius)
+ for (i = 0; i < spikes; i++) {
+ xs = cx + Math.cos(rot) * outerRadius;
+ y = cy + Math.sin(rot) * outerRadius;
+ ctx.lineTo(xs, y)
+ rot += step
+
+ xs = cx + Math.cos(rot) * innerRadius;
+ y = cy + Math.sin(rot) * innerRadius;
+ ctx.lineTo(xs, y)
+ rot += step
+ }
+ ctx.lineTo(cx, cy - outerRadius)
+ ctx.closePath();
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = 'red';
+ ctx.stroke();
+ ctx.fillStyle = 'darkred';
+ ctx.fill();
+
+ }
+ const slimePit1 = level.hazard(7475, -75, 475, 100, 0.01)
+ const slimePit2 = level.hazard(11275, -75, 1450, 100, 0.01)
+ const slimePit3 = level.hazard(13400, -150, 3500, 200, 0.1)
+ const slimePit4 = level.hazard(20275, -400, 3475, 450, 0.01)
+ const slimePit5 = level.hazard(25300, -800, 20000, 650, 0.003)
+ const slimePit6 = level.hazard(47725, -425, 2500, 475, 0.01)
+ const slimePit7 = level.hazard(50975, -575, 4050, 650, 0.01)
+ const slimePit8 = level.hazard(54950, -950, 6650, 1050, 0.01)
+ const slimePit9 = level.hazard(63550, -75, 2150, 100, 0.01)
+ const slimePit10 = level.hazard(70875, -75, 1200, 100, 0.01)
+ const slimePit11 = level.hazard(72075, -50, 900, 75, 1)
+ const slimePit12 = level.hazard(75900, -75, 2575, 100, 0.01)
+ const slimePit13 = level.hazard(78475, -35, 2300, 70, 0.01)
+ const slimePit14 = level.hazard(82875, -75, 5100, 100, 0.1)
+
+ const drip1 = level.drip(32474, -2165, -800, 100);
+ const drip2 = level.drip(37750, -2165, -800, 100);
+ const drip3 = level.drip(43525, -2165, -800, 100);
+ const drip4 = level.drip(20475, -830, -375, 100);
+ const drip5 = level.drip(49960, -2315, -423, 200)
+ let textlogOne = 0;
+ let textlogTwo = 0;
+ let barThere = true;
+ let bar = document.createElement("div");
+ bar.style.cssText = `position: absolute; top: 80px; background-color: black; width: 80vw; z-index: 1; border-radius: 10px; height: 20px; left: 5em; right: 5em;`;
+ bar.innerHTML += `
`
+ document.body.appendChild(bar);
+ let innerBar = document.getElementById("innerBar");
+ level.custom = () => {
+ level.exit.drawAndCheck();
+ if (barThere == true) {
+ innerBar.style.width = "calc(" + `${Math.max(0, Math.min(player.position.x / 1310, 80))}` + "vw - 10px)";
+ innerBar.style.backgroundColor = m.eyeFillColor;
+ }
+ if (m.pos.x > 25360 && textlogOne == 0) {
+ simulation.makeTextLog(`
A stong force pushes you forward...
`)
+ textlogOne++;
+ }
+ if (m.pos.x < -3000) {
+ Matter.Body.setVelocity(player, {
+ x: 99,
+ y: 19
+ });
+
+ if (textlogTwo == 0)
+ simulation.makeTextLog(`
A strong force pushes you away...
`);
+ textlogTwo++;
+ }
+ if (m.pos.y > 1055) {
+ Matter.Body.setPosition(player, { x: 0, y: -150 });
+ simulation.makeTextLog(`
There is nowhere to run...
`);
+ m.damage(0.1 * simulation.difficultyMode);
+ }
+ if (m.alive == false && barThere == true) {
+ document.body.removeChild(bar);
+ barThere = false;
+ }
+ ctx.beginPath()
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = "#000000";
+ ctx.moveTo(40, -1000)
+ ctx.arc(0, -1000, 40, 0, 2 * Math.PI)
+ ctx.stroke()
+ ctx.fillStyle = "#FF00FF55"
+ ctx.fillRect(89750, -1300, 800, 200)
+ ctx.fillRect(89750, -200, 800, 200)
+ ctx.fillRect(92050, -200, 800, 200)
+ ctx.fillRect(92050, -1675, 800, 575)
+ ctx.fillRect(93950, -350, 200, 350);
+ ctx.fillRect(95100, -1350, 150, 375);
+ ctx.fillRect(100900, -1325, 1175, 250);
+ ctx.fillRect(100900, -225, 1200, 250);
+ ctx.fillRect(98725, -1325, 450, 150);
+ ctx.fillRect(98725, -125, 450, 150);
+ ctx.beginPath()
+ //lines!
+ ctx.lineWidth = 10;
+ ctx.strokeStyle = "#000000";
+ ctx.moveTo(7462.5, -250)
+ ctx.lineTo(7462.5, -170)
+ ctx.moveTo(7710, -330)
+ ctx.lineTo(7710, -250)
+ ctx.moveTo(7960, -420)
+ ctx.lineTo(7960, -320)
+ ctx.moveTo(13725, -250)
+ ctx.lineTo(13725, -180)
+ ctx.moveTo(14025, -350)
+ ctx.lineTo(14025, -280)
+ ctx.moveTo(14325, -450)
+ ctx.lineTo(14325, -380)
+ ctx.moveTo(14625, -550)
+ ctx.lineTo(14625, -480)
+ ctx.moveTo(14925, -650)
+ ctx.lineTo(14925, -580)
+ ctx.moveTo(15225, -750)
+ ctx.lineTo(15225, -680)
+ ctx.moveTo(15525, -850)
+ ctx.lineTo(15525, -780)
+ ctx.moveTo(15825, -950)
+ ctx.lineTo(15825, -880)
+ ctx.moveTo(16125, -1050)
+ ctx.lineTo(16125, -980)
+ ctx.moveTo(16425, -1150)
+ ctx.lineTo(16425, -1080)
+ ctx.moveTo(22600, -650)
+ ctx.lineTo(22600, -580)
+ ctx.moveTo(22800, -750)
+ ctx.lineTo(22800, -680)
+ ctx.moveTo(23000, -850)
+ ctx.lineTo(23000, -780)
+ ctx.moveTo(23200, -950)
+ ctx.lineTo(23200, -880)
+ ctx.moveTo(23400, -1050)
+ ctx.lineTo(23400, -980)
+ ctx.moveTo(23600, -1150)
+ ctx.lineTo(23600, -1080)
+ ctx.moveTo(29550, -1625)
+ ctx.lineTo(29550, -1425)
+ ctx.moveTo(32275, -2125)
+ ctx.lineTo(32275, -1925)
+ ctx.moveTo(33775, -2125)
+ ctx.lineTo(33775, -1925)
+ ctx.moveTo(32275, -350)
+ ctx.lineTo(32275, -550)
+ ctx.moveTo(33775, -350)
+ ctx.lineTo(33775, -550)
+ ctx.moveTo(35475, -650)
+ ctx.lineTo(35475, -450)
+ ctx.moveTo(37650, -2000)
+ ctx.lineTo(37650, -1800)
+ ctx.moveTo(39675, -400)
+ ctx.lineTo(39675, -600)
+ ctx.moveTo(40375, -500)
+ ctx.lineTo(40375, -700)
+ ctx.moveTo(41075, -600)
+ ctx.lineTo(41075, -800)
+ ctx.moveTo(43625, -1925)
+ ctx.lineTo(43625, -1725)
+ ctx.moveTo(50975, -1125)
+ ctx.lineTo(50975, -925)
+ ctx.moveTo(51387.5, -1325)
+ ctx.lineTo(51387.5, -1125)
+ ctx.moveTo(51787.5, -1525)
+ ctx.lineTo(51787.5, -1325)
+ ctx.moveTo(52187.5, -1725)
+ ctx.lineTo(52187.5, -1525)
+ ctx.moveTo(52587.5, -1725)
+ ctx.lineTo(52587.5, -1925)
+ ctx.moveTo(52987.5, -2125)
+ ctx.lineTo(52987.5, -1925)
+ ctx.moveTo(53387.5, -2325)
+ ctx.lineTo(53387.5, -2125)
+ ctx.moveTo(53787.5, -2525)
+ ctx.lineTo(53787.5, -2325)
+ ctx.moveTo(54187.5, -2725)
+ ctx.lineTo(54187.5, -2525)
+ ctx.moveTo(54587.5, -2925)
+ ctx.lineTo(54587.5, -2725)
+ ctx.moveTo(54987.5, -3125)
+ ctx.lineTo(54987.5, -2925)
+ ctx.moveTo(57500, -1925)
+ ctx.lineTo(57650, -1925)
+ ctx.moveTo(57520, -1845)
+ ctx.lineTo(57650, -1845)
+ ctx.moveTo(57500, -1925)
+ ctx.lineTo(57895 + 300, -1925)
+ ctx.moveTo(57520, -1845)
+ ctx.lineTo(57895 + 300, -1845)
+ ctx.moveTo(58525, -1725)
+ ctx.lineTo(58525 + 125, -1725)
+ ctx.moveTo(58525, -1625)
+ ctx.lineTo(58525 + 125, -1625)
+ ctx.moveTo(59000, -1725)
+ ctx.lineTo(59150, -1725)
+ ctx.moveTo(59150, -1625)
+ ctx.lineTo(59000, -1625)
+ ctx.moveTo(70875, -200)
+ ctx.lineTo(70875, -100)
+ ctx.moveTo(63700, -200)
+ ctx.lineTo(63800, -200)
+ ctx.moveTo(64000, -200)
+ ctx.lineTo(64100, -200)
+ ctx.moveTo(64675, -200)
+ ctx.lineTo(64575, -200)
+ ctx.moveTo(64875, -200)
+ ctx.lineTo(64975, -200)
+ ctx.moveTo(65025, -300)
+ ctx.lineTo(64925, -300)
+ ctx.moveTo(65225, -300)
+ ctx.lineTo(65325, -300)
+ ctx.moveTo(71275, -200)
+ ctx.lineTo(71275, -300)
+ ctx.moveTo(71675, -300)
+ ctx.lineTo(71675, -400)
+ ctx.moveTo(72075, -400)
+ ctx.lineTo(72075, -500)
+ ctx.moveTo(72425, -325)
+ ctx.lineTo(72425, -425)
+ ctx.moveTo(72675, -200)
+ ctx.lineTo(72675, -300)
+ ctx.moveTo(72925, -75)
+ ctx.lineTo(72925, -175)
+ ctx.moveTo(75225, -100)
+ ctx.lineTo(75225, -200)
+ ctx.moveTo(76600, -125)
+ ctx.lineTo(76600, -225)
+ ctx.moveTo(76900, -200)
+ ctx.lineTo(76900, -300)
+ ctx.moveTo(77175, -275)
+ ctx.lineTo(77175, -375)
+ ctx.moveTo(77475, -350)
+ ctx.lineTo(77475, -450)
+ ctx.moveTo(85575, -275)
+ ctx.lineTo(85575, -375)
+ ctx.moveTo(86000, -275)
+ ctx.lineTo(86000, -375)
+ ctx.moveTo(86275, -275)
+ ctx.lineTo(86275, -375)
+ ctx.moveTo(86950, -425)
+ ctx.lineTo(86950, -525)
+ ctx.moveTo(89700, -175)
+ ctx.lineTo(89700, -75)
+ ctx.moveTo(89700, -1125)
+ ctx.lineTo(89700, -1225)
+ ctx.moveTo(90600, -1225)
+ ctx.lineTo(90600, -1125)
+ ctx.moveTo(90600, -100)
+ ctx.lineTo(90600, -175)
+ ctx.moveTo(92000, -100)
+ ctx.lineTo(92000, -175)
+ ctx.moveTo(92900, -100)
+ ctx.lineTo(92900, -175)
+ ctx.moveTo(92900, -1225)
+ ctx.lineTo(92900, -1125)
+ ctx.moveTo(94500, -1475)
+ ctx.lineTo(94500, -1575)
+ ctx.moveTo(94700, -1475)
+ ctx.lineTo(94700, -1575)
+ ctx.moveTo(94900, -1475)
+ ctx.lineTo(94900, -1575)
+ ctx.moveTo(96125, -1500)
+ ctx.lineTo(96125, -1575)
+ ctx.moveTo(96550, -1575)
+ ctx.lineTo(96550, -1500)
+ ctx.moveTo(97000, -1475)
+ ctx.lineTo(97000, -1575)
+
+ ctx.stroke()
+ ctx.beginPath()
+ ctx.strokeStyle = "#FFFFFF";
+ ctx.fillStyle = document.body.style.backgroundColor;
+ let cycles = Math.sin(simulation.cycle * 0.15)
+ ctx.moveTo(7482.5, -270)
+ ctx.arc(7462.5, -270, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI);
+ ctx.moveTo(7730, -350)
+ ctx.arc(7710, -350, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI);
+ ctx.moveTo(7980, -420)
+ ctx.arc(7960, -420, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(13745, -180)
+ ctx.arc(13725, -180, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(14045, -280)
+ ctx.arc(14025, -280, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(14345, -380)
+ ctx.arc(14325, -380, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(14645, -480)
+ ctx.arc(14625, -480, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(14945, -580)
+ ctx.arc(14925, -580, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(15245, -680)
+ ctx.arc(15225, -680, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(15545, -780)
+ ctx.arc(15525, -780, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(15845, -880)
+ ctx.arc(15825, -880, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(16145, -980)
+ ctx.arc(16125, -980, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(16445, -1080)
+ ctx.arc(16425, -1080, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(22620, -580);
+ ctx.arc(22600, -580, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(22820, -680);
+ ctx.arc(22800, -680, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(23020, -780);
+ ctx.arc(23000, -780, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(23220, -880);
+ ctx.arc(23200, -880, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(23420, -980);
+ ctx.arc(23400, -980, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(23620, -1080);
+ ctx.arc(23600, -1080, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(29570, -1425)
+ ctx.arc(29550, -1425, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(32295, -1925)
+ ctx.arc(32275, -1925, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(33795, -1925)
+ ctx.arc(33775, -1925, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(32295, -550)
+ ctx.arc(32275, -550, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(33795, -550)
+ ctx.arc(33775, -550, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(35495, -650)
+ ctx.arc(35475, -650, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(37670, -1800)
+ ctx.arc(37650, -1800, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(39695, -600)
+ ctx.arc(39675, -600, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(40395, -700)
+ ctx.arc(40375, -700, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(41095, -800)
+ ctx.arc(41075, -800, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(43645, -1725)
+ ctx.arc(43625, -1725, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(50995, -1125)
+ ctx.arc(50975, -1125, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(51407.5, -1325)
+ ctx.arc(51387.5, -1325, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(51807.5, -1525)
+ ctx.arc(51787.5, -1525, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(52207.5, -1725)
+ ctx.arc(52187.5, -1725, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(52607.5, -1925)
+ ctx.arc(52587.5, -1925, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(53007.5, -2125)
+ ctx.arc(52987.5, -2125, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(53407.5, -2325)
+ ctx.arc(53387.5, -2325, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(53807.5, -2525)
+ ctx.arc(53787.5, -2525, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(54207.5, -2725)
+ ctx.arc(54187.5, -2725, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(54607.5, -2925)
+ ctx.arc(54587.5, -2925, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(55007.5, -3125)
+ ctx.arc(54987.5, -3125, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(57520, -1925)
+ ctx.arc(57500, -1925, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(57520, -1845)
+ ctx.arc(57500, -1845, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(58525, -1725)
+ ctx.arc(58505, -1725, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(57895 + 300, -1925)
+ ctx.arc(57875 + 300, -1925, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(57895 + 300, -1845)
+ ctx.arc(57875 + 300, -1845, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(58525, -1625)
+ ctx.arc(58505, -1625, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(58690 + 375 + 125, -1625)
+ ctx.arc(58670 + 375 + 125, -1625, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(59190, -1725)
+ ctx.arc(59170, -1725, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(70895, -200)
+ ctx.arc(70875, -200, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(63720, -200)
+ ctx.arc(63700, -200, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(64120, -200)
+ ctx.arc(64100, -200, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(64595, -200)
+ ctx.arc(64575, -200, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(64995, -200)
+ ctx.arc(64975, -200, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(64945, -300)
+ ctx.arc(64925, -300, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(65345, -300)
+ ctx.arc(65325, -300, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(71295, -300)
+ ctx.arc(71275, -300, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(71695, -400)
+ ctx.arc(71675, -400, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(72095, -500)
+ ctx.arc(72075, -500, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(72445, -425)
+ ctx.arc(72425, -425, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(72695, -300)
+ ctx.arc(72675, -300, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(72945, -175)
+ ctx.arc(72925, -175, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(75245, -200)
+ ctx.arc(75225, -200, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(76620, -125)
+ ctx.arc(76600, -125, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(76920, -200)
+ ctx.arc(76900, -200, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(77195, -275)
+ ctx.arc(77175, -275, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(77495, -350)
+ ctx.arc(77475, -350, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(85595, -375)
+ ctx.arc(85575, -375, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(86020, -375)
+ ctx.arc(86000, -375, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(86295, -375)
+ ctx.arc(86275, -375, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(86970, -525)
+ ctx.arc(86950, -525, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(89720, -175)
+ ctx.arc(89700, -175, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(89720, -1125)
+ ctx.arc(89700, -1125, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(90620, -1125)
+ ctx.arc(90600, -1125, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(90620, -175)
+ ctx.arc(90600, -175, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(92020, -175)
+ ctx.arc(92000, -175, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(92920, -175)
+ ctx.arc(92900, -175, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(92920, -1125)
+ ctx.arc(92900, -1125, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(94520, -1575)
+ ctx.arc(94500, -1575, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(94720, -1575)
+ ctx.arc(94700, -1575, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(94920, -1575)
+ ctx.arc(94900, -1575, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(96145, -1575)
+ ctx.arc(96125, -1575, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(96570, -1500)
+ ctx.arc(96550, -1500, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.moveTo(97020, -1575)
+ ctx.arc(97000, -1575, 20 * (1 + 0.1 * cycles), 0, 2 * Math.PI)
+ ctx.fill()
+ ctx.stroke()
+ slimePit1.query()
+ slimePit2.query()
+ slimePit3.query()
+ slimePit4.query()
+ slimePit5.query()
+ slimePit5.query()
+ slimePit6.query()
+ slimePit7.query()
+ slimePit8.query()
+ slimePit9.query()
+ slimePit10.query()
+ slimePit11.query()
+ slimePit12.query()
+ slimePit13.query()
+ slimePit14.query()
+ drip1.draw()
+ drip2.draw()
+ drip3.draw()
+ drip4.draw()
+ drip5.draw()
+
+ ctx.fillStyle = "rgba(0,255,255,0.9)"
+ ctx.fillRect(25325, -1375, 75, 400)
+ ctx.fillRect(46425, -1350, 100, 500)
+ ctx.fillRect(87925, -725, 75, 450)
+
+ /*
+ if (player.position.x < 46470) {
+ document.body.style.backgroundColor = "#DD00DD";
+ }
+ */
+ if (player.position.x > 25360 && player.position.x < 46470) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x, //+ 0.2,
+ y: player.velocity.y,
+ });
+ if (input.up) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y, //- 1,
+ });
+ }
+ document.body.style.backgroundColor = "#fb3310"
+ } else if (player.position.x > 46470 && player.position.x < 61675) {
+ document.body.style.backgroundColor = "#7704FF"
+ } else if (player.position.x > 9700 && player.position.x < 46470) {
+ document.body.style.backgroundColor = "#7704FF"
+ } else if (player.position.x > 61675 && player.position.x < 87950) {
+ document.body.style.backgroundColor = "#DD1111"
+ } else if (player.position.x > 87950) {
+ document.body.style.backgroundColor = "#7704FF"
+ }
+
+ if (m.pos.y > -200 && 20350 < m.pos.x && m.pos.x < 23635) {
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: 0
+ });
+ Matter.Body.setPosition(player, {
+ x: 20250,
+ y: -1000
+ });
+ // move bots
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ m.damage(0.1 * simulation.difficultyMode)
+ m.energy -= 0.1 * simulation.difficultyMode
+ }
+ if (m.pos.y > -150 && m.pos.x > 47770 && m.pos.x < 50130) {
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: 0
+ });
+ Matter.Body.setPosition(player, {
+ x: 47640,
+ y: -900
+ });
+ // move bots
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ m.damage(0.1 * simulation.difficultyMode)
+ m.energy -= 0.1 * simulation.difficultyMode
+ }
+ if (m.pos.y > -150 && 50975 < m.pos.x && m.pos.x < 54925) {
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: 0
+ });
+ Matter.Body.setPosition(player, {
+ x: 50965,
+ y: -1100
+ });
+ // move bots
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ m.damage(0.1 * simulation.difficultyMode)
+ m.energy -= 0.1 * simulation.difficultyMode
+ }
+ if (m.pos.y > -150 && 55025 < m.pos.x && m.pos.x < 57675) {
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: 0
+ });
+ Matter.Body.setPosition(player, {
+ x: 55148,
+ y: -3072
+ });
+ // move bots
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ m.damage(0.1 * simulation.difficultyMode)
+ m.energy -= 0.1 * simulation.difficultyMode
+ }
+ if (m.pos.y > -150 && 57875 < m.pos.x && m.pos.x < 58700) {
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: 0
+ });
+ Matter.Body.setPosition(player, {
+ x: 57800,
+ y: -2200
+
+ });
+ // move bots
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ m.damage(0.1 * simulation.difficultyMode)
+ m.energy -= 0.1 * simulation.difficultyMode
+ }
+ if (m.pos.y > -150 && 58875 < m.pos.x && m.pos.x < 61650) {
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: 0
+ });
+ Matter.Body.setPosition(player, {
+ x: 58850,
+ y: -2025
+
+ });
+ // move bots
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ m.damage(0.1 * simulation.difficultyMode)
+ m.energy -= 0.1 * simulation.difficultyMode
+ }
+ if (m.pos.y > -1677 && 104650 < m.pos.x && m.pos.x < 105000 && barThere == true) {
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: 0
+ });
+ Matter.Body.setPosition(player, {
+ x: 132577,
+ y: -300
+
+ });
+ // move bots
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ document.body.style.transitionDuration = "0ms";
+ document.body.style.backgroundColor = "#696969";
+ simulation.makeTextLog(`
You have earned: ` + Math.min(3, totalCoin) + ` tech
`)
+ if (barThere == true) { //only runs once
+ document.body.removeChild(bar);
+ for (let i = 0, len = Math.min(3, totalCoin); i < len; i++) powerUps.directSpawn(player.position.x, player.position.y, "tech");
+ barThere = false;
+
+
+ }
+ }
+ ctx.fillStyle = "#FFFFFF53"
+ ctx.fillRect(57645, -2055, 385, 85)
+ ctx.fillRect(58645, -1880, 385, 85)
+ //chains
+ ctx.strokeStyle = "#FF0000"
+ ctx.strokeRect(66975, -725, 25, 50)
+ ctx.strokeRect(67050, -725, 25, 50)
+ ctx.strokeRect(66975 + 1150, -725, 25, 50)
+ ctx.strokeRect(67050 + 1250, -725, 25, 50)
+ ctx.strokeRect(69162, -725, 25, 50)
+ ctx.strokeRect(69862, -725, 25, 50)
+ ctx.strokeRect(74412.5, -412.5, 25, 50)
+ ctx.strokeRect(74612.5, -412.5, 25, 50)
+ ctx.strokeRect(77962.5, -900, 25, 50)
+ ctx.strokeRect(78212.5, -775, 25, 50)
+ ctx.strokeRect(78462.5, -650, 25, 50)
+ ctx.strokeRect(81587.5, -725, 25, 50)
+ ctx.strokeRect(81687.5, -725, 25, 50)
+ ctx.strokeRect(81787.5, -725, 25, 50)
+ ctx.strokeRect(83037.5, -215, 25, 50)
+ ctx.strokeRect(83362.5, -215, 25, 50)
+ ctx.strokeRect(83687.5, -215, 25, 50)
+ ctx.strokeRect(84187.5, -315, 25, 50)
+ ctx.strokeStyle = "#FF000088"
+ ctx.strokeRect(66975, -850, 25, 50)
+ ctx.strokeRect(67050, -850, 25, 50)
+ ctx.strokeRect(66975 + 1150, -850, 25, 50)
+ ctx.strokeRect(67050 + 1250, -850, 25, 50)
+ ctx.strokeRect(69162, -850, 25, 50)
+ ctx.strokeRect(69862, -850, 25, 50)
+ ctx.strokeRect(74412.5, -525, 25, 50)
+ ctx.strokeRect(74612.5, -525, 25, 50)
+ ctx.strokeRect(77962.5, -985, 25, 50)
+ ctx.strokeRect(78212.5, -860, 25, 50)
+ ctx.strokeRect(78462.5, -735, 25, 50)
+ ctx.strokeRect(81587.5, -850, 25, 50)
+ ctx.strokeRect(81687.5, -850, 25, 50)
+ ctx.strokeRect(81787.5, -850, 25, 50)
+ ctx.strokeRect(83037.5, -315, 25, 50)
+ ctx.strokeRect(83362.5, -315, 25, 50)
+ ctx.strokeRect(83687.5, -315, 25, 50)
+ ctx.strokeRect(84187.5, -415, 25, 50)
+ ctx.strokeStyle = "#FF000044"
+ ctx.strokeRect(66975, -975, 25, 50)
+ ctx.strokeRect(67050, -975, 25, 50)
+ ctx.strokeRect(66975 + 1150, -975, 25, 50)
+ ctx.strokeRect(67050 + 1250, -975, 25, 50)
+ ctx.strokeRect(69162, -975, 25, 50)
+ ctx.strokeRect(69862, -975, 25, 50)
+ ctx.strokeRect(74412.5, -633, 25, 50)
+ ctx.strokeRect(74612.5, -633, 25, 50)
+ ctx.strokeRect(77962.5, -1075, 25, 50)
+ ctx.strokeRect(78212.5, -950, 25, 50)
+ ctx.strokeRect(78462.5, -825, 25, 50)
+ ctx.strokeRect(81587.5, -975, 25, 50)
+ ctx.strokeRect(81687.5, -975, 25, 50)
+ ctx.strokeRect(81787.5, -975, 25, 50)
+ ctx.strokeRect(83037.5, -415, 25, 50)
+ ctx.strokeRect(83362.5, -415, 25, 50)
+ ctx.strokeRect(83687.5, -415, 25, 50)
+ ctx.strokeRect(84187.5, -515, 25, 50)
+ ctx.strokeStyle = "#FF000011"
+ ctx.strokeRect(66975, -1100, 25, 50)
+ ctx.strokeRect(67050, -1100, 25, 50)
+ ctx.strokeRect(66975 + 1150, -1100, 25, 50)
+ ctx.strokeRect(67050 + 1250, -1100, 25, 50)
+ ctx.strokeRect(69162, -1100, 25, 50)
+ ctx.strokeRect(69862, -1100, 25, 50)
+ ctx.strokeRect(74412.5, -741, 25, 50)
+ ctx.strokeRect(74612.5, -741, 25, 50)
+ ctx.strokeRect(77962.5, -1165, 25, 50)
+ ctx.strokeRect(78212.5, -1040, 25, 50)
+ ctx.strokeRect(78462.5, -915, 25, 50)
+ ctx.strokeRect(81587.5, -1100, 25, 50)
+ ctx.strokeRect(81687.5, -1100, 25, 50)
+ ctx.strokeRect(81787.5, -1100, 25, 50)
+ ctx.strokeRect(83037.5, -515, 25, 50)
+ ctx.strokeRect(83362.5, -515, 25, 50)
+ ctx.strokeRect(83687.5, -515, 25, 50)
+ ctx.strokeRect(84187.5, -615, 25, 50)
+ ctx.stroke()
+ ctx.beginPath()
+ ctx.strokeStyle = "#FF0000"
+ ctx.moveTo(66987.5, -680)
+ ctx.lineTo(66987.5, -625)
+ ctx.moveTo(67062.5, -680)
+ ctx.lineTo(67062.5, -625)
+ ctx.moveTo(66987.5 + 1150, -680)
+ ctx.lineTo(66987.5 + 1150, -625)
+ ctx.moveTo(67062.5 + 1250, -680)
+ ctx.lineTo(67062.5 + 1250, -625)
+ ctx.moveTo(69175, -680)
+ ctx.lineTo(69175, -625)
+ ctx.moveTo(69875, -680)
+ ctx.lineTo(69875, -625)
+ ctx.moveTo(74425, -290)
+ ctx.lineTo(74425, -370)
+ ctx.moveTo(74625, -290)
+ ctx.lineTo(74625, -370)
+ ctx.moveTo(77975, -790)
+ ctx.lineTo(77975, -855)
+ ctx.moveTo(78225, -665)
+ ctx.lineTo(78225, -730)
+ ctx.moveTo(78475, -540)
+ ctx.lineTo(78475, -605)
+ ctx.moveTo(81600, -680)
+ ctx.lineTo(81600, -625)
+ ctx.moveTo(81700, -680)
+ ctx.lineTo(81700, -625)
+ ctx.moveTo(81800, -680)
+ ctx.lineTo(81800, -625)
+ ctx.moveTo(83050, -100)
+ ctx.lineTo(83050, -170)
+ ctx.moveTo(83375, -100)
+ ctx.lineTo(83375, -170)
+ ctx.moveTo(83700, -100)
+ ctx.lineTo(83700, -170)
+ ctx.moveTo(84200, -200)
+ ctx.lineTo(84200, -270)
+ ctx.stroke()
+ ctx.strokeStyle = "#FF000099"
+ ctx.moveTo(66987.5, -810)
+ ctx.lineTo(66987.5, -715)
+ ctx.moveTo(67062.5, -810)
+ ctx.lineTo(67062.5, -715)
+ ctx.moveTo(66987.5 + 1150, -810)
+ ctx.lineTo(66987.5 + 1150, -715)
+ ctx.moveTo(67062.5 + 1250, -810)
+ ctx.lineTo(67062.5 + 1250, -715)
+ ctx.moveTo(69175, -810)
+ ctx.lineTo(69175, -715)
+ ctx.moveTo(69875, -810)
+ ctx.lineTo(69875, -715)
+ ctx.moveTo(74425, -405)
+ ctx.lineTo(74425, -480)
+ ctx.moveTo(74625, -405)
+ ctx.lineTo(74625, -480)
+ ctx.moveTo(77975, -890)
+ ctx.lineTo(77975, -940)
+ ctx.moveTo(78225, -765)
+ ctx.lineTo(78225, -815)
+ ctx.moveTo(78475, -640)
+ ctx.lineTo(78475, -690)
+ ctx.moveTo(81600, -810)
+ ctx.lineTo(81600, -715)
+ ctx.moveTo(81700, -810)
+ ctx.lineTo(81700, -715)
+ ctx.moveTo(81800, -810)
+ ctx.lineTo(81800, -715)
+ ctx.moveTo(83050, -210)
+ ctx.lineTo(83050, -270)
+ ctx.moveTo(83375, -210)
+ ctx.lineTo(83375, -270)
+ ctx.moveTo(83700, -210)
+ ctx.lineTo(83700, -270)
+ ctx.moveTo(84200, -310)
+ ctx.lineTo(84200, -370)
+ ctx.stroke()
+ ctx.strokeStyle = "#FF000044"
+ ctx.moveTo(66987.5, -930)
+ ctx.lineTo(66987.5, -845)
+ ctx.moveTo(67062.5, -930)
+ ctx.lineTo(67062.5, -845)
+ ctx.moveTo(66987.5 + 1150, -930)
+ ctx.lineTo(66987.5 + 1150, -845)
+ ctx.moveTo(67062.5 + 1250, -930)
+ ctx.lineTo(67062.5 + 1250, -845)
+ ctx.moveTo(69175, -930)
+ ctx.lineTo(69175, -845)
+ ctx.moveTo(69875, -930)
+ ctx.lineTo(69875, -845)
+ ctx.moveTo(74425, -515)
+ ctx.lineTo(74425, -590)
+ ctx.moveTo(74625, -515)
+ ctx.lineTo(74625, -590)
+ ctx.moveTo(77975, -975)
+ ctx.lineTo(77975, -1040)
+ ctx.moveTo(78225, -850)
+ ctx.lineTo(78225, -915)
+ ctx.moveTo(78475, -725)
+ ctx.lineTo(78475, -790)
+ ctx.moveTo(81600, -930)
+ ctx.lineTo(81600, -845)
+ ctx.moveTo(81700, -930)
+ ctx.lineTo(81700, -845)
+ ctx.moveTo(81800, -930)
+ ctx.lineTo(81800, -845)
+ ctx.moveTo(83050, -305)
+ ctx.lineTo(83050, -370)
+ ctx.moveTo(83375, -305)
+ ctx.lineTo(83375, -370)
+ ctx.moveTo(83700, -305)
+ ctx.lineTo(83700, -370)
+ ctx.moveTo(84200, -405)
+ ctx.lineTo(84200, -470)
+ ctx.stroke()
+ ctx.strokeStyle = "#FF000022"
+ ctx.moveTo(66987.5, -1060)
+ ctx.lineTo(66987.5, -965)
+ ctx.moveTo(67062.5, -1060)
+ ctx.lineTo(67062.5, -965)
+ ctx.moveTo(66987.5 + 1150, -1060)
+ ctx.lineTo(66987.5 + 1150, -965)
+ ctx.moveTo(67062.5 + 1250, -1060)
+ ctx.lineTo(67062.5 + 1250, -965)
+ ctx.moveTo(69175, -1060)
+ ctx.lineTo(69175, -965)
+ ctx.moveTo(69875, -1060)
+ ctx.lineTo(69875, -965)
+ ctx.moveTo(74425, -620)
+ ctx.lineTo(74425, -712.5)
+ ctx.moveTo(74625, -620)
+ ctx.lineTo(74625, -712.5)
+ ctx.moveTo(77975, -1075)
+ ctx.lineTo(77975, -1120)
+ ctx.moveTo(78225, -950)
+ ctx.lineTo(78225, -995)
+ ctx.moveTo(78475, -825)
+ ctx.lineTo(78475, -870)
+ ctx.moveTo(81600, -1060)
+ ctx.lineTo(81600, -965)
+ ctx.moveTo(81700, -1060)
+ ctx.lineTo(81700, -965)
+ ctx.moveTo(81800, -1060)
+ ctx.lineTo(81800, -965)
+ ctx.moveTo(83050, -405)
+ ctx.lineTo(83050, -470)
+ ctx.moveTo(83375, -405)
+ ctx.lineTo(83375, -470)
+ ctx.moveTo(83700, -405)
+ ctx.lineTo(83700, -470)
+ ctx.moveTo(84200, -505)
+ ctx.lineTo(84200, -570)
+ ctx.stroke()
+ let star = 95525;
+ for (let i = 0; i < 3; i++) {
+ drawStar(star, -1540, 5, 40, 15);
+ star += 200;
+ }
+ drawStar(97375, -1540, 5, 25, 10)
+ drawStar(97675, -1540, 5, 25, 10)
+ drawStar(97975, -1540, 5, 25, 10)
+ drawStar(98275, -1540, 5, 25, 10)
+ drawStar(98575, -1540, 5, 25, 10)
+
+ };
+ var gradient = ctx.createLinearGradient(0, 0, 175, 0);
+ gradient.addColorStop(0, "#7704FF00");
+ gradient.addColorStop(1, "#00FFFF");
+ level.customTopLayer = () => {
+ if (player.position.x > 25360 && player.position.x < 46470 && player.position.y > -2348 || player.position.x > 87995 && player.position.x < 103950 && player.position.y > -1350) {
+ player.force.x += 0.0045
+ m.airControl = () => {
+ if (input.up) {
+ player.force.y -= 0.02
+ }
+ }
+ m.draw = () => {
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5
+ ctx.translate(player.position.x, player.position.y);
+ ctx.rotate(player.angle);
+ if (input.up) { //forward thrust drawing
+ ctx.rotate(`${Math.max(-0.5, Math.min(m.angle, 0.5))}`)
+ } else {
+ ctx.rotate(`${Math.max(0.5, Math.min(m.angle, -0.5))}`)
+ }
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.beginPath()
+ ctx.moveTo(30, 0)
+ ctx.lineTo(60, 10)
+ ctx.lineTo(60, 30)
+ ctx.lineTo(20, 40)
+ ctx.lineTo(0, 40)
+ ctx.lineTo(-50, 60)
+ ctx.lineTo(-50, 0)
+ ctx.lineTo(-40, -40)
+ ctx.lineTo(-40, -40)
+ ctx.lineTo(-30, 10)
+ ctx.lineTo(30, 10)
+ ctx.lineTo(30, 0)
+ ctx.fill();
+ ctx.moveTo(-50, 30)
+ ctx.lineTo(-60, 30)
+ ctx.lineTo(-60, 0)
+ ctx.lineTo(-50, 0)
+ ctx.fill()
+ ctx.stroke()
+ ctx.restore();
+ }
+ } else {
+ m.resetSkin()
+ m.airControl = () => {
+ if (input.up && m.buttonCD_jump + 20 < m.cycle && m.yOffWhen.stand > 23 && m.lastOnGroundCycle + 5 > m.cycle) m.jump()
+ if (m.buttonCD_jump + 60 > m.cycle && !(input.up) && m.Vy < 0) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y * 0.94
+ });
+ }
+ if (input.left) {
+ if (player.velocity.x > -m.airSpeedLimit / player.mass / player.mass) player.force.x -= m.FxAir; // move player left / a
+ } else if (input.right) {
+ if (player.velocity.x < m.airSpeedLimit / player.mass / player.mass) player.force.x += m.FxAir; //move player right / d
+ }
+ }
+ }
+ ctx.fillStyle = `rgba(68, 68, 68, ${Math.max(0.1, Math.min((-1400 - m.pos.y) / -100, 0.99))})`;
+ ctx.fillRect(91900, -1675, 12050, 375)
+ ctx.save()
+ ctx.translate(104700, -1675);
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, 0, 175, 1675)
+ ctx.restore()
+ };
+ level.setPosToSpawn(0, -150); //spawn
+ level.defaultZoom = 1800 //default I think
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#0150FF";
+ document.body.style.transitionDuration = "1500ms"; //smoother transitions, so that people don't complain
+ level.exit.x = 133150;
+ level.exit.y = -260;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 20);
+ //ground? I forgot
+ spawn.mapRect(-5000, 0, 110000, 1000);
+ //*mountains to prevent player from running away*
+ spawn.mapVertex(-5775, -1330, "0 0 1000 7000 -1000 7000");
+ spawn.mapVertex(-7000, -330, "0 0 1000 4000 -1000 4000");
+ spawn.mapVertex(-10000, -330, "0 0 1000 4000 -1000 4000");
+ spawn.mapVertex(-9000, -330, "0 0 1000 4000 -1000 4000");
+ spawn.mapVertex(-7500, -330, "0 0 1000 4000 -1000 4000");
+ spawn.mapRect(-10000, 0, 3500, 1000);
+ //spawn.mapRect(-10000, -10000, 1000, 11000);
+ //hunter(-600, -150)
+ //stage one --> 0%
+ //spikes
+ spike(3000, -30);
+ spike(5000, -30);
+ spike(4925, 0);
+ spike(7275, -30);
+ spike(7375, -30);
+ spike(9806, -30);
+ spike(9900, -30);
+ spike(12000, -130);
+ spike(13050, -255);
+ spike(17300, -1105);
+ spike(17400, -1105);
+ spike(17200, -1105);
+ spike(17500, -1105);
+ spike(18200, -1105);
+ spike(18100, -1105);
+ spike(18300, -1105);
+ spike(18400, -1105);
+ spike(19875, -1108);
+ spike(19975, -930);
+ spike(21000, -930);
+ spike(21725, -780);
+ spike(23600, -1230);
+ spawn.mapVertex(62000, -300, "0 1000 1000 1000 0 0");
+ //upside down spikes
+ let u = Math.PI * 1.5;
+ spike(18825, -1170, u);
+ spike(18925, -1170, u);
+ spike(19025, -1170, u);
+ spike(19125, -1170, u);
+ spike(19225, -1170, u);
+ spike(19325, -1170, u);
+ spike(49962.5, -2370, u);
+ spike(50062.5, -2370, u);
+ spike(50162.5, -2370, u);
+ spike(50262.5, -2370, u);
+ spike(50362.5, -2370, u);
+ //bottom of the flying part
+ spike(32375, -280);
+ spike(32475, -280);
+ spike(32575, -280);
+ spike(32675, -280);
+ spike(32775, -280);
+ spike(32875, -280);
+ spike(32975, -280);
+ spike(33075, -280);
+ spike(33175, -280);
+ spike(33275, -280);
+ spike(33375, -280);
+ spike(33475, -280);
+ spike(33575, -280);
+ spike(33675, -280);
+ spike(35575, -280);
+ spike(35675, -280);
+ spike(35775, -280);
+ spike(35875, -280);
+ spike(39775, -280);
+ spike(39875, -280);
+ spike(39975, -280);
+ spike(40075, -280);
+ spike(40175, -280);
+ spike(40275, -280);
+ spike(40475, -280);
+ spike(40575, -280);
+ spike(40675, -280);
+ spike(40775, -280);
+ spike(40875, -280);
+ spike(40975, -280);
+ //top of the flying part
+ spike(32375, -2193, u);
+ spike(32475, -2193, u);
+ spike(32575, -2193, u);
+ spike(32675, -2193, u);
+ spike(32775, -2193, u);
+ spike(32875, -2193, u);
+ spike(32975, -2193, u);
+ spike(33075, -2193, u);
+ spike(33175, -2193, u);
+ spike(33275, -2193, u);
+ spike(33375, -2193, u);
+ spike(33475, -2193, u);
+ spike(33575, -2193, u);
+ spike(33675, -2193, u);
+ spike(37750, -2193, u);
+ spike(37850, -2193, u);
+ spike(37950, -2193, u);
+ spike(38050, -2193, u);
+ spike(43025, -2193, u);
+ spike(43125, -2193, u);
+ spike(43225, -2193, u);
+ spike(43325, -2193, u);
+ spike(43425, -2193, u);
+ spike(43525, -2193, u);
+ spike(43725, -2193, u);
+ spike(43825, -2193, u);
+ spike(43925, -2193, u);
+ spike(44025, -2193, u);
+ spike(44125, -2193, u);
+ spike(44225, -2193, u);
+ spike(44325, -2193, u);
+ spike(44425, -2193, u);
+ spike(44525, -2193, u);
+ spike(44625, -2193, u);
+ spike(44725, -2193, u);
+ spike(44825, -2193, u);
+ //about 55% of the map
+ spike(63375, -30);
+ spike(63475, -30);
+ spike(65775, -30);
+ spike(65875, -30);
+ spike(66975, -30);
+ spike(67075, -30);
+ spike(66975, -500, u);
+ spike(67075, -500, u);
+ spike(68125, -30);
+ spike(68225, -30);
+ spike(68325, -30);
+ spike(68125, -500, u);
+ spike(68225, -500, u);
+ spike(68325, -500, u);
+ spike(69175, -500, u);
+ spike(69175, -30);
+ spike(69875, -500, u);
+ spike(69875, -30);
+ spike(70675, -30);
+ spike(70775, -30);
+ spike(73725, -30);
+ spike(73825, -30);
+ spike(74425, -195, u);
+ spike(74525, -195, u);
+ spike(74625, -195, u);
+ spike(75125, -30);
+ spawn.mapVertex(78725, -466, "0 50 100 50 50 0"); //ocd still triggers from -467
+ spike(79300, -180);
+ spike(80800, -30);
+ spike(80900, -30);
+ spike(81600, -30);
+ spike(81700, -30);
+ spike(81800, -30);
+ spike(81600, -500, u);
+ spike(81700, -500, u);
+ spike(81800, -500, u);
+ spike(93425, -1430);
+ spike(93525, -1430);
+ spike(85800, -305);
+ spike(86475, -305);
+ spike(87150, -455);
+ spike(94025, -1570, u);
+ spike(94125, -1570, u);
+ spike(94500, -1430);
+ spike(94700, -1430);
+ spike(94900, -1430);
+ spike(94600, -1400);
+ spike(94800, -1400);
+ spike(94212.5, -1675, u);
+ spike(94287.5, -1675, u);
+ //even more 90%
+ spike(95525, -1400)
+ spike(95525, -1675, u)
+ spike(95625, -1400)
+ spike(95625, -1675, u)
+ spike(95725, -1400)
+ spike(95725, -1675, u)
+ spike(95825, -1400)
+ spike(95825, -1675, u)
+ spike(95925, -1400)
+ spike(95925, -1675, u)
+ spike(96025, -1400)
+ spike(96225, -1400)
+ spike(96650, -1675, u)
+ spike(96900, -1400)
+ spike(97150, -1675, u)
+ spike(98900, -1400)
+ spike(96975, -155)
+ spike(97075, -155)
+ spike(97175, -155)
+ spike(97275, -155)
+ spike(97375, -155)
+ spike(97475, -155)
+ spike(96975, -1170, u)
+ spike(97075, -1170, u)
+ spike(97175, -1170, u)
+ spike(97275, -1170, u)
+ spike(97375, -1170, u)
+ spike(97475, -1170, u)
+ spike(98700, -1070, u)
+ spike(98800, -1070, u)
+ spike(98900, -1070, u)
+ spike(99000, -1070, u)
+ spike(99100, -1070, u)
+ spike(99200, -1070, u)
+ spike(98700, -230)
+ spike(98800, -230)
+ spike(98900, -230)
+ spike(99000, -230)
+ spike(99100, -230)
+ spike(99200, -230)
+ spike(98975, -1400)
+ spike(99375, -1675, u)
+ spike(99300, -1675, u)
+ spike(99575, -1675, u)
+ spike(100000, -1400)
+ //actual stuff
+ spawn.mapRect(7425, -175, 75, 175);
+ spawn.mapRect(7675, -250, 75, 250);
+ spawn.mapRect(7925, -325, 75, 325);
+ spawn.mapRect(10625, -100, 725, 100);
+ spawn.mapRect(11625, -100, 725, 100);
+ spawn.mapRect(12650, -225, 800, 225);
+ spawn.mapRect(13675, -300, 100, 50);
+ spawn.mapRect(13975, -400, 100, 50);
+ spawn.mapRect(14275, -500, 100, 50);
+ spawn.mapRect(14575, -600, 100, 50);
+ spawn.mapRect(14875, -700, 100, 50);
+ spawn.mapRect(15175, -800, 100, 50);
+ spawn.mapRect(15475, -900, 100, 50);
+ spawn.mapRect(15775, -1000, 100, 50);
+ spawn.mapRect(16075, -1100, 100, 50);
+ spawn.mapRect(16375, -1200, 100, 50);
+ spawn.mapRect(16625, -1075, 350, 100);
+ spawn.mapRect(16800, -1075, 1825, 1125);
+ spawn.mapRect(17250, -1225, 200, 50);
+ spawn.mapRect(18150, -1225, 200, 50);
+ spawn.mapRect(18550, -975, 1050, 1025);
+ spawn.mapRect(19525, -1075, 400, 1125);
+ spawn.mapRect(18775, -1275, 600, 75);
+ spawn.mapRect(19825, -900, 500, 950);
+ spawn.mapRect(20150, -900, 375, 125);
+ spawn.mapRect(20750, -900, 300, 50);
+ spawn.mapRect(21225, -750, 550, 50);
+ spawn.mapRect(21950, -625, 450, 50);
+ spawn.mapRect(22550, -700, 100, 50);
+ spawn.mapRect(22750, -800, 100, 50);
+ spawn.mapRect(22950, -900, 100, 50);
+ spawn.mapRect(23150, -1000, 100, 50);
+ spawn.mapRect(23350, -1100, 100, 50);
+ spawn.mapRect(23550, -1200, 100, 50);
+ spawn.mapRect(23525, -975, 400, 100);
+ spawn.mapRect(23650, -975, 1825, 1025);
+ spawn.mapRect(23750, -2500, 625, 1125);
+ spawn.mapRect(24000, -2500, 1200, 1300);
+ spawn.mapRect(24900, -2500, 575, 1125);
+ spawn.mapRect(25425, -2500, 20000, 275);
+ spawn.mapRect(25425, -250, 20000, 300);
+ spawn.mapRect(29450, -2300, 200, 675);
+ spawn.mapRect(32225, -2225, 100, 100);
+ spawn.mapRect(33725, -2225, 100, 100);
+ spawn.mapRect(32225, -350, 100, 100);
+ spawn.mapRect(33725, -350, 100, 100);
+ spawn.mapRect(37600, -2225, 100, 225);
+ spawn.mapRect(35425, -475, 100, 225);
+ spawn.mapRect(39625, -400, 100, 150);
+ spawn.mapRect(40325, -500, 100, 250);
+ spawn.mapRect(41025, -600, 100, 350);
+ spawn.mapRect(43575, -2225, 100, 300);
+ spawn.mapRect(44875, -2500, 1675, 1225);
+ spawn.mapRect(44875, -950, 1675, 1000);
+ spawn.mapRect(46425, -825, 1400, 875);
+ spawn.mapRect(48075, -1100, 175, 1150);
+ spawn.mapRect(48575, -1300, 175, 1375);
+ spawn.mapRect(49075, -1500, 175, 1550);
+ spawn.mapRect(49575, -1700, 175, 975);
+ spawn.mapRect(49575, -500, 175, 550);
+ spawn.mapRect(50075, -1900, 175, 700);
+ spawn.mapRect(50075, -1000, 1000, 1000);
+ spawn.mapRect(49912.5, -2525, 500, 125);
+ spawn.mapRect(51300, -1200, 175, 1225);
+ spawn.mapRect(51700, -1400, 175, 1425);
+ spawn.mapRect(52100, -1600, 175, 1625);
+ spawn.mapRect(52500, -1800, 175, 1825);
+ spawn.mapRect(52900, -2000, 175, 2025);
+ spawn.mapRect(53300, -2200, 175, 2225);
+ spawn.mapRect(53700, -2400, 175, 2425);
+ spawn.mapRect(54100, -2600, 175, 2625);
+ spawn.mapRect(54500, -2800, 175, 2825);
+ spawn.mapRect(54900, -3000, 175, 3025);
+ spawn.mapRect(55050, -3000, 175, 75);
+ spawn.mapRect(55475, -2875, 250, 75);
+ spawn.mapRect(55900, -2625, 250, 75);
+ spawn.mapRect(56500, -2400, 375, 75);
+ spawn.mapRect(57200, -2200, 250, 75);
+ spawn.mapRect(57650, -2050, 375, 75);
+ spawn.mapRect(57650, -1970, 375, 1975);
+ spawn.mapRect(58650, -1875, 375, 75);
+ spawn.mapRect(58650, -1795, 375, 1975);
+ spawn.mapRect(59525, -1750, 175, 75);
+ spawn.mapRect(60125, -1600, 175, 75);
+ spawn.mapRect(60750, -1425, 175, 75);
+ spawn.mapRect(61250, -1225, 175, 75);
+ spawn.mapRect(61550, -1025, 225, 1125);
+ spawn.mapRect(63525, -100, 100, 100);
+ spawn.mapRect(63800, -225, 200, 50);
+ spawn.mapRect(64175, -100, 100, 100);
+ spawn.mapRect(64275, -100, 100, 100);
+ spawn.mapRect(64375, -100, 100, 100);
+ spawn.mapRect(64675, -225, 200, 50);
+ spawn.mapRect(65025, -325, 200, 50);
+ spawn.mapRect(65425, -100, 300, 100);
+ spawn.mapRect(66925, -650, 200, 120);
+ spawn.mapRect(68075, -650, 300, 120);
+ spawn.mapRect(69125, -650, 100, 120);
+ spawn.mapRect(69825, -650, 100, 120);
+ spawn.mapRect(70825, -100, 100, 100);
+ spawn.mapRect(71225, -200, 100, 200);
+ spawn.mapRect(71625, -300, 100, 300);
+ spawn.mapRect(72025, -400, 100, 400);
+ spawn.mapRect(72125, -400, 100, 50);
+ spawn.mapRect(72375, -325, 100, 50);
+ spawn.mapRect(72625, -200, 100, 50);
+ spawn.mapRect(72875, -75, 100, 50);
+ spawn.mapRect(74375, -300, 300, 75);
+ spawn.mapRect(75175, -100, 100, 100);
+ spawn.mapRect(75900, -150, 400, 50);
+ spawn.mapRect(76550, -250, 100, 50);
+ spawn.mapRect(76850, -325, 100, 50);
+ spawn.mapRect(77125, -400, 100, 50);
+ spawn.mapRect(77425, -475, 300, 50);
+ spawn.mapRect(77925, -400, 100, 100);
+ spawn.mapRect(78175, -275, 100, 100);
+ spawn.mapRect(78425, -150, 100, 100);
+ spawn.mapRect(78675, -50, 100, 100);
+ spawn.mapRect(77925, -800, 100, 100);
+ spawn.mapRect(78175, -675, 100, 100);
+ spawn.mapRect(78425, -550, 100, 100);
+ spawn.mapRect(78675, -450, 100, 100);
+ spawn.mapRect(78450, -100, 50, 125);
+ spawn.mapRect(79025, -150, 100, 50);
+ spawn.mapRect(79250, -150, 100, 50);
+ spawn.mapRect(79475, -150, 100, 50);
+ spawn.mapRect(79800, -225, 300, 50);
+ spawn.mapRect(80250, -150, 100, 50);
+ spawn.mapRect(80450, -100, 300, 50);
+ spawn.mapRect(81550, -650, 300, 120);
+ spawn.mapRect(82800, -100, 100, 100);
+ spawn.mapRect(82900, -100, 200, 50);
+ spawn.mapRect(83325, -100, 100, 50);
+ spawn.mapRect(83650, -100, 200, 50);
+ spawn.mapRect(83850, -100, 100, 100);
+ spawn.mapRect(83950, -200, 100, 200);
+ spawn.mapRect(84050, -200, 200, 50);
+ spawn.mapRect(84500, -350, 100, 50);
+ spawn.mapRect(84725, -250, 100, 50);
+ spawn.mapRect(84950, -150, 300, 50);
+ spawn.mapRect(85525, -275, 100, 50);
+ spawn.mapRect(85750, -275, 100, 50);
+ spawn.mapRect(85950, -275, 375, 50);
+ spawn.mapRect(86425, -275, 100, 50);
+ spawn.mapRect(86625, -275, 100, 50);
+ spawn.mapRect(86900, -425, 300, 50);
+ spawn.mapRect(87375, -275, 300, 50);
+ spawn.mapRect(87900, -300, 125, 300);
+ spawn.mapRect(87900, -1850, 125, 1150);
+ spawn.mapRect(87900, -1850, 17000, 175);
+ spawn.mapRect(104875, -1850, 125, 2850); //Last part
+ spawn.mapRect(87900, -1850, 4000, 550);
+ spawn.mapRect(89650, -100, 100, 100);
+ spawn.mapRect(89750, -200, 100, 100);
+ spawn.mapRect(89850, -300, 600, 100);
+ spawn.mapRect(90450, -200, 100, 100);
+ spawn.mapRect(90550, -100, 100, 100);
+ spawn.mapRect(89650, -1300, 100, 100);
+ spawn.mapRect(89750, -1200, 100, 100);
+ spawn.mapRect(89850, -1100, 600, 100);
+ spawn.mapRect(90450, -1200, 100, 100);
+ spawn.mapRect(90550, -1300, 100, 100);
+ spawn.mapRect(91950, -100, 100, 100);
+ spawn.mapRect(92050, -200, 100, 100);
+ spawn.mapRect(92150, -300, 600, 100);
+ spawn.mapRect(92750, -200, 100, 100);
+ spawn.mapRect(92850, -100, 100, 100);
+ spawn.mapRect(92050, -1200, 100, 100);
+ spawn.mapRect(92150, -1100, 600, 100);
+ spawn.mapRect(92750, -1200, 100, 100);
+ spawn.mapRect(92850, -1300, 100, 100);
+ spawn.mapRect(92950, -1400, 11000, 100);
+ spawn.mapRect(93975, -1700, 200, 100);
+ spawn.mapRect(96075, -1500, 100, 100);
+ spawn.mapRect(96500, -1675, 100, 100);
+ spawn.mapRect(96950, -1490, 1900, 100);
+ spawn.mapRect(97200, -1685, 1650, 100);
+ spawn.mapRect(93900, -300, 100, 300);
+ spawn.mapRect(93900, -400, 300, 100);
+ spawn.mapRect(94100, -300, 100, 300);
+ spawn.mapRect(95025, -1300, 100, 300);
+ spawn.mapRect(95025, -1000, 300, 100);
+ spawn.mapRect(95225, -1300, 100, 300);
+ spawn.mapRect(96925, -1300, 600, 100);
+ spawn.mapRect(96925, -125, 600, 125);
+ spawn.mapRect(98650, -1300, 100, 200);
+ spawn.mapRect(98650, -1200, 600, 100);
+ spawn.mapRect(99150, -1300, 100, 200);
+ spawn.mapRect(98650, -200, 100, 200);
+ spawn.mapRect(99150, -200, 100, 200);
+ spawn.mapRect(98650, -200, 600, 100);
+ spawn.mapRect(100825, -1300, 100, 300);
+ spawn.mapRect(100825, -1100, 1325, 100);
+ spawn.mapRect(102050, -1300, 100, 300);
+ spawn.mapRect(100825, -300, 100, 300);
+ spawn.mapRect(100825, -300, 1350, 100);
+ spawn.mapRect(102075, -300, 100, 300);
+ spawn.mapRect(99425, -1675, 100, 125);
+ spawn.mapRect(100050, -1525, 100, 125);
+
+ spawn.mapRect(132025, -225, 2325, 525);
+ spawn.mapRect(132025, -1450, 500, 1750);
+ spawn.mapRect(133875, -1475, 475, 1775);
+ spawn.mapRect(132025, -1925, 2325, 475);
+
+ // simulation.enableConstructMode() //also remove when done
+ coin(50165.9, -1090)
+ coin(78725.4, -600)
+ coin(103830.0, -1473)
+ hunter(0, -1000)
+ },
+ yingYang() {
+ simulation.makeTextLog(`
yingYang by
Richard0820 `);
+
+ let destroyed = false;
+ const lock = level.door(425, -1400, 50, 300, 300);
+ const core = function (x, y, radius = 100 + Math.ceil(Math.random() * 25)) {
+ radius = 9 + radius / 8; //extra small
+ mobs.spawn(x, y, 6, radius, "transparent");
+ let me = mob[mob.length - 1];
+ me.constraint = Constraint.create({
+ pointA: {
+ x: me.position.x,
+ y: me.position.y
+ },
+ bodyB: me,
+ stiffness: 1,
+ damping: 1
+ });
+ Composite.add(engine.world, me.constraint);
+ me.stroke = "transparent"; //used for drawSneaker
+ me.eventHorizon = radius * 40;
+ me.seeAtDistance2 = (me.eventHorizon + 400) * (me.eventHorizon + 400); //vision limit is event horizon
+ me.accelMag = 0.00012 * simulation.accelScale;
+ me.frictionAir = 0.025;
+ me.collisionFilter.mask = cat.player | cat.bullet //| cat.body
+ me.showHealthBar = false;
+ me.memory = Infinity;
+ me.isBoss = true;
+ Matter.Body.setDensity(me, 1); //extra dense //normal is 0.001 //makes effective life much larger
+ me.onDeath = function () {
+ destroyed = true;
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y);
+ }
+ me.do = function () {
+ if (this.health < 1) {
+ this.health += 0.001; //regen
+ simulation.drawList.push({
+ x: this.position.x,
+ y: this.position.y,
+ radius: this.radius / 1.5,
+ color: `rgba(0, 255, 20, ${Math.random() * 0.1})`,
+ time: simulation.drawTime
+ });
+ }
+ this.curl()
+ this.repelBullets()
+ this.seePlayerCheckByDistance()
+ this.checkStatus();
+ const eventHorizon = this.eventHorizon * (0.93 + 0.17 * Math.sin(simulation.cycle * 0.011))
+ //draw darkness
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, eventHorizon * 0.25, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(250,250,250,0.9)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, eventHorizon * 0.55, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(250,250,250,0.5)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(250,250,250,0.1)";
+ ctx.fill();
+ //when player is inside event horizon
+ if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) {
+ if (m.immuneCycle < m.cycle) {
+ if (m.energy > 0) m.energy -= 0.005
+ if (m.energy < 0.1) m.damage(0.0001 * simulation.dmgScale);
+ }
+ const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
+ player.force.x += 0.00125 * player.mass * Math.cos(angle) * (m.onGround ? 1.8 : 1);
+ player.force.y += 0.0001 * player.mass * Math.sin(angle);
+ //draw line to player
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(m.pos.x, m.pos.y);
+ ctx.lineWidth = Math.min(60, this.radius * 2);
+ ctx.strokeStyle = "rgba(250,250,250,0.5)";
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(250,250,250,0.3)";
+ ctx.fill();
+ }
+ }
+ }
+ const sniper = function (x, y, radius = 35 + Math.ceil(Math.random() * 30)) { //same, just white so that we can seen
+ mobs.spawn(x, y, 3, radius, "transparent"); //"rgb(25,0,50)")
+ let me = mob[mob.length - 1];
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ me.isVerticesChange = true
+ // Matter.Body.rotate(me, Math.PI)
+ me.stroke = "transparent"; //used for drawSneaker
+ me.alpha = 1; //used in drawSneaker
+ me.showHealthBar = false;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.canTouchPlayer = false; //used in drawSneaker
+ me.isBadTarget = true;
+ me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
+
+ me.memory = 30 //140;
+ me.fireFreq = 0.005 + Math.random() * 0.002 + 0.0005 * simulation.difficulty; //larger = fire more often
+ me.noseLength = 0;
+ me.fireAngle = 0;
+ me.accelMag = 0.0005 * simulation.accelScale;
+ me.frictionAir = 0.05;
+ me.torque = 0.0001 * me.inertia;
+ me.fireDir = {
+ x: 0,
+ y: 0
+ };
+ me.onDeath = function () { //helps collisions functions work better after vertex have been changed
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
+ }
+ // spawn.shield(me, x, y);
+ me.do = function () {
+ // this.seePlayerByLookingAt();
+ this.seePlayerCheck();
+ this.checkStatus();
+
+ const setNoseShape = () => {
+ const mag = this.radius + this.radius * this.noseLength;
+ this.vertices[1].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[1].y = this.position.y + Math.sin(this.angle) * mag;
+ };
+ //throw a mob/bullet at player
+ if (this.seePlayer.recall) {
+ //set direction to turn to fire
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ // this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 1600; //gives the bullet an arc
+ }
+ //rotate towards fireAngle
+ const angle = this.angle + Math.PI / 2;
+ // c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ //rotate towards fireAngle
+ const dot = Vector.dot({
+ x: Math.cos(angle),
+ y: Math.sin(angle)
+ }, this.fireDir)
+ const threshold = 0.03;
+ if (dot > threshold) {
+ this.torque += 0.000004 * this.inertia;
+ } else if (dot < -threshold) {
+ this.torque -= 0.000004 * this.inertia;
+ } else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) {
+ //fire
+ spawn.sniperBullet(this.vertices[1].x, this.vertices[1].y, 7 + Math.ceil(this.radius / 15), 5);
+ const v = 10 + 8 * simulation.accelScale;
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v + Math.random(),
+ y: this.velocity.y + this.fireDir.y * v + Math.random()
+ });
+ this.noseLength = 0;
+ // recoil
+ this.force.x -= 0.005 * this.fireDir.x * this.mass;
+ this.force.y -= 0.005 * this.fireDir.y * this.mass;
+ }
+ if (this.noseLength < 1.5) this.noseLength += this.fireFreq;
+ setNoseShape();
+ } else if (this.noseLength > 0.1) {
+ this.noseLength -= this.fireFreq / 2;
+ setNoseShape();
+ }
+ // else if (this.noseLength < -0.1) {
+ // this.noseLength += this.fireFreq / 4;
+ // setNoseShape();
+ // }
+
+ if (this.seePlayer.recall) {
+ if (this.alpha < 1) this.alpha += 0.01;
+ } else {
+ if (this.alpha > 0) this.alpha -= 0.03;
+ }
+ //draw
+ if (this.alpha > 0) {
+ if (this.alpha > 0.95) {
+ this.healthBar();
+ if (!this.canTouchPlayer) {
+ this.canTouchPlayer = true;
+ this.isBadTarget = false;
+ this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can touch player
+ }
+ }
+ //draw body
+ ctx.beginPath();
+ const vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.fillStyle = `rgba(250,250,250,${this.alpha * this.alpha})`;
+ ctx.fill();
+ } else if (this.canTouchPlayer) {
+ this.canTouchPlayer = false;
+ this.isBadTarget = true
+ this.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
+ }
+ };
+ }
+ const portal = level.portal({
+ x: 650,
+ y: -1000
+ }, Math.PI * 1.5, {
+ x: 525,
+ y: 2625
+ }, -Math.PI)
+ document.body.style.transition = '0ms'
+ document.body.style.backgroundColor = "#061026" //"#061026";
+
+ var yy = new Image();
+ yy.src = 'https://raw.githubusercontent.com/Whyisthisnotavalable/image-yy/main/Hotpot6.png';
+ color.map = "#FFFFFF11";
+ color.bullet = "#FFFFFF";
+ level.custom = () => {
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ ctx.drawImage(yy, 0 - 500, 0 - 500, 1000, 1000)
+ portal[0].draw();
+ portal[1].draw();
+ portal[2].query();
+ portal[3].query();
+ if (destroyed == false) {
+ lock.isClosing = true;
+ } else {
+ lock.isClosing = false;
+ }
+ lock.openClose();
+
+ };
+ level.customTopLayer = () => {
+ lock.draw()
+ /*
+ ctx.beginPath()
+ ctx.strokeStyle = "transparent";
+ ctx.fillStyle = "#FFFFFF22"
+ ctx.arc(m.pos.x, m.pos.y, 500, 0, Math.PI * 2)
+ ctx.fill()
+ ctx.fillStyle = "#FFFFFF55"
+ ctx.arc(m.pos.x, m.pos.y, 1000, 0, Math.PI * 2)
+ ctx.fill();
+ ctx.stroke(); */
+ ctx.beginPath();
+ ctx.moveTo(m.pos.x, m.pos.y)
+ const arc = Math.PI / 4
+ ctx.arc(m.pos.x, m.pos.y, 100, m.angle + arc, m.angle - arc)
+ ctx.arc(m.pos.x, m.pos.y, 4000, m.angle - arc, m.angle + arc)
+ ctx.fillStyle = "rgba(255,255,255,0.7)";
+ ctx.globalCompositeOperation = "destination-in";
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over";
+ ctx.clip();
+ };
+ level.setPosToSpawn(0, -50);
+ level.exit.x = -275;
+ level.exit.y = 2900;
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ //map
+ spawn.mapRect(-125, -325, 225, 25);
+ spawn.mapRect(300, -150, 25, 325);
+ spawn.mapRect(-325, -125, 25, 300);
+ spawn.mapRect(-150, 300, 275, 25);
+ spawn.mapRect(125, -300, 25, 25);
+ spawn.mapRect(175, -275, 25, 25);
+ spawn.mapRect(225, -250, 25, 25);
+ spawn.mapRect(250, -200, 25, 25);
+ spawn.mapRect(-175, -300, 25, 25);
+ spawn.mapRect(-225, -275, 25, 25);
+ spawn.mapRect(-300, -200, 25, 25);
+ spawn.mapRect(150, 275, 25, 25);
+ spawn.mapRect(200, 225, 25, 25);
+ spawn.mapRect(250, 200, 25, 25);
+ spawn.mapRect(250, -225, 25, 25);
+ spawn.mapRect(275, -175, 25, 25);
+ spawn.mapRect(200, -275, 25, 25);
+ spawn.mapRect(150, -300, 25, 25);
+ spawn.mapRect(100, -325, 25, 25);
+ spawn.mapRect(-150, -300, 25, 25);
+ spawn.mapRect(-200, -300, 25, 25);
+ spawn.mapRect(-250, -250, 25, 25);
+ spawn.mapRect(-275, -225, 25, 25);
+ spawn.mapRect(-300, -175, 25, 50);
+ spawn.mapRect(275, 175, 25, 25);
+ spawn.mapRect(250, 200, 25, 25);
+ spawn.mapRect(225, 225, 25, 25);
+ spawn.mapRect(175, 250, 25, 25);
+ spawn.mapRect(125, 300, 25, 25);
+ spawn.mapRect(-300, 325, 200, 150);
+ spawn.mapRect(-400, 425, 225, 150);
+ spawn.mapRect(-4450, 2900, 1550, 150);
+ spawn.mapRect(-4500, 2525, 150, 525);
+ spawn.mapRect(-4800, 2150, 150, 400);
+ spawn.mapRect(-4400, 2025, 650, 150);
+ spawn.mapRect(-2425, 50, 2125, 150);
+ spawn.mapRect(-2425, 50, 150, 1300);
+ spawn.mapRect(-4600, 1175, 2325, 175);
+ spawn.mapRect(-5075, 1650, 450, 150);
+ spawn.mapRect(-4650, 1225, 75, 125);
+ spawn.mapRect(-4700, 1275, 75, 75);
+ spawn.mapRect(-425, 2925, 425, 125);
+ spawn.mapRect(-450, 2375, 450, 100);
+ spawn.mapRect(-3050, 550, 150, 450);
+ spawn.mapRect(-2925, 825, 100, 175);
+ spawn.mapRect(-2650, 375, 275, 125);
+ spawn.mapRect(-75, 2950, 300, 100);
+ spawn.mapRect(-625, -500, 125, 575);
+ spawn.mapRect(-1050, -325, 275, 100);
+ spawn.mapRect(-1075, -775, 100, 550);
+ spawn.mapRect(-1075, -775, 300, 100);
+ spawn.mapRect(-525, -1100, 1025, 625);
+ spawn.mapRect(450, -1000, 450, 1500);
+ spawn.mapRect(-300, 500, 1200, 75);
+ spawn.mapRect(-200, 425, 725, 100);
+ spawn.mapRect(525, 2450, 275, 600);
+ spawn.mapRect(-25, 2375, 825, 125);
+ spawn.mapRect(400, -1500, 500, 100);
+ spawn.mapRect(800, -1500, 100, 525);
+ spawn.mapRect(-400, 500, 1250, 1900);
+ spawn.mapRect(-300, 2910, 150, 25);
+ spawn.mapRect(-625, -1000, 125, 175);
+ spawn.spawnStairs(-400, 3000, 25, 2500, 2500, 250);
+ spawn.spawnStairs(500, 3000, 5, 250, 250, 250);
+ spawn.debris(-1550, -250, 100);
+ spawn.debris(-1100, 850, 100);
+ spawn.debris(-3700, 1025, 100);
+ spawn.debris(-3525, 2725, 100);
+ spawn.debris(-4750, 2050, 100);
+ spawn.debris(-4000, 1900, 100);
+ spawn.debris(225, -1225, 100);
+
+ //mobs
+ spawn.sneaker(-1350, 1350);
+ spawn.sneaker(-2275, 2275);
+ sniper(-3050 + Math.floor(Math.random() * 100) - Math.floor(Math.random() * 100), 1475 + Math.floor(Math.random() * 100) - Math.floor(Math.random() * 100));
+ sniper(-2925 + Math.floor(Math.random() * 100) - Math.floor(Math.random() * 100), 1775 + Math.floor(Math.random() * 100) - Math.floor(Math.random() * 100));
+ sniper(-3075 + Math.floor(Math.random() * 100) - Math.floor(Math.random() * 100), 1600 + Math.floor(Math.random() * 100) - Math.floor(Math.random() * 100));
+ sniper(-3100 + Math.floor(Math.random() * 100) - Math.floor(Math.random() * 100), 1975 + Math.floor(Math.random() * 100) - Math.floor(Math.random() * 100));
+ sniper(-3075 + Math.floor(Math.random() * 100) - Math.floor(Math.random() * 100), 1750 + Math.floor(Math.random() * 100) - Math.floor(Math.random() * 100));
+ sniper(-3350, 425);
+ sniper(-3550, 600);
+ sniper(-3325, 775);
+ sniper(-5525, 1975);
+ sniper(-50, -1300);
+ for (let i = 0; i < 10 + simulation.difficulty; i++) {
+ spawn.ghoster(0 + Math.floor(Math.random() * 5000) - Math.floor(Math.random() * 5000), 0 + Math.floor(Math.random() * 5000) - Math.floor(Math.random() * 5000))
+ }
+ core(-2000, -1000);
+ powerUps.spawnStartingPowerUps(0, 0)
+ powerUps.addResearchToLevel()
+ },
+ staircase() {
+ simulation.makeTextLog(`
staircase by
ryanbear `);
+
+ level.custom = () => {
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ aaa.query();
+ bbb.query();
+ ccc.query();
+ ddd.move();
+ eee.query();
+ fff.query();
+ ggg.query();
+ hhh.query();
+ iii.query();
+ jjj.query();
+ kk.query();
+ lll.query();
+ mmm.query();
+ nnn.query();
+ ooo.query();
+ ppp.query();
+ };
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 7300;
+ level.exit.y = -5154;
+ // spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d8dadf";
+ // powerUps.spawnStartingPowerUps(1475, -1175);
+ // spawn.debris(750, -2200, 3700, 16); //16 debris per level
+
+ spawn.mapRect(-100, 0, 2100, 100);
+ spawn.mapRect(1984, 17, 100, 500);
+ spawn.mapRect(2013, 522, 1618, 100);
+ spawn.bodyRect(2090, 328, 100, 100);
+
+ spawn.mapRect(3619, 14, 100, 500)
+ var aaa = level.hazard(1999, 10, 1618, 500);
+ var bbb = level.vanish(2320, -345, 234, 20);
+ var ccc = level.vanish(2862, -324, 234, 20);
+ var eee = level.vanish(3002, -1100, 234, 20);
+ var ddd = level.elevator(3399, -420, 200, 200, -950, 0.003, { up: 0.1, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
+ var fff = level.vanish(3359, -1300, 234, 20);
+ var ggg = level.boost(3020, -1600, 700);
+ var hhh = level.vanish(2700, -1940, 1147, 20);
+ var iii = level.boost(5038, -2000, 700);
+ var jjj = level.vanish(5092, -3498, 100, 100);
+ var kk = level.boost(5092, -3772, 700);
+ var lll = level.boost(5372, -2824, 700);
+ var mmm = level.vanish(5112, -3000, 100, 100);
+ var nnn = level.vanish(5367, -3000, 100, 100);
+ var ooo = level.boost(4810, -3161, 700);
+ var ppp = level.vanish(5383, -3485, 100, 100);
+ spawn.mapRect(5377, -4198, 1000, 100);
+ spawn.mapRect(6390, -4359, 200, 200);
+ spawn.mapRect(6605, -4563, 200, 200);
+ spawn.mapRect(6809, -4758, 200, 200);
+ spawn.mapRect(7014, -4962, 200, 200);
+ spawn.mapRect(7212, -5158, 200, 200);
+
+
+
+ spawn.mapRect(4156, -1898, 1000, 100);
+ // spawn.bodyRect(1540, -1110, 300, 25, 0.9);
+ // spawn.randomSmallMob(1300, -70);
+ spawn.randomMob(590, -315);
+ spawn.randomMob(1343, -757);
+ spawn.randomMob(4037, -926);
+ spawn.randomMob(3621, -2376);
+ spawn.randomMob(5026, -2441);
+ spawn.randomMob(4253, -2863);
+ spawn.randomMob(4355, -2430);
+ spawn.randomMob(5316, -3265);
+ spawn.randomMob(5885, -4427);
+ spawn.randomMob(6666, -4979);
+
+
+
+ spawn.laserBoss(6128, -4905);
+
+ // spawn.randomGroup(1700, -900, 0.4);
+ // if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300);
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ fortress() {
+ simulation.makeTextLog(`
fortress by
Desboot `);
+ const boost1 = level.boost(3600, -250, 1000)
+ const boost2 = level.boost(60, -604, 1000)
+ const boost3 = level.boost(2160, -1260, 1000)
+ powerUps.spawnStartingPowerUps(1033.3, -121.4)
+ level.custom = () => {
+ boost1.query();
+ boost2.query();
+ boost3.query();
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 3586; //3586.5, -1464.0
+ level.exit.y = -1494;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d8dadf";
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(0,0,0,0.3)"
+ ctx.fillRect(-272, -580, 1700, 600)
+ ctx.fillRect(1427.5, -487, 1280, 600)
+ ctx.fillRect(2707.3, -580, 1200, 600)
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+ ctx.fillRect(2752, -1744, 1075, 1164)
+ ctx.fillRect(937, -1590, 339, 550)
+ ctx.fillRect(1158, -1040, 118, 550)
+ ctx.fillRect(3049, -1063, 339, 500)
+ ctx.fillRect(1439, -1281, 297, 800)
+ ctx.fillRect(2130, -1182, 167, 800)
+ ctx.fillRect(1892, -2073, 238, 1593)
+ ctx.fillRect(2297, -2073, 238, 1593)
+ ctx.fillStyle = "rgba(0,0,0,0.15)"
+ ctx.fillRect(483, -1277, 350, 700)
+ ctx.fillRect(833, -1000, 325, 450)
+ ctx.fillStyle = "rgba(64,64,64,0.97)" //hidden section
+ ctx.fillRect(2800, -1712, 730, 300)
+ };
+
+ spawn.debris(2700, -120, 180, 3);
+ spawn.debris(1350, -100, 280, 3);
+ spawn.debris(2300, -700, 380, 5);
+ spawn.debris(976, -775, 38, 5);
+ spawn.debris(840, -1424, 3080, 5);
+ spawn.debris(2300, -700, 3080, 5);
+
+ spawn.mapRect(-272, 0, 4198, 123);
+ spawn.mapRect(-272, -581, 132, 581);
+ spawn.mapRect(-272, -581, 572, 326);
+ spawn.mapRect(1462, -229, 92, 229);
+ spawn.mapRect(1462, -229, 352, 57);
+ spawn.mapRect(2872, -220, 1056, 330);
+ spawn.mapRect(170, -260, 484, 80);
+ spawn.mapRect(476, -581, 1162, 75);
+ spawn.mapRect(951, -519, 1760, 132);
+ spawn.mapRect(1747, -492, 506, 66);
+ spawn.mapRect(2462, -581, 1074, 75);
+ spawn.mapRect(1136, -616, 510, 100);
+ spawn.mapRect(3815.6, -1461, 114, 1300); //far right wall
+ spawn.mapRect(480, -1456, 106, 651); //far left wall
+ spawn.mapRect(1426, -906, 106, 400);
+ spawn.mapRect(480, -1302, 374, 57);
+ spawn.mapRect(788, -1302, 75, 308);
+ spawn.mapRect(788, -1055, 370, 62);
+ spawn.mapRect(3049, -1170, 471, 106);
+ spawn.mapRect(3348, -1170, 188, 663);
+ spawn.mapRect(2751, -1461, 1088, 53); //roof under the exit
+ spawn.mapRect(2751, -1743, 92, 915); //wall on left or far right side
+ spawn.mapRect(937, -1667, 339, 84); //upper left platform
+ spawn.mapRect(1135, -3239, 119, 1450);
+ spawn.mapRect(1440, -1346, 295, 66); //center left platform
+ spawn.mapRect(2090, -1240, 242, 57); //center righ platform
+ spawn.mapRect(1892, -2214, 88, 220); //vertical part of left L
+ spawn.mapRect(1892, -2073, 238, 84); //flat part of left L
+ spawn.mapRect(2447, -2214, 88, 220); //vertical part of right L
+ spawn.mapRect(2297, -2073, 238, 84); //flat part of right L
+ spawn.mapRect(2751, -1743, 1078, 57); //exit roof //3587.2, -1470.0
+ spawn.mapRect(3584, -1470, 103, 57); //wall below door3689
+ spawn.mapRect(3428, -1735, 103, 173); //wall covering secret
+
+ spawn.mapRect(-11000, -1000, 100, 10); //SAL
+ spawn.mapRect(-11000, -1000, 10, 100); //SAL
+ spawn.mapRect(-10900, -900, 10, 100); //SAL
+ spawn.mapRect(-11000, -900, 100, 10); //SAL
+ spawn.mapRect(-11000, -800, 100, 10); //SAL
+ spawn.mapRect(-10800, -1000, 10, 200); //SAL
+ spawn.mapRect(-10700, -1000, 10, 200); //SAL
+ spawn.mapRect(-10800, -1000, 100, 10); //SAL
+ spawn.mapRect(-10800, -900, 100, 10); //SAL
+ spawn.mapRect(-10600, -1000, 10, 200); //SAL
+ spawn.mapRect(-10600, -800, 100, 10); //SAL
+
+ spawn.mapRect(-11000, -91000, 100, 10); //SAL
+ spawn.mapRect(-11000, -91000, 10, 100); //SAL
+ spawn.mapRect(-10900, -90900, 10, 100); //SAL
+ spawn.mapRect(-11000, -90900, 100, 10); //SAL
+ spawn.mapRect(-11000, -90800, 100, 10); //SAL
+ spawn.mapRect(-10800, -91000, 10, 200); //SAL
+ spawn.mapRect(-10700, -91000, 10, 200); //SAL
+ spawn.mapRect(-10800, -91000, 100, 10); //SAL
+ spawn.mapRect(-10800, -90900, 100, 10); //SAL
+ spawn.mapRect(-10600, -91000, 10, 200); //SAL
+ spawn.mapRect(-10600, -90800, 100, 10); //SAL
+ //mobs
+ spawn.randomMob(3104.9, -1284.9, 0.2);
+ spawn.randomMob(1784.7, -95.9, 0.2);
+ spawn.randomMob(3474.2, -406.7, 0.1);
+ spawn.randomMob(1603.2, -1493.5, 0.4);
+ spawn.randomMob(772.4, -1505.2, 0.2);
+ spawn.randomMob(824.6, -781.3, 0.2);
+ spawn.randomMob(818.8, -1468.9, 0.2);
+ spawn.randomMob(-124.7, -853, 0.2);
+ spawn.randomMob(3011.1, -1978.0, -0.2);
+ spawn.randomMob(2428.0, -236.8, 0.1);
+ spawn.randomSmallMob(694.3, -385.3);
+ spawn.randomSmallMob(1142.0, -808.4);
+ spawn.randomSmallMob(791.5, -803.7);
+ spawn.randomSmallMob(3175.8, -830.8);
+ spawn.randomSmallMob(1558.5, -1940.8);
+ spawn.randomSmallMob(2700, -475);
+ spawn.randomSmallMob(2700, -475);
+ spawn.pulsar(1762.9, -2768.3)
+ spawn.pulsar(3821.5, -2373.9)
+ let randomBoss = Math.floor(Math.random() * 5);
+ spawn[["laserBoss", "blinkBoss", "shooterBoss", "launcherBoss", "pulsarBoss", "beetleBoss", "bladeBoss", "revolutionBoss", "dragonFlyBoss", "spiderBoss"][randomBoss]](2058.5, -711.4, 100, false);
+
+ //spawn powerups
+ // powerUps.spawn(3167.6, -1300, "tech")
+ powerUps.spawn(3125.8, -1543.4, "tech")
+ powerUps.spawn(3125.8, -1543.4, "heal")
+ powerUps.spawn(3125.8, -1543.4, "ammo")
+ powerUps.spawn(3125.8, -1543.4, "ammo")
+ powerUps.spawn(3137.6, -1300, "ammo")
+ powerUps.spawn(1605.2, -1436.9, "heal")
+ powerUps.spawn(2912.9, -1940.9, "ammo")
+ powerUps.spawn(3167.6, -1300, "heal")
+ powerUps.spawn(1, 1, "ammo")
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ commandeer() {
+ simulation.makeTextLog(`
commandeer by
Desboot `);
+
+ let waterFallWidth = 400
+ let waterFallX = 15900
+ let waterFallSmoothX = 0
+ const elevator = level.elevator(-80.4, -931.6, 180, 50, -1550)
+ 15900 && player.position.x < 16300 && player.position.y > -960.2
+ //const slime = level.hazard(15900, -960, 400, 6000);
+ const slime2 = level.hazard(15147.2, -1782.4, 2000, 822);
+ const boost1 = level.boost(5950, -20, 700)
+ const boost2 = level.boost(21088, -1672, 700)
+ const boost3 = level.boost(19390, -31, 1700)
+ const boost4 = level.boost(19390, -31, 1700)
+ const boost5 = level.boost(17274, -1242, 1000)
+ const portal = level.portal({ x: 443, y: -1636 }, Math.PI, { x: 21391.9, y: -1806.3 }, -Math.PI)
+ const portal2 = level.portal({ x: 16838.3, y: -626.7 }, Math.PI, { x: 16882.8, y: -2566.5 }, -Math.PI)
+ const buttonDoor = level.button(21889, -10)
+ const door = level.door(19119, -2133, 110, 510, 480)
+ const buttonDoor2 = level.button(18711, -2210)
+ const door2 = level.door(17041, -412, 110, 510, 480)
+ const buttonDoor3 = level.button(20456.6, -1636.2)
+ const door3 = level.door(20238, -781.4, 88, 452, 412)
+ const hazard2 = level.hazard(2550, -150, 10, 0.4) //y=-1485
+
+ simulation.enableConstructMode()
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 15316;
+ level.exit.y = -30;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#001738";
+ color.map = "#444" //custom map color
+
+
+
+ level.custom = () => {
+ //spawn.mapRect(22330, -2688.75, 400, 800);
+ //spawn.mapRect(22330, -1793.5, 400, 800);//-46.25*2=-92.5
+ //spawn.mapRect(22330, -804.25, 400, 800);//-46.25*3
+
+
+ ctx.fillStyle = "rgba(250,250,250,0.8)"//lights
+ ctx.beginPath()
+ ctx.moveTo(1124, -628)
+ ctx.lineTo(496, 0)
+ ctx.lineTo(1852, 0)
+ ctx.lineTo(1224, -628)
+ ctx.fill()
+
+ ctx.beginPath()
+ ctx.moveTo(906, -1365)
+ ctx.lineTo(206, -690)
+ ctx.lineTo(1706, -690)
+ ctx.lineTo(1006, -1365)
+ ctx.fill()
+
+ ctx.beginPath()
+ ctx.moveTo(3330, -1905)//-700
+ ctx.lineTo(2815.6, -1405.8)
+ ctx.lineTo(2815.6, -1230)
+ ctx.lineTo(4022.9, -1283.9)
+ ctx.lineTo(4023.5, -1405.8)
+ ctx.lineTo(3430, -1905)
+
+ ctx.fill()
+
+
+
+
+ ctx.fillStyle = "rgba(63,247,251,0.8)"
+ ctx.fillRect(22330, -2713.75, 550, 700)//15845.0, -1262.2
+ ctx.fillRect(22330, -1743.5, 550, 700)
+ ctx.fillRect(22330, -754.25, 550, 700)
+
+ ctx.fillRect(6237, -1830.7, 550, 700)
+ ctx.fillRect(6237, -840.4, 550, 700)
+ ctx.fillStyle = "rgba(200,200,200,0.8)"
+ ctx.fillRect(-192, -1973, 6484, 2071)
+ ctx.fillStyle = "rgba(240,240,240,0.8)"
+
+ ctx.fillRect(15109.5, -2867.5, 7284, 2971)
+ ctx.fillStyle = "rgba(35,35,35,0.8)"
+ ctx.fillRect(15145.9, -960, 200, 25)
+
+
+
+
+ ctx.fillStyle = "rgba(255,255,255,0.9)"
+
+
+
+
+
+ buttonDoor.query();
+ buttonDoor.draw();
+ buttonDoor2.query();
+ buttonDoor2.draw();
+ buttonDoor3.query();
+ buttonDoor3.draw();
+
+
+ //slime.query();
+ slime2.query();
+
+
+ if (buttonDoor.isUp) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ if (buttonDoor2.isUp) {
+ door2.isClosing = true
+ } else {
+ door2.isClosing = false
+ }
+ if (buttonDoor3.isUp) {
+ door3.isClosing = true
+ } else {
+ door3.isClosing = false
+ }
+ door.openClose();
+ door2.openClose();
+ door3.openClose();
+ portal[2].query()
+ portal[3].query()
+ portal2[2].query()
+ portal2[3].query()
+
+ boost1.query();
+ boost2.query();
+ boost3.query();
+ boost4.query();
+ boost5.query();
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ ctx.fillStyle = "rgba(0,0,0,0.2)"//shadows
+ ctx.fillRect(2773, -682, 469, 500)
+ ctx.fillRect(3947, -851, 469, 700)
+ ctx.fillRect(4818, -1006, 400, 400)
+ ctx.fillRect(5313, -1309, 1000, 700)
+
+ ctx.fillRect(16705, -2831, 40, 700)
+ ctx.fillRect(16140, -2812, 40, 400)
+ ctx.fillRect(15559, -2855, 40, 800)
+ ctx.fillRect(16530, -2855, 30, 200)
+
+
+ ctx.beginPath()
+ ctx.moveTo(18254.7, -2194.1)
+ ctx.lineTo(18554.6, -1952.7)
+ ctx.lineTo(18554.6, -1992.7)
+ ctx.lineTo(18294.7, -2194.1)
+ ctx.fill()
+ ctx.beginPath()
+ ctx.moveTo(18154.7, -1004.1)
+ ctx.lineTo(18554.6, -762.7)
+ ctx.lineTo(18554.6, -802.7)
+ ctx.lineTo(18214.7, -1004.1)
+ ctx.fill()
+
+ ctx.beginPath()
+ ctx.moveTo(17585.2, -1123.8)
+ ctx.lineTo(17151.2, -781.7)
+ ctx.lineTo(17151.2, -741.7)
+ ctx.lineTo(17625.2, -1123.8)
+ ctx.fill()
+
+
+ ctx.fillRect(20540, -1103, 610, 300)
+ ctx.fillRect(20820, -243, 410, 300)
+ ctx.fillRect(5772, -609, 469, 700)
+ ctx.fillRect(5772, -609, 469, 700)
+
+ ctx.fillStyle = "rgba(48,184,140,255)"
+ ctx.fillRect(waterFallX, -960, waterFallWidth, 6000)
+ ctx.fillStyle = `hsla(160, 100%, 43%,${0.3 + 0.07 * Math.random()})`
+ ctx.fillRect(waterFallX + waterFallWidth * Math.random(), -900 - Math.random() * 400, Math.random() * 5 + 8, 6000)
+ ctx.fillRect(waterFallX + waterFallWidth * Math.random(), -900 - Math.random() * 400, Math.random() * 5 + 5, 6000)
+ waterFallWidth = 0.995 * waterFallWidth + 4 * Math.random()//4.7
+ waterFalSmoothlX = 0.96 * waterFallSmoothX + 20 * Math.random()//3.5
+ waterFallX = waterFallSmoothX + 15900
+
+
+ ctx.fillStyle = "rgba(0,0,0,0.4)"//wires
+ ctx.fillRect(20990, -2672, 20, 112)
+ ctx.fillRect(21090, -2506, 72, 20)
+ ctx.fillRect(21090, -1970, 72, 20)
+
+
+
+ ctx.fillRect(16901.8, -2497.7, 25, 100)
+ ctx.fillRect(16901.8, -2397.7, 50, 25)
+ ctx.fillRect(16951.8, -2397.7, 25, 1640)
+ ctx.fillRect(16901.8, -782.7, 50, 25)
+ ctx.fillRect(16901.8, -757.7, 25, 100)
+
+
+ ctx.fillRect(20900, -2666, 500, 9)
+ ctx.fillRect(20900, -2651, 1315, 9)
+ ctx.fillRect(20900, -2636, 1300, 9)
+ ctx.fillRect(20900, -2621, 245, 9)
+ ctx.fillRect(20900, -2606, 230, 9)
+ ctx.fillRect(20900, -2591, 215, 9)
+ ctx.fillRect(20900, -2576, 200, 9)
+
+ ctx.fillRect(21145, -2621, 9, 700)
+ ctx.fillRect(21130, -2606, 9, 1000)
+ ctx.fillRect(21115, -2591, 9, 1000)
+ ctx.fillRect(21100, -2576, 9, 850)
+
+ ctx.fillRect(21400, -3066, 9, 409)
+
+
+ ctx.fillRect(20900, -1726, 209, 9)
+ ctx.fillRect(21145, -1921, 270, 9)
+ ctx.fillRect(21415, -1921, 9, 50)
+
+ ctx.fillRect(22200, -2636, 9, 1300)
+ ctx.fillRect(22215, -2651, 9, 300)
+
+ ctx.fillRect(22200, -1336, 300, 9)
+ ctx.fillRect(22215, -2351, 300, 9)
+
+
+ //943.9, -1698.0
+
+ ctx.fillRect(916.5, -1725, 80, 80)//+55 // 55/2=27.5
+ ctx.fillRect(1204, -1706, 25, 40)//179
+ ctx.fillRect(1354, -1706, 25, 40)
+ ctx.fillRect(1504, -1885, 25, 40)
+ ctx.fillRect(3504, -1885, 25, 40)
+ ctx.fillRect(5504, -1885, 25, 40)
+
+
+ ctx.fillRect(1019, -1718, 9, 20)
+ ctx.fillRect(1019, -1674, 9, 20)
+
+ ctx.fillRect(996, -1718, 23, 9)
+ ctx.fillRect(996, -1663, 23, 9)
+
+
+
+
+ ctx.fillRect(1019, -1698, 425, 9)
+ ctx.fillRect(1444, -1868, 9, 179)
+ ctx.fillRect(1444, -1877, 4700, 9)
+
+ ctx.fillRect(1019, -1683, 440, 9)
+ ctx.fillRect(1459, -1853, 9, 179)
+ ctx.fillRect(1459, -1862, 4670, 9)
+
+ ctx.fillRect(6144, -1877, 9, 100)
+ ctx.fillRect(6144, -1777, 100, 9)
+
+ ctx.fillRect(6129, -1862, 9, 1100)
+ ctx.fillRect(6129, -762, 150, 9)
+
+
+
+
+
+
+
+ };
+
+
+ level.customTopLayer = () => {
+
+
+
+ door.draw();
+ door2.draw();
+ door3.draw();
+
+ portal[0].draw();
+ portal[1].draw();
+ portal[2].draw();
+ portal[3].draw();
+ portal2[0].draw();
+ portal2[1].draw();
+ portal2[2].draw();
+ portal2[3].draw();
+ elevator.move()
+
+
+ // if (player.position.x > 15900 && player.position.x < 16300 && player.position.y > -1360.2) {
+ // Matter.Body.setVelocity(player, {
+ // x: player.velocity.x,
+ // y: player.velocity.y + 10
+ // });
+ // }else{
+ // if (Math.abs(player.velocity.x) > 0.5){
+ // if (m.onGround){
+ // Matter.Body.setVelocity(player, {
+ // x: player.velocity.x + (0.07 * (Math.abs(player.velocity.x) / player.velocity.x)),
+ // y: player.velocity.y - 0.2
+
+ // });
+ // }else{
+ // Matter.Body.setVelocity(player, {
+ // x: player.velocity.x,
+ // y: player.velocity.y - 0.2
+ // });
+ // }
+ // }else{
+ // Matter.Body.setVelocity(player, {
+ // x: player.velocity.x,
+ // y: player.velocity.y - 0.2
+ // });
+ // }
+ // }
+
+ if (player.position.x > 15900 && player.position.x < 16300 && player.position.y > -1360.2) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 2
+ });
+ } else {
+ if (Math.abs(player.velocity.x) > 0.5) {
+ if (m.onGround) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x + (0.07 * (Math.abs(player.velocity.x) / player.velocity.x)),
+ y: player.velocity.y - 0.2
+
+ });
+ } else {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y - 0.2
+ });
+ }
+ } else {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y - 0.2
+ });
+ }
+ }
+ hazard2.opticalQuery();
+
+
+ };
+
+
+
+
+
+ //1273.2, -1404.7
+
+ spawn.mapRect(1124, -653, 100, 25);
+ spawn.mapRect(906, -1390, 100, 25);
+ spawn.mapRect(3330, -1930, 100, 25);
+
+
+ //first ship base
+ spawn.mapRect(-300, 0, 6684, 100);//lower floor
+ spawn.mapRect(-300, -2071, 154, 2071);//left right wall
+ spawn.mapRect(2511, -300, 1309, 308);//left big block
+ spawn.mapRect(3820, -184, 1309, 184);//right big block
+ spawn.mapRect(-300, -739, 2549, 100);//upper right floor
+ spawn.mapRect(2056, -1309, 2764, 169);//upper center floor
+ spawn.mapRect(2056, -1309, 193, 650);//upper left floor wall
+ spawn.mapRect(4636, -1309, 193, 793);//upper right floor wall
+ spawn.mapRect(4821, -654, 955, 138);//upper right floor
+ spawn.mapRect(6237, -2071, 147, 2071);//far right wall
+ spawn.mapRect(-300, -2071, 6684, 154);//roof
+
+ //first ship details
+ spawn.mapRect(245, -360, 70, 400);//start room wall
+ spawn.mapRect(500, -1929, 154, 462);
+ spawn.mapRect(185, -1517, 469, 77);
+ spawn.mapRect(2773, -682, 469, 77);//walls in 1st room
+ spawn.mapRect(3743, -566, 77, 469);
+ spawn.mapRect(3947, -851, 469, 77);
+ spawn.mapRect(5313, -1309, 1000, 70);//walls in second area
+ spawn.mapRect(4818, -1006, 400, 70);
+ spawn.mapRect(4768, -1626, 800, 70);
+ spawn.mapRect(4760, -1626, 70, 400);
+ spawn.mapRect(645.1, -1480.8, 700, 100);//room for shielding boss
+ spawn.mapVertex(515, -1447, "0 0 0 100 -400 0");
+ spawn.mapRect(1245.1, -1980.8, 100, 500);
+ spawn.mapRect(2346.9, -1658.8, 469, 77);
+ spawn.mapRect(4023.6, -1723.7, 469, 77);
+
+ //engines //y -2972 -> 0
+ spawn.mapRect(6237, -1880.7, 400, 800);
+ spawn.mapRect(6237, -890.4, 400, 800);
+
+
+ //first ship blocks/debris
+ spawn.debris(3267.6, -797.1, 700, 5); //16 debris per level
+ spawn.debris(1626.0, -372.5, 1700, 8); //16 debris per level
+ spawn.debris(1880.1, -1508.9, 3700, 16); //16 debris per level
+ spawn.debris(5335.3, -1431.6, 3700, 16); //16 debris per level
+ spawn.debris(1563.8, -1087.9, 700, 5); //16 debris per level
+ spawn.bodyRect(1540, -1110, 218, 125, 0.9);
+
+
+
+ //first ship mobs
+ spawn.randomSmallMob(893.5, -120.8);
+
+ // spawn.randomMob(2903.9, -754.5, 0.4);
+ // spawn.randomMob(5577.0, -217.0, 0.2);
+ // spawn.randomMob(765.8, -1029.7, 0.5);
+ // spawn.randomMob(2680.1, -1779.2, 0.6);
+ // spawn.randomMob(20079.4, -2219.7, 0.4);
+ // spawn.randomMob(3924.9, -1504.1, 0.5);
+ // spawn.randomMob(21284.2, -983.1, 0.3);
+ // spawn.randomMob(20381.0, -254.2, 0.5);
+ // spawn.randomMob(18375.6, -1574.4, 0.6);
+ // spawn.randomMob(19448.2, -1323.3, 0.3);
+ // spawn.randomMob(18397.7, -711.2, 0.3);
+ // spawn.randomMob(15547.2, -2249.6, 0.5);
+ // spawn.randomSmallMob(16114.6, -2524.2);
+ // spawn.randomSmallMob(15378.9, -2549.6);
+
+ // spawn.randomSmallMob(3266.4, -1578.4);
+ // spawn.randomSmallMob(4386.2, -439.6);
+ // spawn.randomSmallMob(5667.0, -847.8);
+ // spawn.randomSmallMob(3158.5, -1581.8);
+ // spawn.randomSmallMob(3866.7, -1483.2);
+ // spawn.randomSmallMob(4652.3, -1729.4);
+ // spawn.randomSmallMob(1068.7, -106.1);
+ // spawn.randomSmallMob(3382.5, -1590.6);//3545.0, -413.0
+ // spawn.randomSmallMob(5099.7, -1204.2);
+ // spawn.randomSmallMob(1456.4, -1014.8);
+ // spawn.randomSmallMob(20432.4, -1374.3);
+ // spawn.randomSmallMob(20381.0, -254.2);
+ // spawn.randomSmallMob(3505.1, -1531.1);
+ // spawn.randomSmallMob(20648.1, -136.8);
+ // spawn.randomSmallMob(17502.8, -1520.6);
+ // spawn.randomSmallMob(17438.7, -876.7);
+
+ spawn.randomMob(18375.6, -1574.4, 0.2);
+ spawn.randomSmallMob(15378.9, -2549.6);
+ spawn.randomSmallMob(5820.2, -1545.2);
+ spawn.randomMob(765.8, -1029.7, 0.2);
+ spawn.randomMob(21284.2, -983.1, 0.3);
+ spawn.randomSmallMob(3382.5, -1590.6);
+ spawn.randomSmallMob(3545.0, -413.0);
+ spawn.randomMob(20381.0, -254.2, 0.6);
+ spawn.randomSmallMob(20432.4, -1374.3);
+ spawn.randomSmallMob(5667.0, -847.8);
+ spawn.randomMob(2903.9, -754.5, 0.2);
+ spawn.randomSmallMob(3266.4, -1578.4);
+ spawn.randomSmallMob(20648.1, -136.8);
+ spawn.randomSmallMob(16114.6, -2524.2);
+ spawn.randomSmallMob(20381.0, -254.2);
+ spawn.randomMob(5577.0, -217.0, 0.3);
+ spawn.randomSmallMob(1456.4, -1014.8);
+ spawn.randomSmallMob(1068.7, -106.1);
+ spawn.randomSmallMob(5099.7, -1204.2);
+ spawn.randomSmallMob(17502.8, -1520.6);
+ spawn.randomMob(15547.2, -2249.6, 0.2);
+ spawn.randomMob(19448.2, -1323.3, 0.7);
+ spawn.randomSmallMob(3158.5, -1581.8);
+ spawn.randomSmallMob(17438.7, -876.7);
+ spawn.randomMob(20079.4, -2219.7, 0.2);
+ spawn.randomMob(2680.1, -1779.2, 0.6);
+ spawn.randomMob(3924.9, -1504.1, 0.3);
+ spawn.randomSmallMob(4652.3, -1729.4);
+ spawn.randomMob(18397.7, -711.2, 0.3);
+ spawn.randomSmallMob(4386.2, -439.6);
+
+ spawn.randomSmallMob(3505.1, -1531.1);
+ spawn.randomSmallMob(3866.7, -1483.2);
+
+
+
+
+ //second ship mobs
+ spawn.debris(17732.3, -550.0, 700, 5); //16 debris per level
+ spawn.debris(17827.2, -2357.1, 700, 5); //16 debris per level
+ spawn.debris(16108.6, -2621.1, 700, 5); //16 debris per level
+ spawn.debris(20823.6, -1332.1, 1300, 5); //16 debris per level
+ spawn.debris(21095.5, -423.4, 700, 5); //16 debris per level
+ spawn.debris(20534.5, -1282.1, 700, 5); //16 debris per level
+
+
+
+
+
+
+
+ spawn.randomSmallMob(1300, -70);
+ spawn.shieldingBoss(943.9, -1698.0)
+
+
+ //second ship base
+ spawn.mapRect(15000, 0, 515, 185);//lower floor 1
+ spawn.mapRect(17015, 0, 5500, 185);//lower floor 2
+ spawn.mapRect(15000, -2972, 185, 2972);//left wall
+ spawn.mapRect(15000, -2972, 7515, 185);//roof
+ spawn.mapRect(22330, -2972, 185, 2972);//right wall
+ spawn.mapRect(17002, -2972, 169, 2564);//left middle wall
+ spawn.mapRect(19089, -2972, 169, 855);//right middle wall upper
+ spawn.mapRect(19089, -1625, 169, 1800);//right middle wall lower
+ spawn.mapRect(20760, -2972, 169, 1350);//medium wall left of portal
+ spawn.mapRect(19720, -1625, 1725, 162);//right room upper floor
+ spawn.mapRect(21440, -2325, 169, 863);//medium wall right of portal
+ spawn.mapRect(19720, -855, 2725, 162);//right room lower floor
+
+ //engines //y -2972 -> 0
+ spawn.mapRect(22330, -2763.75, 400, 800);
+ spawn.mapRect(22330, -1793.5, 400, 800);
+ spawn.mapRect(22330, -804.25, 400, 800);
+
+
+
+ //second ship details
+ spawn.mapRect(19904, -1465, 85, 362);//upper L
+ spawn.mapRect(19542, -1191, 412, 88);//lower L
+ spawn.mapRect(18546, -2199, 600, 82);//2nd room enternce wall
+ spawn.mapRect(18546, -2499, 82, 2300);
+ spawn.mapRect(18108, -326, 500, 82);//walls/floors in middle room
+ spawn.mapRect(17750, -682, 300, 82);
+ spawn.mapRect(17156, -468, 500, 60);
+ spawn.mapRect(18022, -1082, 600, 82);
+ spawn.mapRect(17151, -1196, 500, 82);
+ spawn.mapRect(17453, -2060, 500, 82);
+ spawn.mapRect(18197, -2269, 400, 82);
+ spawn.mapRect(18108, -326, 500, 82);
+ spawn.mapRect(20542, -1191, 612, 88);
+ spawn.mapRect(20238, -1191, 88, 412);
+ spawn.mapRect(21520, -1468, 88, 412);
+ spawn.mapRect(20238, -330.2, 88, 412);
+ spawn.mapRect(20819, -328.3, 412, 88);
+ spawn.mapRect(21532, -708, 88, 412);
+ spawn.mapRect(15483.8, 12.5, 388, 30);//broken floor
+ spawn.mapRect(15487.6, 76.6, 488, 24);
+ spawn.mapRect(15506.5, 134.2, 288, 45);
+ spawn.mapVertex(16758.6, 135.3, "400 -30 -350 -40 -400 30 400 30");
+ spawn.mapVertex(16758.6, 55.3, "423 -30 -408 -20 -400 20 400 20");
+ //tank
+ spawn.mapRect(15310, -960, 600, 135);
+ spawn.mapRect(16290, -960, 800, 135);
+ //in tank
+ spawn.mapRect(16524.8, -2726.8, 40, 400);
+ spawn.mapRect(16524.8, -2130.9, 400, 40);
+ spawn.mapRect(16010.2, -2412.2, 300, 40);
+ spawn.mapRect(15379.2, -2055.1, 400, 40);
+
+ spawn.mapVertex(17626.3, -3035, "-245 0 -220 -110 -173 -173 -110 -220 0 -250 110 -220 173 -173 220 -110 245 0");
+ spawn.mapRect(17226.3, -3035, 400, 40);
+
+ spawn.mapVertex(17626.3, 225, "-245 0 -220 110 -173 173 -110 220 0 250 110 220 173 173 220 110 245 0");
+ spawn.mapRect(17226.3, 225, 400, 40);
+
+ spawn.mapVertex(19626.3, -3035, "-245 0 -220 -110 -173 -173 -110 -220 0 -250 110 -220 173 -173 220 -110 245 0");
+ spawn.mapRect(19226.3, -3035, 400, 40);
+
+ spawn.mapVertex(19626.3, 225, "-245 0 -220 110 -173 173 -110 220 0 250 110 220 173 173 220 110 245 0");
+ spawn.mapRect(19226.3, 225, 400, 40);
+
+ spawn.mapVertex(21626.3, -3035, "-245 0 -220 -110 -173 -173 -110 -220 0 -250 110 -220 173 -173 220 -110 245 0");
+ spawn.mapRect(21226.3, -3035, 400, 40);
+
+ spawn.mapVertex(21626.3, 225, "-245 0 -220 110 -173 173 -110 220 0 250 110 220 173 173 220 110 245 0");
+ spawn.mapRect(21226.3, 225, 400, 40);
+
+
+
+ //add fuel tanks in the last room
+
+
+ spawn.mapRect(21531.9, -707.8, 488, 8);
+
+ //22185.5, -114.8
+ spawn.mapVertex(22207.8, -103, "325 -200 100 -200 325 -300");
+ spawn.mapRect(22056.6, -70, 225, 212);
+
+ spawn.mapVertex(20723.1, -1734, "325 -200 100 -200 325 -300");
+ spawn.mapRect(20571.9, -1701.0, 225, 212);
+
+ spawn.mapVertex(22207.8, -103, "325 -200 100 -200 325 -300");
+ spawn.mapRect(22056.6, -70, 225, 212);
+ //spawn.mapVertex(x,y, "coordinates")
+ //the parts in quotes is "x y x y x y x y x y" x and y need to be the coordinates of points that define the shape in a concave clockwise direction
+
+ //second ship blocks/debris
+ spawn.bodyRect(21525, -113, 50, 50, 9);//first button block
+ spawn.bodyRect(18993, -2283, 50, 50, 9);//second button block
+ spawn.bodyRect(20303, -1736, 50, 50, 9);//third button block
+
+
+
+ // spawn.randomLevelBoss(17902, -1689, ["blinkBoss", "shooterBoss", "launcherBoss", "pulsarBoss", "blockBoss", "bladeBoss", "revolutionBoss", "spawnerBossCulture", "spiderBoss", "sneakBoss", "snakeSpitBoss"])
+ spawn.randomLevelBoss(17902, -1689, ["launcherBoss", "laserTargetingBoss", "blinkBoss", "streamBoss", "historyBoss", "grenadierBoss", "blockBoss", "revolutionBoss", "slashBoss"]);
+
+ // powerUps.spawnStartingPowerUps(1475, -1175);
+ // spawn.debris(750, -2200, 3700, 16); //16 debris per level
+ // spawn.bodyRect(1540, -1110, 300, 25, 0.9);
+ // spawn.randomSmallMob(1300, -70);
+ // spawn.randomMob(2650, -975, 0.8);
+ // spawn.randomGroup(1700, -900, 0.4);
+ // if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300);
+ // spawn.secondaryBossChance(100, -1500)
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ clock() {
+ simulation.makeTextLog(`
clock by
Cornbread 2100 `);
+
+ function drawBackgroundGear(x, y, r1, r2, rot, color, speed, numTeeth = 5, toothWidth = 75, linew = 2) {
+ var vertices = getGearVertices(x, y, r1, r2, numTeeth, simulation.cycle * speed + rot, toothWidth / 100);
+
+ // draw gear
+ ctx.beginPath();
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (var i = 1; i < vertices.length; i++) {
+ ctx.lineTo(vertices[i].x, vertices[i].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 2;
+ ctx.fillStyle = color;
+ ctx.fill();
+ ctx.strokeStyle = "#3a3f20";
+ ctx.lineWidth = linew;
+ ctx.stroke();
+ }
+
+ function drawFallingBackgroundGear(x, y, r1, r2, rot, color, speed, fallSpeed, startCycle, numTeeth = 5, linew = 2) {
+ rot *= speed;
+ numTeeth *= 2;
+
+ const gearInc = (2 * Math.PI) / numTeeth;
+ ctx.beginPath()
+ for (var i = 0; i <= numTeeth; i++) {
+ var gear_r = r2;
+ if (i % 2 == 1) gear_r = r1;
+ ctx.arc(x, y + (simulation.cycle - startCycle) * fallSpeed, gear_r, (i * gearInc) + rot, ((i + 1) * gearInc) + rot);
+ }
+ ctx.fillStyle = color;
+ ctx.fill();
+ ctx.strokeStyle = "#3a3f20";
+ ctx.lineWidth = linew;
+ ctx.stroke();
+ }
+
+ function getGearVertices(x, y, r1, r2, numTeeth, rot = 0, teethWidth = 0) {
+ if (teethWidth == 0) {
+ teethWidth = (2 * Math.PI) / (2 * numTeeth);
+ }
+ const gearInc = (2 * Math.PI) / numTeeth;
+ var vertices = [];
+
+ for (var i = 0; i < numTeeth; i++) {
+ //inner vertices of gear teeth
+ var distance = i * gearInc + rot;
+ var vX = Math.sin(distance + teethWidth / 2) * r1;
+ var vY = Math.cos(distance + teethWidth / 2) * r1;
+
+ var point1 = { x: vX, y: vY, point: 1 };
+
+ vX = Math.sin(distance - teethWidth / 2) * r1;
+ vY = Math.cos(distance - teethWidth / 2) * r1;
+
+ var point4 = { x: vX, y: vY, point: 4 };
+
+ vX = Math.sin(distance) * r1;
+ vY = Math.cos(distance) * r1;
+
+ if (vX == 0) {
+ vX = 0.0001
+ }
+
+ var slope = vY / vX;
+
+ var angle = Math.atan2(vY, vX);
+
+ //outer vertices of gear teeth
+ var point2 = { x: point1.x, y: point1.y, point: 2 };
+ point2.x += Math.cos(angle) * (r2 - r1);
+ point2.y += Math.sin(angle) * (r2 - r1);
+
+ var point3 = { x: point4.x, y: point4.y, point: 3 };
+ point3.x += Math.cos(angle) * (r2 - r1);
+ point3.y += Math.sin(angle) * (r2 - r1);
+
+ vertices.push(point4);
+ vertices.push(point3);
+ vertices.push(point2);
+ vertices.push(point1);
+ }
+
+ for (var i = 0; i < vertices.length; i++) {
+ vertices[i].x += x;
+ vertices[i].y += y;
+ }
+
+ return vertices;
+ }
+
+ function getGearTeethVertices(x, y, r1, r2, numTeeth, toothIndex, teethWidth = 0) {
+ if (teethWidth == 0) {
+ teethWidth = (2 * Math.PI) / (2 * numTeeth);
+ }
+
+ const gearInc = (2 * Math.PI) / numTeeth;
+ var vertices = [];
+
+ for (var i = 0; i < numTeeth; i++) {
+ //inner vertices of gear teeth
+ var distance = i * gearInc;
+ var vX = Math.sin(distance + teethWidth / 2) * r1;
+ var vY = Math.cos(distance + teethWidth / 2) * r1;
+
+ var point1 = { x: vX, y: vY, point: 1 };
+
+ vX = Math.sin(distance - teethWidth / 2) * r1;
+ vY = Math.cos(distance - teethWidth / 2) * r1;
+
+ var point4 = { x: vX, y: vY, point: 4 };
+
+ vX = Math.sin(distance) * r1;
+ vY = Math.cos(distance) * r1;
+
+ if (vX == 0) {
+ vX = 0.0001
+ }
+
+ var slope = vY / vX;
+
+ var angle = Math.atan2(vY, vX);
+
+ //outer vertices of gear teeth
+ var point2 = { x: point1.x, y: point1.y, point: 2 };
+ point2.x += Math.cos(angle) * (r2 - r1);
+ point2.y += Math.sin(angle) * (r2 - r1);
+
+ var point3 = { x: point4.x, y: point4.y, point: 3 };
+ point3.x += Math.cos(angle) * (r2 - r1);
+ point3.y += Math.sin(angle) * (r2 - r1);
+
+ if (i == toothIndex) {
+ vertices.push(point4);
+ vertices.push(point3);
+ vertices.push(point2);
+ vertices.push(point1);
+ }
+ }
+
+ for (var i = 0; i < vertices.length; i++) {
+ vertices[i].x += x;
+ vertices[i].y += y;
+ }
+
+ return vertices;
+ }
+
+ function mapGear(x, y, r1, r2, rot, speed, numTeeth = 5, toothWidth = 50, additionalCircleRadius = 10) {
+ const part1 = body[body.length] = Bodies.polygon(x, y, 0, r1 + additionalCircleRadius, {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ isNotHoldable: true,
+ frictionAir: 0,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0
+ });
+
+ var parts = [part1];
+
+ for (var i = 0; i < numTeeth; i++) {
+ var toothVertices = getGearTeethVertices(0, 0, r2 - r1, toothWidth + r2 - r1, numTeeth, i, 70); // for some reason the teeth are sideways
+
+ var center = { // the center of the inner line of the gear
+ x: toothVertices[3].x - toothVertices[0].x,
+ y: toothVertices[3].y - toothVertices[0].y
+ };
+
+ distanceToCenter = Math.sqrt((center.x ** 2) + (center.y ** 2));
+
+ var radiusScale = (r1 + ((r2 - r1) / 2)) / distanceToCenter;
+
+ gearToothSlope = center.y / center.x;
+
+ var newPart = body[body.length] = Bodies.fromVertices(x + center.x * radiusScale, y + center.y * radiusScale, toothVertices, {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ isNotHoldable: true,
+ frictionAir: 0.01,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0
+ });
+
+ parts.push(newPart);
+ }
+
+ const who = Body.create({
+ parts: parts
+ });
+
+ Composite.add(engine.world, who);
+ composite[composite.length] = who;
+ who.collisionFilter.category = cat.body;
+ who.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map
+
+ const constraint = Constraint.create({
+ pointA: {
+ x: x,
+ y: y
+ },
+ bodyB: who,
+ stiffness: 1,
+ damping: 1
+ });
+
+
+ Matter.Body.setDensity(who, 0.0001)
+ Composite.add(engine.world, constraint);
+ Matter.Body.setAngle(who, 0)
+ Matter.Body.setAngularVelocity(who, 0);
+ who.center = { x: x, y: y }
+
+ who.rotate = function () {
+ var rotation = simulation.cycle * speed + rot;
+ Matter.Body.setAngle(who, rotation);
+ }
+
+ who.gearSettings = {
+ x: x,
+ y: y,
+ r1: r1,
+ r2: r2,
+ rot: rot,
+ speed: speed,
+ numTeeth: numTeeth,
+ toothWidth: toothWidth
+ }
+
+ return who;
+ }
+
+ function clockHand(x, y, width, height, speed = 15 * Math.PI / 180, angle = 0, density = 0.001) {
+ var who1 = body[body.length] = Bodies.rectangle(x, y + height / 2, width, height, {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ isNotHoldable: true,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0
+ });
+
+ const who = Body.create({
+ parts: [who1],
+ handRotation: 0
+ });
+
+ Composite.add(engine.world, who);
+ composite[composite.length] = who;
+ who.collisionFilter.category = cat.body;
+ who.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map
+
+ who.position.y = y;
+
+ const constraint = Constraint.create({
+ pointA: {
+ x: who.position.x,
+ y: who.position.y
+ },
+ bodyB: who,
+ stiffness: 1,
+ damping: 1
+ });
+
+ Matter.Body.setDensity(who, density)
+ Composite.add(engine.world, constraint);
+ who.center = { x: who.position.x, y: who.position.y }
+
+ who.rotate = function () {
+ if (simulation.cycle % 60 == 0) {
+ who.handRotation += speed;
+ if (Math.abs(who.handRotation % (Math.PI * 2) - Math.PI) < 0.2) {
+ // spawn random mob at exit door
+ const pick = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)];
+ spawn[pick](300, 600);
+ }
+ if (Matter.Query.collides(player, [this]).length != 0) {
+ var playerAngle = Math.atan((m.pos.y - y) / (m.pos.x - x));
+ if (m.pos.x - x < 0) playerAngle += Math.PI;
+ const playerDistance = Math.sqrt((m.pos.x - x) ** 2 + (m.pos.y - y) ** 2);
+ Matter.Body.setPosition(player, {
+ x: x + Math.cos(playerAngle + speed) * playerDistance,
+ y: y + Math.sin(playerAngle + speed) * playerDistance
+ })
+ }
+ }
+ Matter.Body.setAngle(who, who.handRotation + angle);
+ }
+
+ return who
+ }
+
+ function pendulum(x, y, width, height, swingTime = 50, swingDistanceMultiplier = 0.5, bobSides = 0, bobRadius = 200, density = 100, angle = 0, frictionAir = 0, angularVelocity = 0) {
+ const who1 = body[body.length] = Bodies.rectangle(x, y + height / 2, width, height, {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ isNotHoldable: true,
+ frictionAir: frictionAir,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0
+ });
+
+ const who2 = body[body.length] = Bodies.polygon(x, y + height, bobSides, bobRadius, {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ isNotHoldable: true,
+ frictionAir: 0.01,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0
+ });
+
+ const who = Body.create({
+ parts: [who1, who2],
+ });
+
+ Composite.add(engine.world, who);
+ composite[composite.length] = who;
+ who.collisionFilter.category = cat.body;
+ who.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map
+
+ who.position.y = y;
+
+ const constraint = Constraint.create({
+ pointA: {
+ x: x,
+ y: y
+ },
+ bodyB: who,
+ stiffness: 1,
+ damping: 1
+ });
+
+
+ Matter.Body.setDensity(who, density)
+ Composite.add(engine.world, constraint);
+ Matter.Body.setAngle(who, angle)
+ Matter.Body.setAngularVelocity(who, angularVelocity);
+ who.center = { x: x, y: y + height / 2 }
+
+ who.rotate = function () {
+ var rotation = Math.sin(simulation.cycle / swingTime) * swingDistanceMultiplier;
+
+ if (Matter.Query.collides(player, [this]).length != 0) {
+ var playerAngle = Math.atan((player.position.y - y) / (player.position.x - x)) + rotation - Math.sin((simulation.cycle - 1) / swingTime) * swingDistanceMultiplier;
+ if (player.position.x - x < 0) playerAngle += Math.PI;
+ const playerDistance = Math.sqrt((player.position.x - x) ** 2 + (player.position.y - y) ** 2);
+ Matter.Body.setPosition(player, {
+ x: x + Math.cos(playerAngle) * playerDistance,
+ y: y + Math.sin(playerAngle) * playerDistance
+ })
+ }
+
+ Matter.Body.setAngle(who, rotation);
+ }
+
+ return who;
+ }
+
+ function gearMob(x, y, leaveBody = true, autoFindPlayer = false, radius = Math.floor(25 + 40 * Math.random()), teethRadius = 0) {
+ if (teethRadius == 0) {
+ teethRadius = radius + 15 + Math.floor(Math.random() * 20);
+ }
+
+ mobs.spawn(x, y, 0, teethRadius, "transparent");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+
+ me.delay = 100 + 40 * simulation.CDScale;
+ me.accelMag = Math.PI / 10000;
+ me.memory = 120;
+ me.seeAtDistance2 = 2000000; // 140
+ Matter.Body.setDensity(me, 0.001);
+
+ me.leaveBody = leaveBody;
+
+ const numTeeth = Math.round(5 + Math.random() * 3);
+
+ me.gearRotation = 0;
+ me.gearSpeed = Math.round(-0.1 + Math.random() * 0.2);
+ me.gearAccelerating = true;
+
+ me.do = function () {
+ if (autoFindPlayer) {
+ me.locatePlayer();
+ }
+
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ this.attraction();
+
+ if (me.gearAccelerating && (Math.random() > 0.99 || me.gearSpeed >= 0.1)) {
+ me.gearAccelerating = false;
+ } else if (!me.gearAccelerating && (Math.random() > 0.99 || me.gearSpeed <= -0.1)) {
+ me.gearAccelerating = true;
+ }
+
+ if (me.gearAccelerating) {
+ me.gearSpeed += 0.001;
+ } else {
+ me.gearSpeed -= 0.001;
+ }
+
+ me.gearRotation += me.gearSpeed;
+
+ var newVertices = getGearVertices(me.position.x, me.position.y, radius, teethRadius, numTeeth, me.gearRotation);
+ // draw body
+ ctx.beginPath();
+ ctx.moveTo(newVertices[0].x, newVertices[0].y);
+ for (let i = 1; i < newVertices.length; i++) {
+ ctx.lineTo(newVertices[i].x, newVertices[i].y);
+ }
+ ctx.lineTo(newVertices[0].x, newVertices[0].y);
+ ctx.fillStyle = "#7b3f00";
+ ctx.fill();
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ }
+ }
+
+ function customDoor(x, y, width, height) {
+ x = x + width / 2
+ y = y + height / 2
+ const doorBlock = body[body.length] = Bodies.rectangle(x, y, width, height, {
+ collisionFilter: {
+ category: cat.map,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ inertia: Infinity, //prevents rotation
+ isNotHoldable: true,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0,
+ isClosing: false,
+ setPos(x, y) {
+ if (y - this.position.y <= 0 || ( // only move down if clear of stuff
+ Matter.Query.ray([player], Matter.Vector.create(this.position.x - width / 2, this.position.y + height / 2), Matter.Vector.create(this.position.x + width / 2, this.position.y + height / 2), 5).length === 0 &&
+ Matter.Query.ray(body, Matter.Vector.create(this.position.x - width / 2, this.position.y + height / 2), Matter.Vector.create(this.position.x + width / 2, this.position.y + height / 2), 5).length <= 1 &&
+ Matter.Query.ray(mob, Matter.Vector.create(this.position.x - width / 2, this.position.y + height / 2), Matter.Vector.create(this.position.x + width / 2, this.position.y + height / 2), 5).length === 0)
+ ) {
+ const position = {
+ x: x,
+ y: y
+ }
+ Matter.Body.setPosition(this, position);
+ }
+ },
+ draw() {
+ ctx.fillStyle = "#555"
+ ctx.beginPath();
+ const v = this.vertices;
+ ctx.moveTo(v[0].x, v[0].y);
+ for (let i = 1; i < v.length; ++i) {
+ ctx.lineTo(v[i].x, v[i].y);
+ }
+ ctx.lineTo(v[0].x, v[0].y);
+ ctx.fill();
+ }
+ });
+ Matter.Body.setStatic(doorBlock, true); //make static
+ Composite.add(engine.world, doorBlock); //add to world
+ doorBlock.classType = "body"
+ return doorBlock
+ }
+
+ function horizontalDoor(x, y, width, height, distance, speed = 1) {
+ x = x + width / 2
+ y = y + height / 2
+ const doorBlock = body[body.length] = Bodies.rectangle(x, y, width, height, {
+ collisionFilter: {
+ category: cat.map,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ inertia: Infinity, //prevents rotation
+ isNotHoldable: true,
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0,
+ isClosing: false,
+ openClose() {
+ if (!m.isBodiesAsleep) {
+ if (this.isClosing) {
+ if (this.position.x > x) { //try to close
+ if ( //if clear of stuff
+ Matter.Query.collides(this, [player]).length === 0 &&
+ Matter.Query.collides(this, body).length < 2 &&
+ Matter.Query.collides(this, mob).length === 0
+ ) {
+ const position = {
+ x: this.position.x - speed,
+ y: this.position.y
+ }
+ Matter.Body.setPosition(this, position)
+ }
+ }
+ } else {
+ if (this.position.x < x + distance) { //try to open
+ const position = {
+ x: this.position.x + speed,
+ y: this.position.y
+ }
+ Matter.Body.setPosition(this, position)
+ }
+ }
+ }
+ },
+ isClosed() {
+ return this.position.x < x + 1
+ },
+ draw() {
+ ctx.fillStyle = "#555"
+ ctx.beginPath();
+ const v = this.vertices;
+ ctx.moveTo(v[0].x, v[0].y);
+ for (let i = 1; i < v.length; ++i) {
+ ctx.lineTo(v[i].x, v[i].y);
+ }
+ ctx.lineTo(v[0].x, v[0].y);
+ ctx.fill();
+ }
+ });
+ Matter.Body.setStatic(doorBlock, true); //make static
+ Composite.add(engine.world, doorBlock); //add to world
+ doorBlock.classType = "body"
+ return doorBlock
+ }
+
+ function drawBelt(circle1, circle2) {
+ // circle 1
+ const distance = Math.sqrt((circle2.x - circle1.x) ** 2 + (circle2.y - circle1.y) ** 2);
+ const distanceToIntersection = (-circle1.radius * distance) / (-circle1.radius + circle2.radius);
+ const slopeAngle = Math.atan((circle2.y - circle1.y) / (circle2.x - circle1.x));
+ const angleToTangent = Math.acos(-circle1.radius / distanceToIntersection);
+ const tangentIntersection = {
+ x: Math.cos(slopeAngle) * distanceToIntersection + circle1.x,
+ y: Math.sin(slopeAngle) * distanceToIntersection + circle1.y
+ }
+ const tangentPoint = {
+ x: Math.cos(angleToTangent + slopeAngle) * -circle1.radius + circle1.x,
+ y: Math.sin(angleToTangent + slopeAngle) * -circle1.radius + circle1.y
+ }
+ const invertedTangentPoint = {
+ x: Math.cos(-angleToTangent + slopeAngle) * -circle1.radius + circle1.x,
+ y: Math.sin(-angleToTangent + slopeAngle) * -circle1.radius + circle1.y
+ }
+
+ // circle 2
+ const tangentPoint2 = {
+ x: Math.cos(angleToTangent + slopeAngle) * -circle2.radius + circle2.x,
+ y: Math.sin(angleToTangent + slopeAngle) * -circle2.radius + circle2.y
+ }
+ const invertedTangentPoint2 = {
+ x: Math.cos(-angleToTangent + slopeAngle) * -circle2.radius + circle2.x,
+ y: Math.sin(-angleToTangent + slopeAngle) * -circle2.radius + circle2.y
+ }
+
+ // draw
+ ctx.beginPath();
+ ctx.moveTo(tangentPoint.x, tangentPoint.y);
+ ctx.lineTo(tangentPoint2.x, tangentPoint2.y);
+ const newAngle = Math.atan((tangentPoint2.y - circle2.y) / (tangentPoint2.x - circle2.x));
+ const newAngle2 = Math.atan((invertedTangentPoint2.y - circle2.y) / (invertedTangentPoint2.x - circle2.x));
+ ctx.arc(circle2.x, circle2.y, circle2.radius, newAngle, newAngle2 + Math.PI);
+ ctx.lineTo(invertedTangentPoint.x, invertedTangentPoint.y);
+ const newAngle3 = Math.atan((invertedTangentPoint.y - circle1.y) / (invertedTangentPoint.x - circle1.x));
+ const newAngle4 = Math.atan((tangentPoint.y - circle1.y) / (tangentPoint.x - circle1.x));
+ ctx.arc(circle1.x, circle1.y, circle1.radius, newAngle3 + Math.PI, newAngle4);
+ ctx.strokeStyle = '#000';
+ ctx.lineWidth = 5;
+ ctx.stroke();
+ }
+
+ function drawDiagonalBelt(circle1, circle2) {
+ // circle 1
+ const distance = Math.sqrt((circle2.x - circle1.x) ** 2 + (circle2.y - circle1.y) ** 2);
+ const distanceToIntersection = (circle1.radius * distance) / (circle1.radius + circle2.radius);
+ const slopeAngle = Math.atan((circle2.y - circle1.y) / (circle2.x - circle1.x));
+ const angleToTangent = Math.acos(circle1.radius / distanceToIntersection);
+ const tangentIntersection = {
+ x: Math.cos(slopeAngle) * distanceToIntersection + circle1.x,
+ y: Math.sin(slopeAngle) * distanceToIntersection + circle1.y
+ }
+ const tangentPoint = {
+ x: Math.cos(angleToTangent + slopeAngle) * circle1.radius + circle1.x,
+ y: Math.sin(angleToTangent + slopeAngle) * circle1.radius + circle1.y
+ }
+ const invertedTangentPoint = {
+ x: Math.cos(-angleToTangent + slopeAngle) * circle1.radius + circle1.x,
+ y: Math.sin(-angleToTangent + slopeAngle) * circle1.radius + circle1.y
+ }
+
+ // circle 2
+ const tangentPoint2 = {
+ x: Math.cos(angleToTangent + slopeAngle) * -circle2.radius + circle2.x,
+ y: Math.sin(angleToTangent + slopeAngle) * -circle2.radius + circle2.y
+ }
+ const invertedTangentPoint2 = {
+ x: Math.cos(-angleToTangent + slopeAngle) * -circle2.radius + circle2.x,
+ y: Math.sin(-angleToTangent + slopeAngle) * -circle2.radius + circle2.y
+ }
+
+ // draw
+ ctx.beginPath();
+ ctx.moveTo(tangentPoint.x, tangentPoint.y);
+ ctx.lineTo(tangentPoint2.x, tangentPoint2.y);
+ const newAngle = Math.atan((tangentPoint2.y - circle2.y) / (tangentPoint2.x - circle2.x));
+ const newAngle2 = Math.atan((invertedTangentPoint2.y - circle2.y) / (invertedTangentPoint2.x - circle2.x));
+ ctx.arc(circle2.x, circle2.y, circle2.radius, newAngle, newAngle2 + Math.PI);
+ ctx.lineTo(invertedTangentPoint.x, invertedTangentPoint.y);
+ const newAngle3 = Math.atan((invertedTangentPoint.y - circle1.y) / (invertedTangentPoint.x - circle1.x));
+ const newAngle4 = Math.atan((tangentPoint.y - circle1.y) / (tangentPoint.x - circle1.x));
+ ctx.arc(circle1.x, circle1.y, circle1.radius, newAngle3, newAngle4 + Math.PI, true);
+ ctx.strokeStyle = '#000';
+ ctx.lineWidth = 5;
+ ctx.stroke();
+ }
+
+ function getIntersection(v1, v1End, domain) {
+ const intersections = getIntersections(v1, v1End, domain);
+
+ var best = {
+ x: v1End.x,
+ y: v1End.y,
+ dist: Math.sqrt((v1End.x - v1.x) ** 2 + (v1End.y - v1.y) ** 2)
+ }
+ for (const intersection of intersections) {
+ const dist = Math.sqrt((intersection.x - v1.x) ** 2 + (intersection.y - v1.y) ** 2);
+ if (dist < best.dist) {
+ best = {
+ x: intersection.x,
+ y: intersection.y,
+ dist: dist
+ };
+ }
+ }
+
+ return best;
+ }
+
+ function getIntersections(v1, v1End, domain) {
+ const intersections = [];
+
+ for (const obj of domain) {
+ for (var i = 0; i < obj.vertices.length - 1; i++) {
+ results = simulation.checkLineIntersection(v1, v1End, obj.vertices[i], obj.vertices[i + 1]);
+ if (results.onLine1 && results.onLine2) intersections.push({ x: results.x, y: results.y });
+ }
+ results = simulation.checkLineIntersection(v1, v1End, obj.vertices[obj.vertices.length - 1], obj.vertices[0]);
+ if (results.onLine1 && results.onLine2) intersections.push({ x: results.x, y: results.y });
+ }
+
+ return intersections;
+ }
+
+ function circleLoS(pos, radius, domain) {
+
+ function allCircleLineCollisions(c, radius, domain) {
+ var lines = [];
+ for (const obj of domain) {
+ //const obj = domain[0]
+ for (var i = 0; i < obj.vertices.length - 1; i++) {
+ lines.push(circleLineCollisions(obj.vertices[i], obj.vertices[i + 1], c, radius));
+ }
+ lines.push(circleLineCollisions(obj.vertices[obj.vertices.length - 1], obj.vertices[0], c, radius));
+ }
+
+ const collisionLines = [];
+ for (const line of lines) {
+ if (line.length == 2) {
+ const distance1 = Math.sqrt((line[0].x - c.x) ** 2 + (line[0].y - c.y) ** 2)
+ const angle1 = Math.atan2(line[0].y - c.y, line[0].x - c.x);
+ const queryPoint1 = {
+ x: Math.cos(angle1) * (distance1 - 1) + c.x,
+ y: Math.sin(angle1) * (distance1 - 1) + c.y
+ }
+ const distance2 = Math.sqrt((line[1].x - c.x) ** 2 + (line[1].y - c.y) ** 2)
+ const angle2 = Math.atan2(line[1].y - c.y, line[1].x - c.x);
+ const queryPoint2 = {
+ x: Math.cos(angle2) * (distance2 - 1) + c.x,
+ y: Math.sin(angle2) * (distance2 - 1) + c.y
+ }
+
+ collisionLines.push(line)
+ }
+ }
+
+ return collisionLines;
+ }
+
+ function circleLineCollisions(a, b, c, radius) {
+ // calculate distances
+ const angleOffset = Math.atan2(b.y - a.y, b.x - a.x);
+ const sideB = Math.sqrt((a.x - c.x) ** 2 + (a.y - c.y) ** 2);
+ const sideC = Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2);
+ const sideA = Math.sqrt((c.x - b.x) ** 2 + (c.y - b.y) ** 2);
+
+ // calculate the closest point on line AB to point C
+ const angleA = Math.acos((sideB ** 2 + sideC ** 2 - sideA ** 2) / (2 * sideB * sideC)) * (a.x - c.x) / -Math.abs(a.x - c.x)
+ const sideAD = Math.cos(angleA) * sideB;
+ const d = { // closest point
+ x: Math.cos(angleOffset) * sideAD + a.x,
+ y: Math.sin(angleOffset) * sideAD + a.y
+ }
+ const distance = Math.sqrt((d.x - c.x) ** 2 + (d.y - c.y) ** 2);
+ if (distance == radius) {
+ // tangent
+ return [d];
+ } else if (distance < radius) {
+ // secant
+ const angleOffset = Math.atan2(d.y - c.y, d.x - c.x);
+ const innerAngle = Math.acos(distance / radius);
+ const intersection1 = {
+ x: Math.cos(angleOffset + innerAngle) * radius + c.x,
+ y: Math.sin(angleOffset + innerAngle) * radius + c.y
+ }
+
+ const intersection2 = {
+ x: Math.cos(angleOffset - innerAngle) * radius + c.x,
+ y: Math.sin(angleOffset - innerAngle) * radius + c.y
+ }
+
+ const distance1 = {
+ a: Math.sqrt((intersection1.x - a.x) ** 2 + (intersection1.y - a.y) ** 2),
+ b: Math.sqrt((intersection1.x - b.x) ** 2 + (intersection1.y - b.y) ** 2)
+ }
+ const distance2 = {
+ a: Math.sqrt((intersection2.x - a.x) ** 2 + (intersection2.y - a.y) ** 2),
+ b: Math.sqrt((intersection2.x - b.x) ** 2 + (intersection2.y - b.y) ** 2)
+ }
+ const result = [];
+ if (Math.abs(sideC - (distance1.a + distance1.b)) < 0.01) {
+ result.push(intersection1);
+ } else {
+ if (distance1.a < distance1.b) {
+ if (sideB <= radius) result.push(a);
+ } else {
+ if (sideA <= radius) result.push(b)
+ }
+ }
+ if (Math.abs(sideC - (distance2.a + distance2.b)) < 0.01) {
+ result.push(intersection2);
+ } else {
+ if (distance2.a <= distance2.b) {
+ if (sideB <= radius) result.push(a);
+ } else {
+ if (sideA <= radius) result.push(b)
+ }
+ }
+
+ return result;
+ } else {
+ // no intersection
+ return [];
+ }
+ }
+
+ var vertices = [];
+ for (const obj of losDomain) {
+ for (var i = 0; i < obj.vertices.length; i++) {
+ const vertex = obj.vertices[i];
+ const angleToVertex = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ const queryPoint = {
+ x: Math.cos(angleToVertex + Math.PI) + vertex.x,
+ y: Math.sin(angleToVertex + Math.PI) + vertex.y
+ }
+
+ if (Matter.Query.ray(domain, pos, queryPoint).length == 0) {
+ var distance = Math.sqrt((vertex.x - pos.x) ** 2 + (vertex.y - pos.y) ** 2);
+ var endPoint = {
+ x: vertex.x,
+ y: vertex.y
+ }
+
+ if (distance > radius) {
+ const angle = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ endPoint = {
+ x: Math.cos(angle) * radius + pos.x,
+ y: Math.sin(angle) * radius + pos.y
+ }
+
+ distance = radius
+ }
+
+ var best = getIntersection(pos, endPoint, domain);
+
+ if (best.dist >= distance) {
+ best = {
+ x: endPoint.x,
+ y: endPoint.y,
+ dist: distance
+ }
+ }
+ vertices.push(best)
+
+
+ var angle = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ endPoint = {
+ x: Math.cos(angle + 0.001) * radius + pos.x,
+ y: Math.sin(angle + 0.001) * radius + pos.y
+ }
+
+ best = getIntersection(pos, endPoint, domain);
+
+ if (best.dist >= radius) {
+ best = {
+ x: endPoint.x,
+ y: endPoint.y,
+ dist: radius
+ }
+ }
+ vertices.push(best)
+
+
+ angle = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ endPoint = {
+ x: Math.cos(angle - 0.001) * radius + pos.x,
+ y: Math.sin(angle - 0.001) * radius + pos.y
+ }
+
+ best = getIntersection(pos, endPoint, domain);
+
+ if (best.dist >= radius) {
+ best = {
+ x: endPoint.x,
+ y: endPoint.y,
+ dist: radius
+ }
+ }
+ vertices.push(best)
+ }
+ }
+ }
+
+ const outerCollisions = allCircleLineCollisions(pos, radius, domain);
+ const circleCollisions = [];
+ for (const line of outerCollisions) {
+ for (const vertex of line) {
+ const distance = Math.sqrt((vertex.x - pos.x) ** 2 + (vertex.y - pos.y) ** 2)
+ const angle = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ const queryPoint = {
+ x: Math.cos(angle) * (distance - 1) + pos.x,
+ y: Math.sin(angle) * (distance - 1) + pos.y
+ }
+ if (Math.abs(distance - radius) < 1 && Matter.Query.ray(domain, pos, queryPoint).length == 0) circleCollisions.push(vertex)
+ }
+ }
+
+ for (var i = 0; i < circleCollisions.length; i++) {
+ const vertex = circleCollisions[i];
+ var nextIndex = i + 1;
+ if (nextIndex == circleCollisions.length) nextIndex = 0;
+ const nextVertex = circleCollisions[nextIndex];
+ const angle1 = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ const angle2 = Math.atan2(nextVertex.y - pos.y, nextVertex.x - pos.x);
+ var newAngle;
+ if (Math.abs(angle1) > Math.PI / 2 && Math.abs(angle2) > Math.PI / 2 && angle1 / Math.abs(angle1) != angle2 / Math.abs(angle2)) {
+ // if the arc between the to points crosses over the left side (+/- pi radians)
+ const newAngle1 = (Math.PI - Math.abs(angle1)) * (angle1 / Math.abs(angle1));
+ const newAngle2 = (Math.PI - Math.abs(angle2)) * (angle2 / Math.abs(angle2));
+ newAngle = (newAngle1 + newAngle2) / 2;
+ var multiplier;
+ if (newAngle == 0) {
+ multiplier = 1;
+ } else {
+ multiplier = newAngle / Math.abs(newAngle);
+ }
+ newAngle = Math.PI * multiplier - newAngle * multiplier;
+ test = true;
+ } else {
+ newAngle = (angle1 + angle2) / 2;
+ }
+
+ // shoot ray between them
+ var endPoint = {
+ x: Math.cos(newAngle) * radius + pos.x,
+ y: Math.sin(newAngle) * radius + pos.y
+ }
+
+ var best = getIntersection(pos, endPoint, domain);
+
+ vertices.push(vertex);
+
+ if (best.dist <= radius) vertices.push({ x: best.x, y: best.y })
+ }
+
+ vertices.sort((a, b) => Math.atan2(a.y - pos.y, a.x - pos.x) - Math.atan2(b.y - pos.y, b.x - pos.x));
+ return vertices;
+ }
+
+ function compareArrays(array1, array2) {
+ for (var i = 0; i < array1.length; i++) {
+ if (array1[i] != array2[i]) return false;
+ }
+
+ return true;
+ }
+
+ function generateIntersectMap() {
+ // include intersections in map elements to avoid LoS issues with overlapping
+ const intersectMap = [];
+ for (var i = 0; i < map.length; i++) {
+ const obj = map[i];
+ const newVertices = [];
+ const restOfMap = [...map].slice(0, i).concat([...map].slice(i + 1))
+ for (var j = 0; j < obj.vertices.length - 1; j++) {
+ var intersections = getIntersections(obj.vertices[j], obj.vertices[j + 1], restOfMap);
+ newVertices.push(obj.vertices[j]);
+ for (const vertex of intersections) {
+ newVertices.push({ x: vertex.x, y: vertex.y });
+ }
+ }
+ intersections = getIntersections(obj.vertices[obj.vertices.length - 1], obj.vertices[0], restOfMap);
+ newVertices.push(obj.vertices[obj.vertices.length - 1]);
+ for (const vertex of intersections) {
+ newVertices.push({ x: vertex.x, y: vertex.y });
+ }
+
+ intersectMap.push({ vertices: newVertices });
+ }
+
+ return intersectMap;
+ }
+
+ function addPartToMap(len) { // from "run" map
+ map[len].collisionFilter.category = cat.map;
+ map[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(map[len], true);
+ Composite.add(engine.world, map[len]);
+ }
+
+ level.setPosToSpawn(-500, -50);
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.x = 250;
+ level.exit.y = 720;
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20);
+ level.defaultZoom = 1800;
+ simulation.zoomTransition(level.defaultZoom);
+ document.body.style.backgroundColor = "#d8dadf";
+
+ spawn.mapRect(-925, 0, 2650, 100);
+
+ spawn.mapRect(-925, -1700, 325, 1800);
+ spawn.mapRect(-650, -325, 325, 50);
+ spawn.mapRect(-650, -1400, 325, 50);
+ spawn.mapRect(-1700, -1700, 1100, 200);
+ spawn.mapRect(-1700, -4600, 300, 3100);
+ spawn.mapRect(-1700, -4600, 1250, 200);
+ spawn.mapRect(200, -4600, 2750, 200);
+ spawn.mapRect(-400, -4225, 200, 50);
+ spawn.mapRect(2800, -4600, 150, 1400);
+
+ spawn.mapRect(1350, -325, 100, 50);
+ spawn.mapRect(1400, -1500, 325, 1600);
+ spawn.mapRect(1400, -1500, 1550, 50);
+ spawn.mapRect(1400, -1900, 900, 50);
+ spawn.mapRect(1400, -2900, 100, 1050);
+
+ spawn.mapRect(-600, -2900, 3550, 100);
+ spawn.mapRect(2850, -2900, 100, 700);
+ spawn.mapRect(2850, -2200, 100, 350);
+ map[map.length - 1].fallsOff2 = true; // this piece will fall off in the middle of cutscene
+
+ spawn.mapRect(2300, -1900, 500, 50);
+ map[map.length - 1].fallsOff = true; // this piece wall fall off at the start of cutscene
+
+ spawn.mapRect(2800, -1900, 200, 50);
+ spawn.mapRect(2900, -1900, 50, 450);
+ powerUps.directSpawn(2700, -1675, "tech");
+
+ spawn.mapRect(2800, -3300, 825, 100);
+ spawn.mapRect(3525, -3300, 100, 3000);
+ spawn.mapRect(3400, -2850, 225, 50);
+ spawn.mapRect(2875, -2525, 175, 25);
+ spawn.mapRect(3325, -2675, 150, 25);
+ spawn.mapRect(3400, -2850, 75, 200);
+ spawn.mapRect(3150, -2225, 100, 25);
+
+ spawn.mapRect(-2300, 750, 5450, 100);
+
+ pendulum1 = pendulum(400, -2500, 75, 1700, 50, 0.3, 0, 300);
+ const gear1 = mapGear(-1200, -2000, 100, 200, 0, -0.05, 5, 75);
+ const gear2 = mapGear(-700, -2500, 150, 270, -0.5, 0.05, 5, 50);
+ const gear3 = mapGear(-3500, -1000, 1100, 1500, -0.5, 0.005, 10, 150, 40);
+ const piston1 = customDoor(1650, -1850, 100, 350); // x, y, width, height, distance, speed = 1
+ const piston2 = customDoor(1950, -1850, 100, 350);
+ const piston3 = horizontalDoor(-2000, -4200, 300, 100, 300, 20);
+ const piston4 = horizontalDoor(-2000, -3800, 300, 100, 300, 20);
+ const piston5 = horizontalDoor(-2000, -3400, 300, 100, 300, 20);
+ const piston6 = horizontalDoor(-2000, -3000, 300, 100, 300, 20);
+ const piston7 = horizontalDoor(-2000, -2600, 300, 100, 300, 20);
+ const hand1 = clockHand(400, -3700, 75, 600);
+ const elevator1 = level.elevator(3200, 0, 150, 50, -1750, 0.0025, { up: 0.05, down: 0.2 });
+
+ spawn.debris(-300, 0, 1300, 6);
+ spawn.debris(0, -2900, 2500, 8);
+
+ spawn.randomSmallMob(-500, -500, 1);
+ spawn.randomMob(190, -1300, 1);
+ spawn.randomMob(200, -320, 0.3);
+ spawn.randomMob(1000, -1100, 1);
+ spawn.randomMob(-160, -2050, 1);
+ spawn.randomMob(-1100, -2900, 0.5);
+ spawn.randomLevelBoss(1900, -3800, spawn.randomBossList.splice(0, spawn.randomBossList.indexOf("shieldingBoss"), 1).concat(spawn.randomBossList.splice(spawn.randomBossList.indexOf("shieldingBoss") + 1))); // shieldingBoss lags out the lighting system for some reason
+ spawn.randomMob(2500, -3500, 0.3);
+ spawn.randomMob(1300, -4100, 0.5);
+ spawn.randomMob(3400, -2450, 1);
+ spawn.randomMob(2850, -2050, 0.4);
+ spawn.randomGroup(-150, -2400, 0.5);
+ spawn.randomMob(-1250, -5150, 1);
+ spawn.randomMob(-2900, -4000, 0.4);
+ spawn.randomMob(-1350, -950, 1);
+ spawn.randomMob(2700, -850, 0.4);
+ spawn.randomMob(2500, -50, 0.4);
+
+ powerUps.addResearchToLevel() // needs to run after mobs are spawned
+
+ var dealtPiston1Damage = false;
+ var dealtPiston2Damage = false;
+ var dealtPiston1MobDamage = false;
+ var dealtPiston2MobDamage = false;
+ var lastPistonDirection = false;
+ var pistonsLocked = false;
+ var finishedGearFight = false;
+ var roofReadyToFall = false;
+ var roofFallCycle = 0;
+ var drawGear = false;
+ var gearCycle = simulation.cycle;
+ var gearPositions = [];
+ var pistonUnlockCycle = 0;
+
+ for (var i = 0; i < 15; i++) {
+ gearPositions.push({
+ x: 2400 + Math.random() * 200,
+ y: -3300 - Math.random() * 3000
+ });
+ }
+
+ var gearSizes = [];
+
+ for (var i = 0; i < 15; i++) {
+ const r1 = 30 + Math.random() * 50;
+ gearSizes.push({
+ r1: r1,
+ r2: r1 + 15 + Math.random() * 30
+ })
+ }
+
+ var circleHead = Matter.Bodies.polygon(m.pos.x, m.pos.y, 0, 31);
+ var losDomain = generateIntersectMap().concat(mob.filter((obj) => { return obj.isNotCloaked == null && (obj.isBoss || obj.label != 'Circle Body') }), [pendulum1, gear1, gear2, piston1, player, circleHead]);
+ var oldMap = [...map];
+ var oldMob = [...mob];
+ var spawnGearMobCycle = 0;
+ var gearsSpawned = 0;
+ var lastSmallGearRot = 0;
+ var smallGearRot = 0;
+ var smallGearPosRot = 0;
+ var bigGearRot = 0;
+ var finalGearRot;
+ var lastFinalGearRot;
+ var startCycle = simulation.cycle; // used to offset simulation.cycle to avoid the swing starting halfway through at the start of the level and messing up syncronization
+
+ level.custom = () => {
+ Matter.Body.setPosition(circleHead, m.pos)
+ if (!(compareArrays(oldMap, map) && compareArrays(oldMob, mob))) {
+ losDomain = generateIntersectMap().concat(mob.filter((obj) => { return obj.isNotCloaked == null && (obj.isBoss || obj.label != 'Circle Body') }), [pendulum1, gear1, gear2, piston1, player, circleHead]);
+ }
+ oldMap = [...map];
+ oldMob = [...mob];
+ ctx.fillStyle = "#b0b0b2";
+ ctx.fillRect(-600, -1700, 2000, 1700);
+ ctx.fillRect(1350, -1851, 1550, 350);
+ ctx.fillRect(-1400, -2950, 4250, 1450);
+ ctx.fillRect(-1400, -4400, 4350, 1500);
+ ctx.fillRect(-450, -4600, 650, 250);
+ ctx.fillRect(2750, -3200, 200, 1300);
+ ctx.fillRect(2750, -3200, 200, 1300);
+ ctx.fillStyle = "#000";
+ ctx.fillRect(350, -2800, 100, 25);
+ // light
+ var lightPos = { x: 400, y: -2775 };
+ var lightRadius = 2950;
+ const vertices = circleLoS(lightPos, lightRadius, map.concat(mob.filter((obj) => { return obj.isNotCloaked == null && (obj.isBoss || obj.label != 'Circle Body') }), [pendulum1, gear1, gear2, piston1, player, circleHead])); if (vertices.length > 0 && vertices[0].x) {
+ ctx.beginPath();
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (var i = 1; i < vertices.length; i++) {
+ var currentDistance = Math.sqrt((vertices[i - 1].x - lightPos.x) ** 2 + (vertices[i - 1].y - lightPos.y) ** 2);
+ var newDistance = Math.sqrt((vertices[i].x - lightPos.x) ** 2 + (vertices[i].y - lightPos.y) ** 2);
+ if (Math.abs(currentDistance - lightRadius) < 1 && Math.abs(newDistance - lightRadius) < 1) {
+ const currentAngle = Math.atan2(vertices[i - 1].y - lightPos.y, vertices[i - 1].x - lightPos.x);
+ const newAngle = Math.atan2(vertices[i].y - lightPos.y, vertices[i].x - lightPos.x);
+ ctx.arc(lightPos.x, lightPos.y, lightRadius, currentAngle, newAngle);
+ } else {
+ ctx.lineTo(vertices[i].x, vertices[i].y)
+ }
+ }
+ newDistance = Math.sqrt((vertices[0].x - lightPos.x) ** 2 + (vertices[0].y - lightPos.y) ** 2);
+ currentDistance = Math.sqrt((vertices[vertices.length - 1].x - lightPos.x) ** 2 + (vertices[vertices.length - 1].y - lightPos.y) ** 2);
+ if (Math.abs(currentDistance - lightRadius) < 1 && Math.abs(newDistance - lightRadius) < 1) {
+ const currentAngle = Math.atan2(vertices[vertices.length - 1].y - lightPos.y, vertices[vertices.length - 1].x - lightPos.x);
+ const newAngle = Math.atan2(vertices[0].y - lightPos.y, vertices[0].x - lightPos.x);
+ ctx.arc(lightPos.x, lightPos.y, lightRadius, currentAngle, newAngle);
+ } else {
+ ctx.lineTo(vertices[0].x, vertices[0].y)
+ }
+ ctx.fillStyle = "rgba(216, 218, 223, 0.5)";
+ ctx.fill();
+ }
+
+ ctx.beginPath();
+ ctx.moveTo(425, -2775);
+ ctx.arc(400, -2775, 25, 0, Math.PI);
+ ctx.fillStyle = "#c6aa12";
+ ctx.fill();
+ ctx.strokeStyle = "#000000";
+ ctx.lineWidth = 1;
+ ctx.stroke();
+ pendulum1.rotate();
+ gear1.rotate();
+ gear2.rotate();
+ gear3.rotate();
+ hand1.rotate();
+ drawBackgroundGear(-1200, -2300, 75, 150, 0.3, "#ccc", -0.05);
+ drawBackgroundGear(-1010, -2380, 30, 100, -0.1, "#ccc", 0.05);
+
+ // pendulum gears
+ if (!m.isBodiesAsleep) smallGearPosRot += Math.sin((simulation.cycle - startCycle) / 50) * 0.3 - Math.sin((simulation.cycle - startCycle - 1) / 50) * 0.3;
+ if (smallGearPosRot > 0.1) smallGearPosRot = 0.1;
+ if (smallGearPosRot < -0.1) smallGearPosRot = -0.1;
+ var circ = 2 * Math.PI * 150;
+ var arcLength = ((smallGearPosRot - Math.sin((simulation.cycle - startCycle) / 50) * 0.2) / (Math.PI * 2)) * circ;
+ lastSmallGearRot = smallGearRot;
+ smallGearRot = arcLength / (2 * Math.PI * 50) * Math.PI * -2 + 0.6;
+
+ if (Math.abs(smallGearPosRot) == 0.1) {
+ bigGearRot += Math.abs((smallGearRot - lastSmallGearRot) * (50 / 75));
+ }
+
+ drawBackgroundGear(740, -2625, 270, 330, bigGearRot, "#d2d3d4", 0, 15, 20); // the big one in the background
+
+ drawBackgroundGear(400, -2500, 100, 150, Math.sin((simulation.cycle - startCycle) / 50) * -0.3, "#ccc", 0, 8, 20); // attached to pendulum
+
+ drawBackgroundGear(400 + Math.cos(smallGearPosRot) * 200, -2500 + Math.sin(smallGearPosRot) * 200, 50, 75, smallGearRot, "#ccc", 0, 7, 20);
+ ctx.beginPath();
+ ctx.arc(400 + Math.cos(smallGearPosRot) * 200, -2500 + Math.sin(smallGearPosRot) * 200, 10, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#444";
+ ctx.lineWidth = 10;
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(400, -2500, 200, -0.1, 0.1);
+ ctx.strokeStyle = "#444";
+ ctx.lineWidth = 10;
+ ctx.stroke();
+
+ drawBackgroundGear(740, -2625, 75, 110, bigGearRot, "#ccc", 0, 8, 20);
+ ctx.beginPath();
+ ctx.arc(740, -2625, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "#bbb";
+ ctx.fill();
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ drawBackgroundGear(740, -2375, 75, 110, bigGearRot * -1, "#ccc", 0, 8, 20);
+ ctx.beginPath();
+ ctx.arc(740, -2375, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "#bbb";
+ ctx.fill();
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+
+ drawDiagonalBelt({ x: 740, y: -2625, radius: 40 }, { x: 740, y: -2375, radius: 40 })
+
+ if (finalGearRot != null) lastFinalGearRot = finalGearRot;
+ finalGearRot = Math.round((-bigGearRot * 294.72 / 25) * 100) / 100 + Math.PI / 2;
+
+ drawBackgroundGear(1080, -2650, 10, 20, finalGearRot, "#ccc", 0, 5, 50);
+ ctx.beginPath();
+ ctx.arc(1080, -2650, 10, 0, 2 * Math.PI);
+ ctx.fillStyle = "#bbb";
+ ctx.fill();
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ drawBackgroundGear(1650, -2550, 300, 360, finalGearRot, "#ccc", 0, 6, 50);
+ ctx.beginPath();
+ ctx.arc(1650, -2550, 100, 0, 2 * Math.PI);
+ ctx.fillStyle = "#bbb";
+ ctx.fill();
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ drawBelt({ x: 1080, y: -2650, radius: 10 }, { x: 1650, y: -2550, radius: 100 });
+ ctx.beginPath();
+ ctx.arc(Math.cos(-finalGearRot) * 294 + 1650, Math.sin(-finalGearRot) * 294 - 2550, 25, 0, 2 * Math.PI);
+ ctx.fillStyle = "#000";
+ ctx.fill();
+ drawBackgroundGear(2300, -2550, 300, 360, -finalGearRot + 0.5, "#ccc", 0, 6, 50);
+ ctx.beginPath();
+ ctx.arc(Math.cos(finalGearRot) * 294 + 2300, Math.sin(finalGearRot) * 294 - 2550, 25, 0, 2 * Math.PI);
+ ctx.fillStyle = "#000";
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.arc(1630, -2215, 15, 0, 2 * Math.PI);
+ ctx.fillStyle = "#000";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(1670, -2215, 15, 0, 2 * Math.PI);
+ ctx.fillStyle = "#000";
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.arc(1940, -2250, 15, 0, 2 * Math.PI);
+ ctx.fillStyle = "#000";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(2300, -2215, 15, 0, 2 * Math.PI);
+ ctx.fillStyle = "#000";
+ ctx.fill();
+
+ if (!finishedGearFight && !pistonsLocked && m.pos.x > 2100 && m.pos.x < 2900 && m.pos.y > -1850 && m.pos.y < -1500) {
+ pistonsLocked = true;
+
+ roofFallCycle = simulation.cycle + 250;
+ roofReadyToFall = true;
+ }
+
+ if (roofReadyToFall && simulation.cycle >= roofFallCycle) {
+ // section of roof is deleted
+ for (var i = 0; i < map.length; i++) {
+ if (map[i].fallsOff) {
+ Matter.Composite.remove(engine.world, map[i]);
+ map.splice(i, 1);
+ }
+ }
+
+ // replace it with a block
+ spawn.bodyRect(2310, -1900, 480, 50);
+ roofReadyToFall = false;
+ drawGear = true;
+ gearCycle = simulation.cycle + 100;
+ }
+
+ //draw some background gears falling when roof falls
+ if (drawGear && simulation.cycle >= gearCycle) {
+ for (var i = 0; i < 15; i++) {
+ drawFallingBackgroundGear(gearPositions[i].x, gearPositions[i].y, gearSizes[i].r1, gearSizes[i].r2, simulation.cycle, "#ccc", 0.1, 25, gearCycle);
+ }
+
+ if (spawnGearMobCycle == 0) {
+ spawnGearMobCycle = simulation.cycle + 100;
+ }
+ }
+
+ if (spawnGearMobCycle > 0 && simulation.cycle >= spawnGearMobCycle) {
+ if (gearsSpawned < 40) {
+ gearMob(1600 + Math.random() * 1000, -2300 - Math.random() * 300, false, true);
+ gearsSpawned++;
+ spawnGearMobCycle = simulation.cycle + 25 - (simulation.difficulty - simulation.difficultyMode) / 2;
+ } else if (pistonUnlockCycle == 0) {
+ pistonUnlockCycle = simulation.cycle + 50;
+ }
+ }
+
+ if (!finishedGearFight && pistonUnlockCycle > 0 && simulation.cycle > pistonUnlockCycle) {
+ pistonsLocked = false;
+ finishedGearFight = true;
+
+ for (var i = 0; i < map.length; i++) {
+ if (map[i].fallsOff2) {
+ Matter.Composite.remove(engine.world, map[i]);
+ map.splice(i, 1);
+ }
+ }
+
+ spawn.bodyRect(2850, -2180, 100, 280);
+ Matter.Body.setAngularVelocity(body[body.length - 1], 0.025);
+ }
+
+ if (Math.sin((simulation.cycle + 15) / 25) < 0 && !lastPistonDirection) { // 15 cycles early to line up better with pendulum
+ piston3.isClosing = true;
+ piston4.isClosing = false;
+ piston5.isClosing = true;
+ piston6.isClosing = false;
+ piston7.isClosing = true;
+ } else if (Math.sin((simulation.cycle + 15) / 25) > 0 && lastPistonDirection) {
+ piston3.isClosing = false;
+ piston4.isClosing = true;
+ piston5.isClosing = false;
+ piston6.isClosing = true;
+ piston7.isClosing = false;
+ }
+
+ if (Math.sin(-finalGearRot) - Math.sin(-lastFinalGearRot) < -0.01) {
+ dealtPiston1Damage = false;
+ dealtPiston1MobDamage = false;
+ }
+ if (Math.sin(-finalGearRot) - Math.sin(-lastFinalGearRot) > 0.01) {
+ dealtPiston2Damage = false;
+ dealtPiston2MobDamage = false;
+ }
+
+ piston3.openClose();
+ piston4.openClose();
+ piston5.openClose();
+ piston6.openClose();
+ piston7.openClose();
+
+ if (!pistonsLocked) {
+ piston1.isLocked = false;
+ }
+
+ if (!pistonsLocked || ((Math.sin(-finalGearRot) - Math.sin(-lastFinalGearRot) != 0 || piston1.position.y < -1850) && !piston1.isLocked)) {
+ piston1.setPos(1650, -1850 + Math.sin(-finalGearRot) * 175);
+ } else {
+ piston1.isLocked = true;
+ }
+
+ piston2.setPos(1950, -1850 + Math.sin(finalGearRot) * 175);
+ ctx.beginPath();
+ ctx.moveTo(Math.cos(-finalGearRot) * 294 + 1650, Math.sin(-finalGearRot) * 294 - 2550);
+ ctx.lineTo(1650, -2230);
+ ctx.lineTo(piston1.position.x, piston1.position.y - 175)
+ ctx.strokeStyle = "#777";
+ ctx.lineWidth = 10;
+ ctx.stroke();
+
+ var circle1;
+ var circle2;
+ if (Math.cos(finalGearRot) * 294 > 0) {
+ circle1 = {
+ x: Math.cos(finalGearRot) * 294 + 2300,
+ y: Math.sin(finalGearRot) * 294 - 2550,
+ radius: -25
+ }
+
+ circle2 = {
+ x: 2300,
+ y: -2215,
+ radius: -15
+ }
+ } else {
+ circle1 = {
+ x: Math.cos(finalGearRot) * 294 + 2300,
+ y: Math.sin(finalGearRot) * 294 - 2550,
+ radius: 25
+ }
+
+ circle2 = {
+ x: 2300,
+ y: -2215,
+ radius: 15
+ }
+ }
+
+ // same method used in drawBelt()
+ var distance = Math.sqrt((circle2.x - circle1.x) ** 2 + (circle2.y - circle1.y) ** 2);
+ var distanceToIntersection = (-circle1.radius * distance) / (-circle1.radius + circle2.radius);
+ var slopeAngle = Math.atan((circle2.y - circle1.y) / (circle2.x - circle1.x));
+ var angleToTangent = Math.acos(-circle1.radius / distanceToIntersection);
+ const tangentPoint = {
+ x: Math.cos(angleToTangent + slopeAngle) * -circle2.radius + circle2.x,
+ y: Math.sin(angleToTangent + slopeAngle) * -circle2.radius + circle2.y
+ }
+
+ // same method used in drawDiagonalBelt()
+ const circle3 = {
+ x: 1940,
+ y: -2250,
+ radius: 15
+ }
+
+ distance = Math.sqrt((circle2.x - circle3.x) ** 2 + (circle2.y - circle3.y) ** 2);
+ distanceToIntersection = (circle3.radius * distance) / (circle3.radius + circle2.radius);
+ slopeAngle = Math.atan((circle2.y - circle3.y) / (circle2.x - circle3.x));
+ angleToTangent = Math.acos(circle3.radius / distanceToIntersection);
+ const tangentPoint2 = {
+ x: Math.cos(angleToTangent + slopeAngle) * circle3.radius + circle3.x,
+ y: Math.sin(angleToTangent + slopeAngle) * circle3.radius + circle3.y
+ }
+ const invertedTangentPoint2 = {
+ x: Math.cos(-angleToTangent + slopeAngle) * circle3.radius + circle3.x,
+ y: Math.sin(-angleToTangent + slopeAngle) * circle3.radius + circle3.y
+ }
+
+ const tangentPoint3 = {
+ x: Math.cos(angleToTangent + slopeAngle) * -circle2.radius + circle2.x,
+ y: Math.sin(angleToTangent + slopeAngle) * -circle2.radius + circle2.y
+ }
+ const invertedTangentPoint3 = {
+ x: Math.cos(-angleToTangent + slopeAngle) * -circle2.radius + circle2.x,
+ y: Math.sin(-angleToTangent + slopeAngle) * -circle2.radius + circle2.y
+ }
+
+ distance = Math.sqrt((piston2.position.y - 175 - circle3.y) ** 2 + (piston2.position.x - 50 - circle3.x) ** 2);
+ slopeAngle = Math.atan((piston2.position.y - 175 - circle3.y) / (piston2.position.x - 50 - circle3.x));
+ angleToTangent = Math.acos(circle3.radius / distance);
+ const tangentPoint4 = {
+ x: Math.cos(angleToTangent) * distance + circle3.x,
+ y: Math.sin(angleToTangent) * distance + circle3.y
+ }
+
+ // draw
+ ctx.beginPath();
+ ctx.moveTo(circle1.x, circle1.y);
+ ctx.lineTo(tangentPoint.x, tangentPoint.y);
+ const newAngle = Math.atan((tangentPoint.y - circle2.y) / (tangentPoint.x - circle2.x));
+ const newAngle2 = Math.atan((tangentPoint3.y - circle2.y) / (tangentPoint3.x - circle2.x));
+ ctx.arc(circle2.x, circle2.y, Math.abs(circle2.radius), newAngle, -newAngle2);
+ ctx.lineTo(invertedTangentPoint2.x, invertedTangentPoint2.y);
+ const newAngle3 = Math.atan((invertedTangentPoint2.y - circle3.y) / (invertedTangentPoint2.x - circle3.x));
+ ctx.arc(circle3.x, circle3.y, circle3.radius, newAngle3, Math.PI / 2 + angleToTangent, true);
+ ctx.lineTo(tangentPoint4.x, tangentPoint4.y);
+ ctx.strokeStyle = '#777';
+ ctx.lineWidth = 10;
+ ctx.stroke();
+
+ lastPistonDirection = Math.sin((simulation.cycle + 15) / 25) < 0;
+
+ if (Matter.Query.ray([player], Matter.Vector.create(piston1.position.x - 50, piston1.position.y + 175), Matter.Vector.create(piston1.position.x + 50, piston1.position.y + 175), 5).length > 0 && !dealtPiston1Damage && Math.sin(-finalGearRot) - Math.sin(-lastFinalGearRot) > 0.01) {
+ m.damage(0.1);
+ dealtPiston1Damage = true;
+ }
+
+ var piston1MobCollisions = Matter.Query.ray(mob, Matter.Vector.create(piston1.position.x - 50, piston1.position.y + 175), Matter.Vector.create(piston1.position.x + 50, piston1.position.y + 175), 5);
+ if (piston1MobCollisions.length > 0 && !dealtPiston1MobDamage && Math.sin(-finalGearRot) - Math.sin(-lastFinalGearRot) > 0.01) {
+ for (var mobHit of piston1MobCollisions) {
+ mobHit.body.damage(1);
+ }
+ dealtPiston1MobDamage = true;
+ }
+
+ if (Matter.Query.ray([player], Matter.Vector.create(piston2.position.x - 50, piston2.position.y + 175), Matter.Vector.create(piston2.position.x + 50, piston2.position.y + 175), 5).length > 0 && !dealtPiston2Damage && Math.sin(-finalGearRot) - Math.sin(-lastFinalGearRot) < -0.01) {
+ m.damage(0.1);
+ dealtPiston2Damage = true;
+ }
+
+ var piston2MobCollisions = Matter.Query.ray(mob, Matter.Vector.create(piston2.position.x - 50, piston2.position.y + 175), Matter.Vector.create(piston2.position.x + 50, piston2.position.y + 175), 5);
+ if (piston2MobCollisions.length > 0 && !dealtPiston2MobDamage && Math.sin(-finalGearRot) - Math.sin(-lastFinalGearRot) > 0.01) {
+ for (var mobHit of piston2MobCollisions) {
+ mobHit.body.damage(1);
+ }
+ dealtPiston2MobDamage = true;
+ }
+
+ // clock
+ ctx.beginPath();
+ ctx.arc(400, -3700, 600, 0, 2 * Math.PI);
+ ctx.fillStyle = "#e9e9e9";
+ ctx.fill();
+ ctx.strokeStyle = "#3a3f20";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+
+ ctx.lineCap = "butt";
+ ctx.beginPath();
+ ctx.moveTo(350, -4275);
+ ctx.lineTo(390, -4150);
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 20;
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(390, -4275);
+ ctx.lineTo(350, -4150);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(420, -4275);
+ ctx.lineTo(420, -4150);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(450, -4275);
+ ctx.lineTo(450, -4150);
+ ctx.stroke();
+
+ var numberOffset = {
+ x: 400 + Math.cos(-Math.PI / 3) * 510,
+ y: -3700 + Math.sin(-Math.PI / 3) * 510
+ }
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x, numberOffset.y + 63);
+ ctx.stroke();
+
+ var numberOffset = {
+ x: 400 + Math.cos(-Math.PI / 6) * 510,
+ y: -3700 + Math.sin(-Math.PI / 6) * 510
+ }
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 20, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x - 20, numberOffset.y + 63);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x + 20, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x + 20, numberOffset.y + 63);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(870, -3762);
+ ctx.lineTo(870, -3637);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(910, -3762);
+ ctx.lineTo(910, -3637);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(950, -3762);
+ ctx.lineTo(950, -3637);
+ ctx.stroke();
+
+ var numberOffset = {
+ x: 400 + Math.cos(Math.PI / 6) * 535,
+ y: -3700 + Math.sin(Math.PI / 6) * 535
+ }
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 50, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x - 50, numberOffset.y + 63);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 20, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x, numberOffset.y + 53);
+ ctx.lineTo(numberOffset.x + 20, numberOffset.y - 62);
+ ctx.stroke();
+
+ var numberOffset = {
+ x: 400 + Math.cos(Math.PI / 3) * 515,
+ y: -3700 + Math.sin(Math.PI / 3) * 515
+ }
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 20, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x, numberOffset.y + 53);
+ ctx.lineTo(numberOffset.x + 20, numberOffset.y - 62);
+ ctx.stroke();
+
+ var numberOffset = {
+ x: 400 + Math.cos(Math.PI / 2) * 515,
+ y: -3700 + Math.sin(Math.PI / 2) * 515
+ }
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 35, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x - 15, numberOffset.y + 53);
+ ctx.lineTo(numberOffset.x + 5, numberOffset.y - 62);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x + 35, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x + 35, numberOffset.y + 63);
+ ctx.stroke();
+
+ var numberOffset = {
+ x: 400 + Math.cos(Math.PI * 2 / 3) * 500,
+ y: -3700 + Math.sin(Math.PI * 2 / 3) * 500
+ }
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 65, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x - 45, numberOffset.y + 53);
+ ctx.lineTo(numberOffset.x - 25, numberOffset.y - 62);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x + 5, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x + 5, numberOffset.y + 63);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x + 35, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x + 35, numberOffset.y + 63);
+ ctx.stroke();
+
+ var numberOffset = {
+ x: 400 + Math.cos(Math.PI * 5 / 6) * 500,
+ y: -3700 + Math.sin(Math.PI * 5 / 6) * 500
+ }
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 65, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x - 45, numberOffset.y + 53);
+ ctx.lineTo(numberOffset.x - 25, numberOffset.y - 62);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x + 5, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x + 5, numberOffset.y + 63);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x + 35, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x + 35, numberOffset.y + 63);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x + 65, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x + 65, numberOffset.y + 63);
+ ctx.stroke();
+
+ var numberOffset = {
+ x: 400 + Math.cos(Math.PI) * 500,
+ y: -3700 + Math.sin(Math.PI) * 500
+ }
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 5, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x + 35, numberOffset.y + 63);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 5, numberOffset.y + 63);
+ ctx.lineTo(numberOffset.x + 35, numberOffset.y - 62);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 35, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x - 35, numberOffset.y + 63);
+ ctx.stroke();
+
+ var numberOffset = {
+ x: 400 + Math.cos(-Math.PI * 5 / 6) * 500,
+ y: -3700 + Math.sin(-Math.PI * 5 / 6) * 500
+ }
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 25, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x + 25, numberOffset.y + 63);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 25, numberOffset.y + 63);
+ ctx.lineTo(numberOffset.x + 25, numberOffset.y - 62);
+ ctx.stroke();
+
+ var numberOffset = {
+ x: 400 + Math.cos(-Math.PI * 2 / 3) * 500,
+ y: -3700 + Math.sin(-Math.PI * 2 / 3) * 500
+ }
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 10, numberOffset.y - 62);
+ ctx.lineTo(numberOffset.x + 40, numberOffset.y + 63);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 10, numberOffset.y + 63);
+ ctx.lineTo(numberOffset.x + 40, numberOffset.y - 62);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(numberOffset.x - 40, numberOffset.y + 63);
+ ctx.lineTo(numberOffset.x - 40, numberOffset.y - 62);
+ ctx.stroke();
+
+ ctx.lineCap = "round";
+
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ }
+
+ var lastBlock = Math.sin(simulation.cycle / 50) < 0;
+
+ level.customTopLayer = () => {
+ elevator1.move();
+
+ ctx.beginPath();
+ ctx.moveTo(pendulum1.parts[2].vertices[0].x, pendulum1.parts[2].vertices[0].y);
+ for (var i = 0; i < pendulum1.parts[2].vertices.length; i++) {
+ ctx.lineTo(pendulum1.parts[2].vertices[i].x, pendulum1.parts[2].vertices[i].y);
+ }
+ ctx.lineTo(pendulum1.parts[2].vertices[0].x, pendulum1.parts[2].vertices[0].y);
+ ctx.fillStyle = "#999";
+ ctx.fill();
+ ctx.lineWidth = 2
+ ctx.strokeStyle = color.blockS;
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(gear3.parts[1].vertices[0].x, gear3.parts[1].vertices[0].y);
+ for (var i = 0; i < gear3.parts[1].vertices.length; i++) {
+ ctx.lineTo(gear3.parts[1].vertices[i].x, gear3.parts[1].vertices[i].y);
+ }
+ ctx.lineTo(gear3.parts[1].vertices[0].x, gear3.parts[1].vertices[0].y);
+ ctx.fillStyle = "#999";
+ ctx.fill();
+ ctx.lineWidth = 2
+ ctx.strokeStyle = color.blockS;
+ ctx.stroke();
+
+ ctx.fillStyle = "#444";
+ ctx.fillRect(3275, -1750, 1, 1750);
+
+ ctx.fillStyle = "#888";
+
+ if (Math.sin(simulation.cycle / 50) < 0 && !lastBlock) {
+ // remove old elements
+ for (var i = 0; i < map.length; i++) {
+ if (map[i].isRemove) {
+ Matter.Composite.remove(engine.world, map[i]);
+ map.splice(i, 1);
+ }
+ }
+
+ // add new element
+ spawn.mapRect(-200, -600, 275, 50);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ } else if (Math.sin(simulation.cycle / 50) * 0.3 >= 0 && lastBlock) {
+ for (var i = 0; i < map.length; i++) {
+ if (map[i].isRemove) {
+ Matter.Composite.remove(engine.world, map[i]);
+ map.splice(i, 1);
+ }
+ }
+
+ spawn.mapRect(825, -600, 275, 50);
+ addPartToMap(map.length - 1);
+ map[map.length - 1].isRemove = true;
+ }
+
+ simulation.draw.setPaths();
+ lastBlock = Math.sin(simulation.cycle / 50) * 0.3 < 0;
+ }
+ },
+ buttonbutton() {
+ simulation.makeTextLog(`
buttonbutton by
||Destabilized E|| `);
+ const mover = level.mover(1425, -1949, 600, 25); //x,y,width.height,VxGoal,force
+
+ let portal
+ portal = level.portal({
+ x: -146,
+ y: 131
+ }, 2 * Math.PI, {
+ x: 1805,
+ y: -2295
+ }, 90)
+
+ const button = level.button(-456, -1320)
+ spawn.bodyRect(-400, -1475, 75, 75);
+ const button2 = level.button(1781, -61)
+ spawn.bodyRect(1781, (-61) - 100, 75, 75);
+ const boost1 = level.boost(1366, -1942, 1300)
+
+ button.isUp = true
+ button2.isUp = true
+
+ const train = level.transport(-250, 1151, 400, 50, 8 + simulation.difficultyMode)
+ level.custom = () => {
+ if (train.position.x < -244) {
+ train.changeDirection(true) //go right
+ } else if (train.position.x > 1700) {
+ train.changeDirection(false) //go left
+ }
+ if (button.isUp && button2.isUp) train.move();
+ mover.push();
+ ctx.fillStyle = "rgba(0,255,255,0.1)";
+ ctx.fillRect(6400, -550, 300, 350);
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+ level.customTopLayer = () => {
+ button.query();
+ button.draw();
+ button2.query();
+ button2.draw();
+ boost1.query();
+ train.draw()
+ portal[2].query()
+ portal[3].query()
+ portal[0].draw();
+ portal[1].draw();
+ mover.draw();
+ ctx.fillStyle = "rgba(0,0,0,0.1)"
+ ctx.fillRect(-150, -650, 900, 250)
+ };
+ level.setPosToSpawn(0, -450); //normal spawn
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.exit.x = -525;
+ level.exit.y = 1128;
+ level.defaultZoom = 1500
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#ddd";
+ spawn.mapRect(-725, -1325, 575, 1900);
+ spawn.mapRect(1425, -1925, 600, 1550);
+ spawn.mapRect(1450, -50, 500, 425);
+ spawn.mapRect(1950, 75, 325, 300);
+ spawn.mapRect(2275, 200, 200, 175);
+ spawn.mapRect(-150, -400, 900, 250);
+ spawn.mapRect(-150, 300, 900, 275);
+ spawn.mapRect(1700, 900, 450, 275);
+ spawn.mapRect(1800, 1600, 450, 250);
+ spawn.mapRect(1675, 1675, 275, 175);
+ spawn.mapRect(1575, 1675, 275, 175);
+ spawn.mapRect(-550, 1150, 150, 100);
+ spawn.bodyRect(-1475, -225, 50, 50);
+ spawn.bodyRect(2450, 1525, 925, 850);
+ spawn.mapRect(2275, 1400, 300, 150);
+ spawn.mapRect(2125, 1025, 125, 150);
+ spawn.mapRect(2250, 1175, 175, 75);
+ spawn.mapRect(2150, 1175, 175, 75);
+ spawn.mapRect(1725, 1150, 475, 100);
+ spawn.mapRect(2225, 675, 650, 50);
+ spawn.bodyRect(2400, 500, 150, 175);
+ spawn.nodeGroup(326, 85, "grenadier", 6)
+ spawn.mapRect(-225, -1325, 625, 225);
+
+ spawn.randomMob(151, -1500)
+ spawn.randomMob(-88, -1829)
+ spawn.randomMob(2339, 896)
+
+
+ spawn.randomMob(1907, 1381)
+ spawn.randomMob(2398, 1301)
+ spawn.randomMob(1839, 811)
+
+
+ spawn.randomMob(2282, 1103)
+ spawn.randomMob(8, 124)
+ spawn.randomMob(629, 111)
+
+ spawn.randomMob(43, 831)
+ spawn.randomMob(168, 1002)
+ spawn.randomMob(2956, 1006)
+
+ spawn.randomMob(2713, 535)
+ spawn.randomMob(2396, 117)
+ spawn.randomMob(1498, -121)
+
+ spawn.nodeGroup(2030, -16, "grower", 6)
+ spawn.randomLevelBoss(1840, 675)
+ },
+ movers() {
+ simulation.makeTextLog(`
movers by
ryanbear `);
+ level.custom = () => {
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ for (var i = 0; i < trains.length; i++) {
+ //oscillate back and forth
+ if (trains[i].position.x < 5075) {
+ trains[i].changeDirection(true) //go right
+ } else if (trains[i].position.x > 7875) {
+ trains[i].changeDirection(false) //go left
+ }
+ trains[i].draw();
+ trains[i].move();
+ }
+ for (var j = 0; j < zzz.length; j++) {
+ zzz[j][0].query();
+ }
+ mvr.push();
+ v3.query();
+ ctx.fillStyle = "rgba(68,68,68,1)";
+ ctx.fillRect(1725, -2400, 1000, 150);
+ ctx.fillRect(2175, -2775, 250, 450);
+ ctx.fillRect(2200, -2825, 225, 200);
+ ctx.fillRect(2075, -2575, 150, 200);
+ ctx.fillRect(2075, -2700, 150, 150);
+ ctx.fillRect(1875, -2525, 300, 125);
+ ctx.fillRect(1975, -2575, 150, 75);
+ ctx.fillRect(1800, -2475, 175, 100);
+ ctx.fillRect(2150, -2725, 350, 375);
+ ctx.fillRect(2475, -2575, 175, 200);
+ ctx.fillRect(2675, -2550, 25, 175);
+ ctx.fillRect(2625, -2550, 75, 200);
+ ctx.fillRect(2025, -2600, 200, 175);
+ ctx.fillRect(2025, -2675, 225, 225);
+ ctx.fillRect(2125, -2800, 250, 375);
+ ctx.fillRect(2400, -2625, 175, 175);
+ ctx.fillRect(2450, -2700, 100, 225);
+ ctx.fillRect(1950, -2600, 150, 200);
+ ctx.fillRect(1675, -2325, 250, 75);
+ ctx.fillRect(2700, -2525, 25, 150);
+ };
+ simulation.enableConstructMode()
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 23885;
+ level.exit.y = 800;
+ spawn.mapRect(-98, -8, 1000, 20); //bump for level entrance
+ spawn.mapRect(972, -287, 200, 20); //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ var trains = [];
+ var zzz = [];
+ spawn.mapRect(9850, 475, 200, 75);
+ for (var i = 0; i < 6; i++) {
+ trains.push(level.transport(6275, -2100 + 525 * i, 600, 50, (2 * i % 2 - 1) * 4 * Math.min(simulation.difficulty / 2, 2) * (1 + Math.random())))
+ zzz.push([level.boost(6275, -2100 + 525 * i, 100), 6275]);
+ }
+ document.body.style.backgroundColor = "#d8dadf";
+
+ const portal1 = level.portal({
+ x: 3984,
+ y: 1293
+ }, -2 * Math.PI, { //right
+ x: 23863,
+ y: 82
+ }, 2 * Math.PI) //right
+
+ spawn.mapRect(1825, -2250, 3300, 300); spawn.mapRect(3250, -2875, 150, 625);
+ spawn.mapRect(3250, -2875, 425, 125);
+ spawn.mapRect(3425, -2725, 150, 300);
+ spawn.mapRect(3400, -2750, 175, 350);
+ spawn.mapRect(3575, -2625, 150, 375);
+ spawn.mapRect(3175, -2750, 75, 300);
+ spawn.mapRect(3100, -2750, 275, 300);
+ spawn.mapRect(3675, -2875, 75, 125);
+ spawn.mapRect(3675, -2625, 75, 400);
+ spawn.mapRect(3350, -2425, 100, 175);
+ spawn.mapRect(8350, 825, 1825, 250);
+ spawn.mapRect(3950, 800, 800, 375);
+ var hzd = level.hazard(3750, -2625, 1375, 375);
+ // spawn.mapRect(3750, -2625, 1375, 375);
+ var v1 = level.vanish(3975, -2600, 225, 25);
+ var v2 = level.vanish(4275, -2975, 225, 25);
+ var mvr = level.mover(2585, 1928, 2375, 100);
+ //spawn.mapRect(4925, 1725, 300, 25);
+ var v3 = level.vanish(4925, 1725, 100, 25);
+ for (var i = 0; i < 16; i++) {
+ if (i < 10) {
+ level.boost(1600 + 62 * i, -2307 - 62 * i, 100);
+ }
+ else {
+ level.boost(1600 + 62 * i, -2307 - 62 * 20 + 62 * i, 100);
+ }
+ }
+
+
+ for (var i = -1; i < 10; i++) {
+ level.boost(3847 - 62 * i, 879 + 62 * i, 100);
+ }
+ spawn.mapRect(3050, 1500, 1600, 200);
+ spawn.mapRect(1850, -1950, 3275, 1275); spawn.mapRect(1850, -675, 3275, 1300);
+
+ spawn.mapRect(2700, -2525, 25, 175);
+ spawn.mapRect(3825, 925, 125, 575); spawn.mapRect(3600, 1100, 350, 400); spawn.mapRect(3375, 1350, 275, 150); spawn.mapRect(3550, 1300, 100, 50); spawn.mapRect(3800, 1000, 100, 150); spawn.mapRect(3725, 1075, 150, 125); spawn.mapRect(3725, 1025, 150, 125); spawn.mapRect(3550, 1225, 150, 125); spawn.mapRect(3500, 1275, 175, 125);
+ // color.map = "#444" //custom map color
+ bosses = ["laserBoss", "blinkBoss", "shooterBoss", "launcherBoss", "pulsarBoss", "beetleBoss", "bladeBoss", "revolutionBoss", "dragonFlyBoss", "spiderBoss"];
+ let randomBoss = Math.floor(Math.random() * bosses.length);
+ spawn[bosses[randomBoss]](2240, -2499, 100, false);
+ var btn = level.button(9889, 747);
+ btn.isUp = true;
+ spawn.randomMob(475, -725, 0.7); spawn.randomMob(825, -1825, 0.7); spawn.randomMob(3275, -3475, 0.7); spawn.randomMob(8550, 350, 0.7); spawn.randomMob(9350, -175, 0.7); spawn.randomMob(1575, 225, 0.7); spawn.randomMob(22825, 250, 0.7);
+ spawn.mapRect(-100, 0, 1000, 100);
+ var ddd = level.elevator(1326, -447, 200, 200, -2131, 0.003, { up: 0.1, down: 0.2 });
+ /// transport(x, y, width, height, VxGoal = -6, force = VxGoal > 0 ? 0.0005 : -0.0005) {
+ spawn.mapRect(9500, 750, 675, 75);
+ spawn.mapRect(22350, 825, 3000, 150);
+ powerUps.spawn(4246, 1335, "tech")
+ powerUps.spawn(4246.8, 1335, "heal")
+ powerUps.spawn(4246.8, 1335.4, "ammo")
+ spawn.bodyRect(9200, 725, 50, 25); spawn.mapRect(12200, 675, 125, 50); spawn.mapRect(12925, 675, 100, 100); spawn.mapRect(13675, 650, 150, 150); spawn.mapRect(14200, 750, 25, 25); spawn.mapRect(14200, 675, 25, 75); spawn.mapRect(14550, 675, 125, 50); spawn.mapRect(15850, 675, 125, 100); spawn.mapRect(17175, 600, 25, 200); spawn.mapRect(17725, 700, 175, 50); spawn.mapRect(18775, 675, 175, 75);
+ spawn.bodyRect(8975, 700, 25, 25); spawn.bodyRect(8850, 575, 50, 50); spawn.bodyRect(9050, 650, 50, 50); spawn.bodyRect(8625, 575, 100, 75); spawn.bodyRect(8475, 675, 75, 25);
+ var train1 = level.transport(10250 - 700, 775, Math.max(1200 / simulation.difficulty, 200), 1350, 8);
+ level.customTopLayer = () => {
+ ddd.move();
+ hzd.query();
+ v1.query();
+ v2.query();
+ btn.draw();
+ portal1[2].query();
+ portal1[2].draw();
+ portal1[3].query();
+ portal1[3].draw();
+ btn.query();
+ if (!btn.isUp) {
+ spawn.mapRect(4050, 1175, 600, 325);
+ }
+ if (!btn.isUp && train1.position.x < 23785) {
+ train1.draw();
+ train1.move();
+ }
+ // if (trains[i].position.x < 5075) {
+ // trains[i].changeDirection(true) //go right
+ };
+ // powerUps.spawnStartingPowerUps(1475, -1175);
+ // spawn.debris(750, -2200, 3700, 16); //16 debris per level
+ // spawn.bodyRect(1540, -1110, 300, 25, 0.9);
+ // spawn.randomSmallMob(1300, -70);
+ // spawn.randomMob(2650, -975, 0.8);
+ // spawn.randomGroup(1700, -900, 0.4);
+ // if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300);
+ // spawn.secondaryBossChance(100, -1500)
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ downpour() {
+ simulation.makeTextLog(`
Downpour by
DesBoot `);
+ let mobsspawned = 0
+ const laser = level.hazard(7492, -2612, 10, 500, 0.3) //laserintro
+
+ //5381, -3268, 10, 0.4
+ spawn.mapRect(340, -2032.5, 20, 25); //laser nose //laserintro
+ const laserbutton = level.button(5485, -2510)
+ const doorbutton = level.button(7618, -3204)
+ const doortoggle = level.toggle(5088.4, 1226.7)
+ const door = level.door(6500, -1200, 100, 350, 100)
+ const bunkerdoor = level.door(10700, -2500, 100, 500, 200)
+
+ const boost1 = level.boost(7300, 1209, 2200)
+ const boost2 = level.boost(6232.6, -832.8, 1400)
+ const portal = level.portal({ x: 4886.4, y: 1050.7 }, 2 * Math.PI, { x: 7686, y: -2121 }, 2 * Math.PI)
+ //let portal
+ const slime = level.hazard(-1800, 10, 4200, 400);
+ const slime2 = level.hazard(2400, -2100, 200, 2100);
+ const slime3 = level.hazard(2600, -2100, 3600, 200);
+ const slime4 = level.hazard(6400, -2100, 3600, 200);
+ simulation.enableConstructMode()
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 13130.3;
+ let rainCount = 1
+ level.exit.y = -370;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit
+ level.defaultZoom = 1800
+ let stopcycle = 0
+ let flashcycle = Math.round(Math.random() * 25 + 260)
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#2e416e";//d8dadf
+ // color.map = "#444" //custom map color
+
+
+ //simulation.makeTextLog(stopcycle)
+ level.custom = () => {
+ do {
+
+ ctx.beginPath()
+ ctx.fillStyle = "rgba(30,150,117,255)"
+ ctx.rect(Math.random() * 4500 - 2000, -5000, Math.random() * 3 + 2.5, 5000)
+ ctx.rect(Math.random() * 4500 - 2000, -5000, Math.random() * 3 + 2.5, 5000)
+ ctx.rect(Math.random() * 4500 - 2000, -5000, Math.random() * 3 + 2.5, 5000)
+ ctx.rect(Math.random() * 2000 + 2500, -5000, Math.random() * 3 + 2.5, 3000)
+ ctx.rect(Math.random() * 2000 + 2500, -5000, Math.random() * 3 + 2.5, 3000)
+ ctx.rect(Math.random() * 1300 + 4500, -5000, Math.random() * 3 + 2.5, 2500)
+ ctx.rect(Math.random() * 1300 + 7500, -5000, Math.random() * 3 + 2.5, 1800)
+ ctx.rect(Math.random() * 1800 + 5700, -5000, Math.random() * 3 + 2.5, 3000)
+ ctx.rect(Math.random() * 1800 + 5700, -5000, Math.random() * 3 + 2.5, 3000)
+ ctx.rect(Math.random() * 1800 + 8400, -5000, Math.random() * 3 + 2.5, 3000)
+ ctx.rect(Math.random() * 1800 + 8400, -5000, Math.random() * 3 + 2.5, 3000)
+ ctx.rect(Math.random() * 4500 - 2000, -5000, Math.random() * 3 + 2.5, 5000)
+ ctx.rect(Math.random() * 1800 + 10200, -5000, Math.random() * 3 + 2.5, 3000)
+ ctx.rect(Math.random() * 1800 + 10200, -5000, Math.random() * 3 + 2.5, 3000)
+ ctx.rect(Math.random() * 1800 + 12000, -5000, Math.random() * 3 + 2.5, 3000)
+ ctx.rect(Math.random() * 1800 + 12000, -5000, Math.random() * 3 + 2.5, 3000)
+ ctx.fillStyle = "rgba(30,150,117,255)"
+ ctx.fill()
+ // }
+ // if (rainCount > 12) {
+ // rainCount = 1
+ // simulation.makeTextLog(rainCount)
+
+ // } else {
+ // rainCount = rainCount + 1
+ // simulation.makeTextLog(rainCount)
+ // }
+ } while (Math.random() < 0.8);
+ //simulation.makeTextLog(stopcycle)
+ //simulation.makeTextLog(m.cycle)
+ // ctx.fillStyle = "rgba(228,255,0,0.8)"
+ // //simulation.makeTextLog(stopcycle)
+ // ctx.fillRect(50.4, -1210.0, 100, 100)
+ // stopcycle = m.cycle + Math.random * 600;
+ //stopcycle = m.cycles + Math.random * 600
+
+ if (stopcycle > 300) {
+ stopcycle = 0
+ flashcycle = Math.round(Math.random() * 25 + 260)
+ document.body.style.backgroundColor = "#2e416e";
+ } else {
+ if (stopcycle > flashcycle) {
+ document.body.style.backgroundColor = "#7391ff";
+ for (let i = 0; i < mob.length; i++) mobs.statusStun(mob[i], Math.random() * 20 + 30)
+ }
+ stopcycle = stopcycle + 1
+ }
+
+ ctx.fillStyle = "#d4f4f4"
+ ctx.fillRect(12984, -704, 420, 450)
+ ctx.fillStyle = "rgba(0,0,0,0.5)"
+ ctx.fillRect(4703, -2362, 100, 100)
+ ctx.fillRect(5053, -2362, 100, 100)
+ ctx.fillRect(5403, -2362, 100, 100)
+ ctx.fillRect(4703, -2062, 100, 100)
+ ctx.fillRect(5053, -2062, 100, 100)
+ ctx.fillRect(5403, -2062, 100, 100)
+ ctx.fillRect(4523, -2512, 1150, 800)
+ ctx.fillRect(4735, -1233, 100, 500)//tree
+ ctx.beginPath()
+ ctx.moveTo(4487, -1195)//slope of -1/3
+ ctx.lineTo(4736, -792)
+ ctx.lineTo(4736, -852)
+ ctx.lineTo(4527, -1195)
+
+
+ ctx.moveTo(5087, -1195)//slope of -1/3
+ ctx.lineTo(4836, -792)
+ ctx.lineTo(4836, -852)
+ ctx.lineTo(5047, -1195)
+ ctx.fill()
+ ctx.moveTo(5252.4, -2483.5)
+ ctx.lineTo(5141.2, -2507.8)
+ ctx.lineTo(5209.2, -2625.2)
+ ctx.lineTo(5290.2, -2626.6)
+
+ ctx.lineTo(5361.2, -2697.9)
+ ctx.lineTo(5410.6, -2717.0)
+
+ ctx.lineTo(5680.2, -2648.7)
+ ctx.lineTo(5687.7, -2471.5)
+
+ ctx.fill()
+
+
+
+ //building 2 spawn.mapRect(8473, -2513, 50, 50);
+ ctx.fillRect(8673, -2137, 50, 175)
+
+ ctx.fillRect(7630, -2540, 100, 100)
+ ctx.fillRect(7930, -2540, 100, 100)
+ ctx.fillRect(8230, -2540, 100, 100)
+
+ ctx.fillRect(8530, -2765, 100, 100)
+
+ ctx.fillRect(7630, -2990, 100, 100)
+ ctx.fillRect(7930, -2990, 100, 100)
+
+ ctx.fillRect(8230, -2990, 100, 100)
+
+
+ ctx.beginPath()
+ ctx.moveTo(7475, -3213)
+ ctx.lineTo(8100, -3213)
+ ctx.lineTo(8191.2, -3334.7)
+ ctx.lineTo(8318.0, -3388.3)
+ ctx.lineTo(8348.5, -3496.9)
+ ctx.lineTo(8480.0, -3512.6)
+ ctx.lineTo(8670, -3482)
+ ctx.lineTo(8725, -3213)
+ ctx.lineTo(8725, -1463)
+ ctx.lineTo(7475, -1463)
+ ctx.fill()
+
+
+
+ //stairs spawn.mapRect(7523, -2313, 800, 75);
+ ctx.fillRect(8523, -2563, 50, 50)
+ ctx.fillRect(8473, -2613, 50, 50)
+ ctx.fillRect(8423, -2663, 50, 50)
+ ctx.fillRect(8373, -2713, 50, 50)
+ ctx.fillRect(8323, -2763, 50, 50)
+
+ ctx.fillRect(8323, -2813, 50, 50)
+ ctx.fillRect(8373, -2863, 50, 50)
+ ctx.fillRect(8423, -2913, 50, 50)
+ ctx.fillRect(8473, -2963, 50, 50)
+
+ ctx.fillRect(8523, -3013, 50, 50)//make block
+ ctx.fillRect(8473, -3063, 50, 50)//make block
+ ctx.fillRect(8423, -3113, 50, 50)//make block
+ ctx.fillRect(8373, -3163, 50, 50)
+ ctx.fillRect(8323, -3213, 50, 50)
+
+ //caves
+
+ ctx.fillStyle = "rgba(30,150,117,255)"//fake slime
+ //87,189,146,255
+ ctx.fillRect(6100, -1900, 100, 1050)
+ ctx.fillRect(6400, -1900, 100, 1050)
+ ctx.fillRect(2600, -850, 4700, 200)
+ ctx.fillRect(7200, -650, 100, 1900)
+ ctx.fillRect(2399, -1, 200, 400)
+
+ //bunker
+ ctx.fillStyle = "rgba(0,0,0,0.5)"
+
+ ctx.beginPath()
+ ctx.moveTo(10800, -2400)//slope of -1/3
+ ctx.lineTo(10800, -340)
+ ctx.lineTo(12980, -340)
+ ctx.lineTo(12980, -700)
+ ctx.lineTo(13465, -700)
+ ctx.lineTo(13541, -1737)
+ ctx.lineTo(11864.6, -1967.0)
+ ctx.lineTo(11003, -2400)
+ ctx.fill()
+ ctx.fillRect(6100, -2000, 400, 50)
+
+ // -2000 -> 2500
+ // Math.random() * 5000 -2500
+ ctx.fillStyle = "rgba(0,0,0,0.6)"
+ ctx.beginPath()
+ ctx.moveTo(6100, -1700)
+ ctx.lineTo(5799.5, -800)
+ ctx.lineTo(2600, -800)
+ ctx.lineTo(2600, -1700)
+ ctx.lineTo(5799.5, -1700)
+
+ ctx.moveTo(6500, -1200)
+ ctx.lineTo(7600, -1200)
+ ctx.lineTo(8000, 1400)
+ ctx.lineTo(4600, 1500)
+ ctx.lineTo(4500.5, 0)
+ ctx.lineTo(6500, -200)
+ ctx.lineTo(6500, -1200)
+ ctx.fill()
+
+
+
+
+ portal[2].query()
+ portal[3].query()
+ if (laserbutton.isUp) {
+ laser.isOn = true;
+ } else {
+ laser.isOn = false;
+ }
+
+
+ ctx.fillStyle = "rgba(0,0,0,0.6)"
+ ctx.fillRect(2113, -791, 500, 75)
+ ctx.fillRect(1766, -1091, 250, 310)
+ ctx.fillRect(4473, -2912, 50, 1000)
+ ctx.fillRect(5673, -2712, 50, 800)
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+
+ ctx.fillRect(4523, -2512, 350, 75)
+ ctx.fillRect(5273, -2212, 400, 75)
+
+
+ level.exit.drawAndCheck();
+ slime.query();
+ slime2.query();
+ slime3.query();
+ slime4.query();
+
+ // spawn.mapRect(4873, -2512, 800, 75);
+ // spawn.mapRect(4473, -2212, 800, 75);
+ //setTimeout(function(){/*YourCode*/},1000);
+
+ //water falling/flowing effect
+ ctx.fillStyle = `hsla(160, 100%, 26%,${0.5 + 0.07 * Math.random()})`//lower river
+ ctx.fillRect(-1800 + Math.random() * 100, 10 + 400 * Math.random(), 3900, 5)
+ ctx.fillRect(-1800, 10 + 400 * Math.random(), 4400, 5)
+
+ ctx.fillRect(2400 + 200 * Math.random(), Math.random() * - 100 - 2000, 5, 2000)//first waterfall
+ ctx.fillRect(6100 + 100 * Math.random(), Math.random() * - 100 - 1900, 5, 1050)//twin waterfalls
+ ctx.fillRect(6400 + 100 * Math.random(), Math.random() * - 100 - 1900, 5, 1050)
+
+ ctx.fillRect(7200 + 100 * Math.random(), -800 - 50 * Math.random(), 5, 2032)
+ level.enter.draw();
+ laserbutton.query();
+ laserbutton.draw();
+ doortoggle.query();
+ if (!doortoggle.isOn) {
+ door.isClosing = true
+ bunkerdoor.isClosing = true
+
+ } else {
+ door.isClosing = false
+ bunkerdoor.isClosing = false
+ if (mobsspawned == 0) {
+ spawn.randomSmallMob(6128.0, 822.6);
+ spawn.randomSmallMob(6854.8, 560.2);
+ spawn.randomSmallMob(8320.7, -3402.4);
+ spawn.randomMob(6629.0, 711.3, 0.8);
+ spawn.randomMob(8199.2, -2545.5, 0.8);
+ spawn.randomMob(8067.7, -2957.2, 0.8);
+ spawn.randomMob(5149.6, -1444.1, 0.8);
+
+ mobsspawned = 1
+
+ }
+
+ }
+ door.openClose();
+ bunkerdoor.openClose();
+
+ };
+ level.customTopLayer = () => {
+ door.draw();
+ bunkerdoor.draw();
+
+ laser.opticalQuery();
+ if (player.position.y > -70 && player.position.x < 2785) {
+ if (m.onGround) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x - (2 + m.pos.y / 150),
+ y: player.velocity.y
+ });
+ } else {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x - (1 + m.pos.y / 150),
+ y: player.velocity.y
+ });
+ }
+
+ }
+ if (player.position.x > 2400 && player.position.x < 2600) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 4
+ });
+
+
+ }
+ boost1.query();
+ boost2.query();
+ if (player.position.x > 2600 && player.position.x < 4500 && player.position.y < -1900 && player.position.y > -2121.3) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x - 2,
+ y: player.velocity.y
+ });
+ }
+ if (player.position.x > 4500 && player.position.x < 6000 && player.position.y < -1900 && player.position.y > -2121.3) {
+
+ if (input.left) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x + 0.1,
+ y: player.velocity.y
+ });
+ } else {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x + 0.5,
+ y: player.velocity.y
+ });
+ }
+ }
+ if (player.position.x > 6500 && player.position.x < 7500 && player.position.y < -1900 && player.position.y > -2121.3) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x - 1,
+ y: player.velocity.y
+ });
+ }
+ if (player.position.x > 7500 && player.position.x < 10000 && player.position.y < -1900 && player.position.y > -2121.3) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x - 1,
+ y: player.velocity.y
+ });
+ }
+ if (player.position.x > 2600 && player.position.x < 6100 && player.position.y < -650 && player.position.y > -920) {
+ if (input.right) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x - 0.2,
+ y: player.velocity.y
+ });
+ } else {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x - 0.4,
+ y: player.velocity.y
+ });
+ }
+ }
+ if (player.position.x > 6500 && player.position.x < 7300 && player.position.y < -650 && player.position.y > -920 && m.onGround) {
+ if (input.left) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x + 0.2,
+ y: player.velocity.y
+ });
+ } else {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x + 0.4,
+ y: player.velocity.y
+ });
+ }
+ }
+ if (player.position.x > 7200 && player.position.x < 7350 && player.position.y > -950 && player.position.y < 1250) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 0.8
+ });
+ }
+ if (player.position.x > 6100 && player.position.x < 6200 && player.position.y < -800 && player.position.y > -2000) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 0.3
+ });
+ }
+ if (player.position.x > 6400 && player.position.x < 6500 && player.position.y < -800 && player.position.y > -2000) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 0.3
+ });
+ }
+ // ctx.fillRect(7200, -650, 100, 1900)
+
+ portal[0].draw();
+ portal[1].draw();
+ portal[2].draw();
+ portal[3].draw();
+
+
+ };
+
+ spawn.mapRect(-100, 0, 1000, 100);
+ spawn.mapRect(-1800, 400, 4400, 1300);
+ spawn.mapRect(-1800, 0, 100, 400);
+ spawn.mapRect(2600, -2000, 3500, 300);
+ spawn.mapRect(2600, -2000, 500, 800);
+ spawn.mapRect(2955, -1779, 800, 300);
+ spawn.mapRect(2600, -800, 2300, 2500);
+ spawn.mapRect(-460, 100, 1570, 400);
+ spawn.mapVertex(965, 67, "0 -100 220 0 0 0");
+ spawn.mapVertex(-185, 67, "0 -100 -420 0 0 0");
+ spawn.mapVertex(1210, 365, "0 -400 300 0 0 0");
+ spawn.mapRect(217.5, -358.5, 50, 360);
+ spawn.mapRect(-83, -358.5, 300, 50);
+
+ //blocks in river/waterfall
+
+ spawn.mapRect(1275, 0, 450, 75);
+ spawn.mapRect(2027, -388, 600, 75);
+ spawn.mapRect(1666, -791, 450, 75);
+ spawn.mapRect(1666, -1091, 450, 75);
+ //buildings
+
+ spawn.mapRect(4873, -2512, 800, 75);
+ spawn.mapRect(4473, -2212, 800, 75);
+ spawn.mapRect(4473, -2912, 50, 800);
+ spawn.mapRect(5673, -2712, 50, 575);
+
+ spawn.mapRect(6671.5, -2401.4, 500, 50);
+ spawn.mapRect(6105.1, -2354.1, 400, 50);
+
+ spawn.mapRect(4473, -2952, 8, 75);//1,3,2
+ spawn.mapRect(4493, -3032, 15, 150);
+ spawn.mapRect(4513, -2982, 7, 75);
+
+ spawn.mapRect(5673, -2742, 12, 50);
+ spawn.mapRect(5703, -2772, 8, 100);
+
+
+ //building 2
+ // ctx.fillRect(8323, -2363, 50, 50)
+
+ spawn.mapRect(7473, -3412, 50, 800);
+ spawn.mapRect(7473, -2312, 50, 500);
+ spawn.mapRect(8673, -3212, 50, 1075);
+ spawn.mapRect(7523, -2313, 800, 75);
+ spawn.mapRect(7523, -2763, 800, 75);
+ spawn.mapRect(7523, -3213, 800, 75);
+ spawn.mapRect(8725, -2340, 400, 50);
+ spawn.mapRect(8925, -2640, 200, 50);
+ spawn.mapRect(8725, -2940, 200, 50);
+
+ //stairs
+ spawn.mapRect(8323, -2363, 50, 50);
+ spawn.mapRect(8373, -2413, 50, 50);
+ spawn.mapRect(8423, -2463, 50, 50);
+ spawn.mapRect(8473, -2513, 250, 50);
+ //stairs 2
+ spawn.mapRect(8523, -3013, 50, 50)//make block
+ spawn.mapRect(8473, -3063, 50, 50)//make block
+ spawn.mapRect(8423, -3113, 50, 50)//make block
+ //trees in tunnel
+ spawn.mapRect(4485, -1243, 600, 50)
+ spawn.mapRect(3967, -1056, 400, 50)
+ spawn.mapRect(5453, -1150, 50, 300)
+ spawn.mapRect(5453, -1700, 50, 300)
+
+
+ //tunnels and boss
+ spawn.mapRect(6500, -2000, 3100, 800);
+ spawn.mapRect(7500, -2000, 3300, 3700);
+ spawn.mapRect(4900, -800, 2300, 1000);
+ spawn.mapRect(4354, 1230, 4000, 470);
+ spawn.mapRect(5388, 863, 100, 500);
+ spawn.mapRect(5388, 63, 100, 500);
+ spawn.mapRect(5834, 549, 500, 80);
+ spawn.mapRect(6756, 897, 400, 80);
+
+
+ //extra boss
+ spawn.mapRect(9196, -11492, 500, 100);
+ spawn.mapRect(9196, -11492, 500, 100);
+
+ //bunker
+ spawn.mapRect(11500, -2000, 1900, 500);
+ spawn.mapRect(10800, -900, 800, 2600);
+ spawn.mapRect(11600, -340, 1800, 2600);
+ spawn.mapRect(13400, -2000, 1800, 3600);
+ spawn.mapRect(10800, -2500, 200, 100);
+ spawn.mapVertex(11400, -2235, "0 10 900 510 800 510 750 510 0 110");
+
+ spawn.mapVertex(10100, -2000, "0 0 0 -250 400 0");
+ spawn.mapRect(12945.0, -741.9, 600, 50);
+ spawn.mapRect(12945.0, -741.9, 50, 250);
+ //stairs
+ spawn.mapRect(11600, -850, 50, 550);
+ spawn.mapRect(11650, -800, 50, 500);
+ spawn.mapRect(11700, -750, 50, 450);
+ spawn.mapRect(11750, -700, 50, 400);
+ spawn.mapRect(11800, -650, 50, 350);
+ spawn.mapRect(11850, -600, 50, 300);
+ spawn.mapRect(11900, -550, 50, 250);
+ spawn.mapRect(11950, -500, 50, 200);
+ spawn.mapRect(12000, -450, 50, 150);
+ spawn.mapRect(12050, -400, 50, 100);
+ spawn.mapRect(12100, -350, 50, 50);
+
+
+ //mobs
+ //spawn.tetherBoss(6480, 992, { x: 6480, y: 210 })
+
+ if (Math.random() < 0.5) {
+ spawn.tetherBoss(6480, 992, { x: 6480, y: 210 })
+ } else {
+ spawn.randomLevelBoss(5977, 992)
+ }
+
+
+ //mobs for waterfall and first cavern
+ //spawn.randomSmallMob(1999.2, -487.4);
+ spawn.randomMob(1999.2, -487.4, 0.8);
+ //spawn.randomSmallMob(2080.0, -1206.4);
+ spawn.randomMob(2080.0, -1206.4, 0.8);
+ spawn.randomSmallMob(3287.5, -1021.1);
+ //spawn.randomSmallMob(3992.2, -1223.9);
+ spawn.randomSmallMob(5018.1, -1483.5);
+ spawn.randomGroup(6776.2, -3054.5, 0.4);
+ spawn.randomGroup(4217.4, -1403.6, 0.4);
+
+
+ //surface area mobs
+ spawn.randomSmallMob(5089.0, -2284.1);
+ spawn.randomSmallMob(6988.3, -2580.2);
+ spawn.randomSmallMob(7975.0, -2920.3);
+ spawn.randomMob(5132.0, -2646.2, 0.8);
+ spawn.randomMob(6365.2, -2459.2, 0.8);
+ spawn.randomMob(8129.0, -2406.7, 0.8);
+ spawn.randomMob(8129.0, -2406.7, 0.8);
+ spawn.randomGroup(2225.3, -1543.2, 0.4);
+
+
+ spawn.debris(4426.9, -1433.8, 700, 1); //16 debris per level
+ spawn.debris(4651.2, -2597.3, 700, 1); //16 debris per level
+ spawn.debris(9920.9, -2378.3, 700, 2); //16 debris per level
+ spawn.debris(8298.5, -2883.8, 700, 1); //16 debris per level
+ spawn.debris(6779.2, -2662.9, 700, 1); //16 debris per level
+ spawn.debris(6371.5, 442.3, 700, 2); //16 debris per level
+ spawn.debris(1873.5, -1297.5, 700, 1); //16 debris per level
+
+ spawn.bodyRect(6457.9, -2541.5, 300, 25, 0.9);
+ //spawn.bodyRect(5685, -2140, 25, 140, 0.9);
+ spawn.bodyRect(4473, -2110, 50, 110, 0.9);
+ //spawn.bodyRect(5292.1, -2617.2, 50, 50, 0.9);
+ spawn.bodyRect(6370.1, -2408.4, 50, 50, 0.9);
+ //spawn.bodyRect(5467, -1400, 25, 250, 0.9);
+
+ spawn.bodyRect(4509.0, -1425.7, 30 + 45 * Math.random(), 30 + 45 * Math.random(), 0.9);
+ //spawn.bodyRect(8082.9, -2488.1, 30 + 45 * Math.random(), 30 + 45 * Math.random(), 0.9);
+ spawn.bodyRect(7859.6, -2883.6, 30 + 45 * Math.random(), 30 + 45 * Math.random(), 0.9);
+ //spawn.bodyRect(5609.5, 948.5, 30 + 45 * Math.random(), 30 + 45 * Math.random(), 0.9);
+ spawn.bodyRect(5803.7, 1125.5, 30 + 45 * Math.random(), 30 + 45 * Math.random(), 0.9);
+ //spawn.bodyRect(5492.1, 1061.7, 90, 169, 0.9);
+ spawn.bodyRect(5582.1, 1061.7, 110, 70, 0.9);
+ //spawn.bodyRect(5582.1, 961.7, 50, 30, 0.9);
+
+
+
+
+ // spawn.randomSmallMob(1300, -70);
+ // spawn.randomSmallMob(1300, -70);
+ // spawn.randomSmallMob(1300, -70);
+ // spawn.randomSmallMob(1300, -70);
+
+ // powerUps.spawnStartingPowerUps(1475, -1175);
+ // spawn.debris(750, -2200, 3700, 16); //16 debris per level
+ // spawn.bodyRect(1540, -1110, 300, 25, 0.9);
+ // spawn.randomSmallMob(1300, -70);
+ // spawn.randomMob(2650, -975, 0.8);
+ // spawn.randomGroup(1700, -900, 0.4);
+ // if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300);
+ // spawn.secondaryBossChance(100, -1500)
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ dungeon() {
+ let destroyed = false;
+ const door = level.door(2650, -825, 50, 250, 250, 10);
+ const elevator = level.elevator(-11050, -650, 450, 75, -2975, 0.003, { up: 0.1, down: 0.1 })
+ const slimePit = level.hazard(-4775, -350, 1975, 175);
+ const boost = level.boost(137.5, -600, 75, 25);
+ let base = Matter.Bodies.rectangle(-4375, -1000, 100, 100, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let left = Matter.Bodies.rectangle(-4375 + 50, -1000 - 50, 50, 50, {//not actually left/right
+ density: 0.05,
+ isNotHoldable: true,
+ isStatic: false
+ });
+ let right = Matter.Bodies.rectangle(-4375 - 50, -1000 - 50, 50, 50, {
+ density: 0.05,
+ isNotHoldable: true,
+ isStatic: false
+ });
+ let left2 = Matter.Bodies.rectangle(-4375 - 50, -1000 + 50, 50, 50, {
+ density: 0.05,
+ isNotHoldable: true,
+ isStatic: false
+ });
+ let right2 = Matter.Bodies.rectangle(-4375 + 50, -1000 + 50, 50, 50, {
+ density: 0.05,
+ isNotHoldable: true,
+ isStatic: false
+ });
+ dong = Matter.Body.create({
+ parts: [base, left, right, left2, right2]
+ });
+ body[body.length] = base;
+ body[body.length] = left;
+ body[body.length] = right;
+ body[body.length] = left2;
+ body[body.length] = right2;
+ Matter.Composite.add(engine.world, dong)
+ Matter.Composite.add(engine.world, Constraint.create({
+ pointA: { x: -3825, y: -975 },
+ bodyB: dong,
+ stiffness: 0.2,
+ damping: 0.1
+ }));
+ composite[composite.length] = dong;
+ setTimeout(function () {
+ dong.collisionFilter.category = cat.body;
+ dong.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mobBullet | cat.mob //| cat.map
+ }, 1000);
+ level.custom = () => {
+ ctx.save()
+ ctx.beginPath()
+ ctx.fillStyle = "#80808077";
+ ctx.strokeStyle = "#80808022";
+ ctx.fillRect(225, -1025, 2400, 450);
+ ctx.fillRect(-2950, -1025, 3100, 450);
+ ctx.fillRect(-7050, -1025, 2400, 450);
+ ctx.fillRect(-10575, -3975, 4525, 1025);
+ ctx.fillRect(-4650, -1700, 1700, 1100);
+ ctx.fillRect(-11150, -3575, 575, 3050);
+ ctx.fillRect(-11900, -1000, 750, 475);
+ ctx.fill()
+ ctx.stroke()
+ ctx.restore()
+ ctx.save()
+ ctx.beginPath()
+ ctx.fillStyle = "#d8dadf";
+ ctx.strokeStyle = "#d8dadf";
+ ctx.moveTo(-2950, -600);
+ ctx.lineTo(-3730, -1725);
+ ctx.lineTo(-3730, -600);
+
+ ctx.moveTo(-4650, -600);
+ ctx.lineTo(-3925, -1725);
+ ctx.lineTo(-3925, -575);
+
+ ctx.moveTo(-10575, -3425); //NE section
+ ctx.lineTo(-10100, -2975);
+ ctx.lineTo(-10575, -2975);
+
+ // ctx.moveTo(-7625, -3800);
+ // ctx.lineTo(-6750, -2975);
+ // ctx.lineTo(-7625, -2975);
+
+ ctx.moveTo(-7975, -2975);
+ ctx.lineTo(-7625, -3800);
+ ctx.lineTo(-7350, -2950);
+
+ ctx.moveTo(-6750, -2975);
+ ctx.lineTo(-7075, -3800);
+ ctx.lineTo(-7350, -2950);
+
+ // ctx.moveTo(-7975, -2975);
+ // ctx.lineTo(-7075, -3800);
+ // ctx.lineTo(-7075, -2975);
+
+ ctx.moveTo(-11900, -950);
+ ctx.lineTo(-11900, -550);
+ ctx.lineTo(-11500, -550);
+
+ ctx.fillRect(-3925, -1675, 200, 1075);
+ ctx.fillRect(-7625, -3800, 550, 875);
+ ctx.clearRect(-10600, -4000, 525, 475);
+ ctx.clearRect(-10100, -4000, 500, 300);
+ ctx.clearRect(-9625, -4000, 500, 175);
+ ctx.fillRect(-11125, -3600, 550, 50);
+ ctx.fillRect(-10600, -3400, 50, 425);
+ ctx.fillRect(-11925, -925, 45, 375);
+ ctx.fillRect(-3950, -1675, 75, 1100);
+ ctx.fillRect(-3925, -625, 950, 50);
+ ctx.fillRect(-4650, -600, 1700, 375);
+ ctx.fillRect(-14550, -2400, 2650, 2050);
+ //ctx.clearRect(-11050, -3000, 475, 50);
+
+ ctx.moveTo(-11150, -3575);
+ ctx.lineTo(-10575, -2150);
+ ctx.lineTo(-10575, -3575);
+
+ ctx.stroke()
+ ctx.fill()
+ ctx.restore()
+ boost.query()
+ slimePit.query()
+ if (Matter.Query.collides(dong, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ const dmg = 0.05 * Math.min(simulation.dmgScale, simulation.difficulty);
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: dong.position.x,
+ y: dong.position.y,
+ radius: Math.sqrt(dmg) * 200,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ }
+ for (let i = 0; i < mob.length; i++) {
+ if (Matter.Query.collides(dong, [mob[i]]).length > 0) {
+ const dmg = 1;
+ mob[i].damage(dmg, true);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: dong.position.x,
+ y: dong.position.y,
+ radius: Math.sqrt(dmg) * 50,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ break
+ }
+ }
+ level.exit.drawAndCheck();
+ ctx.beginPath()
+ ctx.fillStyle = '#68686822';
+ ctx.fillRect(-25, -2175, 100, 200);
+ ctx.fill()
+ ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
+ ctx.moveTo(-3825, -975)
+ ctx.lineTo(dong.position.x, dong.position.y)
+ ctx.stroke();
+ ctx.setLineDash([]);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: dong.position.x,
+ y: dong.position.y,
+ radius: 10,
+ color: color.block,
+ time: 20
+ });
+ ctx.beginPath()
+ ctx.fillStyle = `rgba(68,68,68, ${3 * Math.sin(simulation.cycle * 0.015)})`
+ ctx.fillRect(-3000, -2175, 175, 25);
+ ctx.fillRect(-2850, -2300, 25, 150);
+ ctx.fillRect(-3000, -2300, 175, 25);
+ ctx.fillRect(-3000, -2425, 25, 150);
+ ctx.fillRect(-3000, -2425, 175, 25);
+ ctx.fill()
+ ctx.fillStyle = `rgba(68,68,68, ${5 * Math.sin(simulation.cycle * 0.015)})`
+ ctx.fillRect(-2725, -2425, 25, 275);
+ ctx.fillRect(-2725, -2425, 175, 25);
+ ctx.fillRect(-2575, -2425, 25, 275);
+ ctx.fillRect(-2725, -2300, 175, 25);
+ ctx.fill()
+ ctx.fillStyle = `rgba(68,68,68, ${7 * Math.sin(simulation.cycle * 0.015)})`
+ ctx.fillRect(-2450, -2425, 25, 275);
+ ctx.fillRect(-2450, -2175, 175, 25);
+ ctx.fill()
+ ctx.stroke();
+ ctx.fillStyle = `#00FFFF22`;
+ ctx.fillRect(-7650, -2975 - 100, 600, 2375 + 100)
+ ctx.fill()
+ ctx.fillStyle = `#00FFFF66`
+ ctx.fillRect(-7650 + Math.floor(Math.random() * 600), -2975 - 100, 5, 2375 + 100)
+ ctx.fillRect(-7650 + Math.floor(Math.random() * 600), -2975 - 100, 5, 2375 + 100)
+ ctx.fillStyle = `rgba(68, 68, 68)`
+ ctx.fillRect(-7675, -3075, 50, 125);
+ ctx.fillRect(-7075, -3075, 50, 125);
+ ctx.fillRect(-7725, -3025, 75, 75);
+ ctx.fillRect(-7050, -3025, 75, 75);
+ ctx.fill()
+ for (let i = 0, len = body.length; i < len; ++i) { //push blocks away vertically
+ if (body[i].position.x > -7625 && body[i].position.x < -7075 && body[i].position.y > -2975 - 100 && body[i].position.y < -625) {
+ body[i].force.y -= simulation.g * body[i].mass + 0.012;
+ }
+ }
+ for (let i = 0, len = bullet.length; i < len; ++i) { //push bullets away vertically
+ if (bullet[i].position.x > -7625 && bullet[i].position.x < -7075 && bullet[i].position.y > -2975 - 100 && bullet[i].position.y < -625) {
+ bullet[i].force.y -= simulation.g * bullet[i].mass;
+ }
+ }
+ for (let i = 0, len = powerUp.length; i < len; ++i) { //push powerups away vertically
+ if (powerUp[i].position.x > -7625 && powerUp[i].position.x < -7075 && powerUp[i].position.y > -2975 - 100 && powerUp[i].position.y < -625) {
+ powerUp[i].force.y -= simulation.g * powerUp[i].mass + 0.12;
+ }
+ }
+ for (let i = 0, len = mob.length; i < len; ++i) { //push mobs away vertically
+ if (mob[i].position.x > -7625 && mob[i].position.x < -7075 && mob[i].position.y > -2975 - 100 && mob[i].position.y < -625) {
+ mob[i].force.y -= simulation.g * mob[i].mass + 0.0012;
+ }
+ }
+ if (m.pos.x > -7625 && m.pos.x < -7075 && m.pos.y > -2975 - 100 && m.pos.y < -625) {
+ player.force.y -= m.mass * simulation.g + (input.down ? 0 : 0.012 * 2);
+
+ }
+ elevator.move()
+ };
+ level.setPosToSpawn(30, -2000); //normal spawn
+ level.exit.x = 2775;
+ level.exit.y = -650;
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom + 800)
+ document.body.style.backgroundColor = "#d8dadf";
+ spawn.mapRect(-225, -1950, 350, 75);
+ spawn.mapRect(225, -1950, 50, 75);
+ spawn.mapRect(-250, -2025, 50, 150);
+ spawn.mapRect(250, -2025, 50, 150);
+ spawn.mapRect(-250, -2250, 50, 125);
+ spawn.mapRect(-225, -2325, 500, 100);
+ spawn.mapRect(250, -2250, 50, 125);
+ spawn.mapRect(-100, -2400, 250, 100);
+ spawn.mapRect(-25, -2475, 100, 100);
+ spawn.mapRect(125, -2350, 50, 50);
+ spawn.mapRect(-125, -2350, 50, 50);
+ spawn.mapRect(-50, -2425, 50, 50);
+ spawn.mapRect(50, -2425, 50, 50);
+ spawn.mapRect(-250, -2350, 50, 50);
+ spawn.mapRect(250, -2350, 50, 50);
+ spawn.mapRect(-75, -1975, 200, 50);
+ spawn.mapRect(-50, -2000, 150, 50);
+ spawn.mapRect(100, -1950, 50, 75);
+ spawn.mapRect(-75, -2250, 200, 50);
+ spawn.mapRect(-50, -2225, 150, 50);
+ spawn.mapRect(-2950, -1900, 3100, 900);
+ spawn.mapRect(225, -1900, 2875, 900);
+ spawn.mapRect(-2950, -600, 6050, 450);
+ spawn.mapRect(-3050, -500, 200, 350);
+ spawn.mapRect(-3150, -400, 200, 250);
+ spawn.mapRect(-3250, -300, 200, 150);
+ spawn.mapRect(2950, -1050, 150, 500);
+ spawn.mapRect(-4675, -1900, 1825, 200);
+ spawn.mapRect(-5325, -1900, 675, 900);
+ spawn.mapRect(-5325, -250, 2100, 100);
+ spawn.mapRect(-5325, -600, 675, 450); // -
+ spawn.mapRect(-4700, -500, 150, 350);
+ spawn.mapRect(-4650, -400, 200, 250);
+ spawn.mapRect(-4550, -300, 200, 150);
+ spawn.mapRect(-3875, -1025, 100, 100);
+ spawn.mapRect(-3800, -1050, 50, 50);
+ spawn.mapRect(-3900, -1050, 50, 50);
+ spawn.mapRect(-3800, -950, 50, 50);
+ spawn.mapRect(-3900, -950, 50, 50);
+ spawn.mapRect(-6925, -1175, 1700, 175);
+ spawn.mapRect(-6925, -600, 1725, 175);
+ spawn.mapRect(-7700, -600, 800, 425);// -
+ spawn.mapRect(-7800, -2950, 175, 2775);
+ spawn.mapRect(-7075, -2950, 175, 1950);
+ spawn.mapRect(-9150, -2975, 1525, 175);
+ spawn.mapRect(-7075, -2975, 1150, 175);
+ spawn.mapRect(-6100, -3900, 175, 1100);
+ spawn.mapRect(-9150, -3975, 3225, 175);
+ spawn.mapRect(-9175, -3850, 75, 75);
+ spawn.mapRect(-9625, -3825, 500, 150);
+ spawn.mapRect(-9650, -3725, 75, 75);
+ spawn.mapRect(-10100, -3700, 500, 150);
+ spawn.mapRect(-10100, -2975, 975, 175);
+ spawn.mapRect(-10125, -3600, 75, 75);
+ spawn.mapRect(-10575, -3575, 500, 150);
+ spawn.mapRect(-10575, -2975, 500, 175);
+ spawn.mapRect(-11325, -2975, 250, 175);
+ spawn.mapRect(-11325, -3575, 175, 775);
+ // spawn.mapRect(-11325, -3575, 800, 150);
+ spawn.mapRect(-11225, -2975, 150, 2000);
+ spawn.mapRect(-10575, -2975, 150, 2500);
+ spawn.mapRect(-11650, -550, 1225, 150);
+ spawn.mapRect(-11650, -1100, 575, 150);
+ spawn.mapRect(-14675, -2525, 2925, 150);
+ spawn.mapRect(-11900, -2525, 150, 1575);
+ spawn.mapRect(-11850, -1100, 250, 150);
+ spawn.mapRect(-11875, -550, 275, 150);
+ spawn.mapRect(-11900, -550, 150, 350);
+ spawn.mapRect(-14675, -2525, 150, 2300);
+ spawn.mapRect(-14675, -375, 2925, 175);
+ spawn.mapRect(2725, -625, 250, 50);
+ spawn.mapRect(2625, -1025, 100, 225);
+ spawn.mapRect(2700, -1025, 300, 125);
+ spawn.mapRect(2625, -612.5, 125, 50);
+ spawn.mapRect(-3950, -1725, 250, 50);
+ spawn.mapRect(-7650, -3825, 600, 50);
+ spawn.mapRect(-13900, -2400, 200, 50);
+ spawn.mapVertex(-11957, -430, '-175 175 0 175 0 0');
+ spawn.mapVertex(-14470, -430, '175 175 0 175 0 0');
+ spawn.mapVertex(-11957, -2319, '-175 -175 0 -175 0 0');
+ spawn.mapVertex(-14470, -2319, '0 0 0 -175 175 -175');
+ //spawn.mapRect(-13900, -2150, 1375, 125);
+ const sword = function () { //the ultimate blade of las destruction
+ mobs.spawn(player.position.x, player.position.y, 5, 30, "transparent");
+ let me = mob[mob.length - 1];
+ Matter.Body.setDensity(me, 1);
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position);
+ me.collisionFilter.category = cat.bullet;
+ me.collisionFilter.mask = cat.mob | cat.mobBullet;
+ me.isDropPowerUp = false;
+ me.isShielded = true;
+ me.showHealthBar = false;
+ me.isUnblockable = true;
+ me.leaveBody = false;
+ me.isBadTarget = true;
+ me.stroke = "transparent";
+ me.isSword = true;
+ let index = 0;
+ let radius = 50;
+ me.do = function () {
+ this.health = Infinity;//just in case
+ for (let i = 0; i < mob.length; i++) {
+ if (Matter.Query.collides(this, [mob[i]]).length > 0 && !mob[i].isSword) {
+ const dmg = 0.25;//do not nerf
+ mob[i].damage(dmg, true);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: mob[i].position.x,
+ y: mob[i].position.y,
+ radius: Math.sqrt(dmg) * 50,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ break
+ }
+ }
+ Matter.Body.setPosition(this, {
+ x: player.position.x + Math.cos(m.angle) * 100,
+ y: player.position.y - (input.down ? 0 : 30) + Math.sin(m.angle) * 100
+ })
+ Matter.Body.setAngle(this, m.angle + Math.PI * 2);
+ const setNoseShape = () => {
+ const mag = radius + radius * 10;
+ this.vertices[2].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[2].y = this.position.y + Math.sin(this.angle) * mag;
+ this.vertices[4].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[4].y = this.position.y + Math.sin(this.angle) * mag;
+ this.vertices[0].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[0].y = this.position.y + Math.sin(this.angle) * mag;
+ };
+ const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[2], this.position)), radius * 100)
+ const spike2 = Vector.mult(Vector.normalise(Vector.sub(this.vertices[4], this.position)), radius * 500)
+ const spike3 = Vector.mult(Vector.normalise(Vector.sub(this.vertices[0], this.position)), radius * 500)
+ this.vertices[2].x = this.position.x + spike.x / 100
+ this.vertices[2].y = this.position.y + spike.y / 100
+ this.vertices[4].x = this.position.x + spike2.x / 75
+ this.vertices[4].y = this.position.y + spike2.y / 75
+ this.vertices[0].x = this.position.x + spike3.x / 75
+ this.vertices[0].y = this.position.y + spike3.y / 75
+ if (index == 0) {
+ setNoseShape();
+ index++;
+ }
+ ctx.save()
+ ctx.beginPath();
+ const vertices = this.vertices;
+ ctx.lineWidth = 100;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ const gradient = ctx.createRadialGradient(this.position.x, this.position.y, 15, this.position.x, this.position.y, Math.abs(275 * Math.sin(simulation.cycle / 50)) + 15);
+ // Add three color stops
+ gradient.addColorStop(0, m.eyeFillColor);
+ gradient.addColorStop(0.9, "white");
+ gradient.addColorStop(1, "darkgray");
+ ctx.fillStyle = gradient;
+ ctx.strokeStyle = "transparent";
+ ctx.shadowBlur = 10;
+ ctx.shadowColor = m.eyeFillColor;
+ ctx.fill();
+ ctx.stroke();
+ ctx.restore()
+
+ const Dx = Math.cos(m.angle);
+ const Dy = Math.sin(m.angle);
+ let xElec = this.position.x + 10 * Dx;
+ let yElec = this.position.y + 10 * Dy;
+ ctx.beginPath();
+ ctx.moveTo(xElec, yElec);
+ const step = 40
+ for (let i = 0; i < 6; i++) {
+ xElec += step * (Dx + 1.5 * (Math.random() - 0.5))
+ yElec += step * (Dy + 1.5 * (Math.random() - 0.5))
+ ctx.lineTo(xElec, yElec);
+ }
+ ctx.strokeStyle = m.eyeFillColor;
+ ctx.lineWidth = 1.5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ if (this.alive && m.energy > 0) {
+ const gradient = ctx.createRadialGradient(this.position.x, this.position.y, 0, this.position.x, this.position.y, Math.abs(20 * Math.cos(simulation.cycle / 50)));
+ // Add three color stops
+ gradient.addColorStop(0, m.eyeFillColor);
+ gradient.addColorStop(0.9, "white");
+ gradient.addColorStop(1, "gray");
+ ctx.save()
+ ctx.beginPath()
+ ctx.moveTo(this.position.x, this.position.y)
+ ctx.arc(this.position.x, this.position.y, 20, 0, 2 * Math.PI)
+ ctx.fillStyle = gradient;
+ ctx.strokeStyle = "transparent";
+ ctx.shadowBlur = 10;
+ ctx.shadowColor = m.eyeFillColor;
+ ctx.fill()
+ ctx.stroke()
+ ctx.restore()
+ m.energy -= 0.002;
+
+ ctx.save()
+ ctx.translate(this.vertices[2].x, this.vertices[2].y)
+ ctx.rotate(m.angle + Math.PI / 2)
+ ctx.beginPath()
+ ctx.font = "16px Arial";
+ ctx.fillStyle = "black";
+ ctx.strokeStyle = "black";
+ // ctx.fillText("Θ", 0,0 - 110)
+ // ctx.fillText("ά", 0,15 - 110)
+ // ctx.fillText("ν", 0,30 - 110)
+ // ctx.fillText("α", 0,45 - 110)
+ // ctx.fillText("τ", 0,60 - 110)
+ // ctx.fillText("ο", 0,75 - 110)
+ // ctx.fillText("ς", 0,90 - 110)
+ ctx.fillText("Ω", 0, 55)
+ ctx.fill()
+ ctx.stroke()
+ ctx.restore()
+
+ simulation.drawList.push({
+ x: this.position.x + Math.floor(Math.random() * 300 - Math.random() * 300),
+ y: this.position.y + Math.floor(Math.random() * 300 - Math.random() * 300),
+ radius: 2,
+ color: m.eyeFillColor,
+ time: simulation.drawTime
+ });
+ } else {
+ this.death()
+ powerUps.activated = false
+ }
+ }
+ }
+ //setTimeout(function() {sword();}, 100);
+ const wire = function () {
+ const breakingPoint = -1600;
+ const spawnx = -13800 + Math.floor(Math.random() * 100 - Math.random() * 100);
+ mobs.spawn(spawnx, -2375, 0, 2, "transparent");
+ let me = mob[mob.length - 1];
+ let boss = mob[0];
+ me.collisionFilter.category = cat.body;
+ me.collisionFilter.mask = cat.map;
+ me.g = 0.0003; //required for gravity
+ me.restitution = 0;
+ me.stroke = "transparent"
+ me.freeOfWires = false;
+ me.frictionAir = 0.01;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.isBadTarget = true;
+ me.isUnblockable = true;
+ const wireX = spawnx;
+ const wireY = -2375;
+ //const randomw = Math.floor(Math.random() * 100 - Math.random() * 100);
+ const width = Math.abs(10 + Math.floor(Math.random() * 10 - Math.random() * 10));
+ const randomx = Math.floor(30 * Math.random() - 30 * Math.random());
+ const randomy = Math.floor(10 * Math.random() - 10 * Math.random())
+ me.do = function () {
+ if (this.freeOfWires) {
+ this.gravity();
+ } else {
+ if (boss.position.y > breakingPoint) {
+ this.freeOfWires = true;
+ this.force.y -= -0.0006;
+ this.force.x += Math.random() * boss.velocity.x / 10000;
+ this.fill = "#111";
+ }
+ //move mob to mob
+ Matter.Body.setPosition(this, {
+ x: boss.position.x + randomx,
+ y: boss.position.y + randomy
+ })
+ }
+ //draw wire
+ ctx.beginPath();
+ ctx.moveTo(wireX, wireY);
+ ctx.quadraticCurveTo(wireX, -100, this.position.x, this.position.y);
+ ctx.lineWidth = width;
+ ctx.lineCap = "butt";
+ ctx.strokeStyle = "#111";
+ ctx.stroke();
+ ctx.lineCap = "round";
+ };
+ }
+
+ const ball = function (x, y, radius = 11 * tech.bulletSize, sides = 70) {//superball //also, why is it called superballs?
+ mobs.spawn(x, y, sides, radius, "rgba(0,0,0)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.onHit = function () {
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: 20,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ };
+ Matter.Body.setDensity(me, 0.00001); //normal is 0.001
+ me.timeLeft = 500;
+ me.friction = 0;
+ me.restitution = 1;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ //me.inertia = Infinity;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.map | cat.body;
+ let index = 0;
+ me.do = function () {
+ this.timeLimit();
+ this.alwaysSeePlayer()
+ this.force.y += this.mass * 0.0012;
+ }
+ }
+ const normalBullet = function (x, y, radius = 9, sides = 3) {
+ //bullets
+ mobs.spawn(x, y, sides, radius, "rgba(0,0,0)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position);
+ me.onHit = function () {
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: 20,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ };
+ Matter.Body.setDensity(me, 0.00004); //normal is 0.001
+ me.timeLeft = 220;
+ me.frictionAir = -0.01;
+ me.restitution = -1;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ //me.inertia = Infinity;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = null;
+ let index = 0;
+ me.do = function () {
+ this.timeLimit();
+ this.alwaysSeePlayer()
+ const setNoseShape = () => {
+ const mag = this.radius + this.radius * 10;
+ this.vertices[1].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[1].y = this.position.y + Math.sin(this.angle) * mag;
+ const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
+ Matter.Body.setAngle(this, angle);
+ };
+ const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), radius * 1000)
+ this.vertices[1].x = this.position.x + spike.x / 100
+ this.vertices[1].y = this.position.y + spike.y / 100
+ if (index == 0) {
+ setNoseShape();
+ index++;
+ }
+ if (Matter.Query.collides(this, map).length > 0 || Matter.Query.collides(this, body).length > 0) {
+ const slow = 0.69 //im sorry it looks cool though
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * slow,
+ y: this.velocity.y * slow
+ });
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: 10,
+ color: '#000000',
+ time: simulation.drawTime
+ });
+ if (this.velocity.x == 0 && this.velocity.y == 0) {
+ this.death();
+ }
+ this.frictionAir += 0.0001;
+ Matter.Body.setAngularVelocity(this, 0)
+ }
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles // I wasnt gonna add this but since ya'll would have killed me if I didn't I added this
+ const dmg = 0.013 * simulation.dmgScale;
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: Math.sqrt(dmg) * 200,
+ color: '#000000',
+ time: simulation.drawTime
+ });
+ }
+ };
+ }
+ const foamBullet = function (x, y, radius = 9, sides = 70) { //bullets
+ mobs.spawn(x, y, sides, radius, "rgb(0,0,0)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ Matter.Body.setDensity(me, 0.00005); //normal is 0.001
+ me.timeLeft = 120;
+ // me.g = 0.0005; //required if using this.gravity
+ me.accelMag = 0.00006;
+ me.isVerticesChange = true
+ me.delay = 360 * simulation.CDScale;
+ me.spikeVertex = 0;
+ me.spikeLength = 0;
+ me.isSpikeGrowing = false;
+ me.spikeGrowth = 0;
+ me.isSpikeReset = false;
+ me.frictionAir = 0;
+ me.restitution = 0;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.isUnblockable = true;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.body //| cat.bullet;// | cat.player;
+ me.do = function () {
+ if (this.distanceToPlayer2() < 40000) {
+ this.force = Vector.mult(Vector.normalise(Vector.sub(player.position, this.position)), this.mass * 0.004)
+ const slow = 0.99999999999999999;
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * slow,
+ y: this.velocity.y * slow
+ });
+ }
+ // this.gravity();
+ this.timeLimit();
+ // for (let i = 0, len = this.vertices.length; i < len; i++) {
+ // const dist = Vector.sub(this.seePlayer.position, this.vertices[i]);
+ // const distMag = Vector.magnitude(dist);
+ // const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[i], this.position)), radius * distMag)
+ // this.vertices[i].x = this.position.x + spike.x / 100
+ // this.vertices[i].y = this.position.y + spike.y / 100
+ // }
+ if (this.radius < 50) {
+ const scale = 1.05;
+ Matter.Body.scale(this, scale, scale);
+ this.radius *= scale;
+ }
+ if (Matter.Query.collides(this, map).length > 0 || Matter.Query.collides(this, body).length > 0 && this.speed < 10) {
+ const slow = 0.97
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * slow,
+ y: this.velocity.y * slow
+ });
+ const SCALE = 0.9
+ Matter.Body.scale(this, SCALE, SCALE);
+ this.radius *= SCALE;
+ if (this.radius < 1) {
+ this.death()
+ }
+ } else {
+ this.attach();
+ }
+
+ };
+ me.attach = function () {
+ if (Matter.Query.collides(this, [player]).length > 0) {
+ Matter.Body.setPosition(this, player.position)
+ if (player.speed > 2.5) Matter.Body.setVelocity(player, Vector.mult(player.velocity, 0.94))
+ Matter.Body.setAngularVelocity(player, player.angularVelocity * 0.9);
+ m.damage(0.00003); //balanced? not sure
+ }
+ }
+ };
+
+ const orbital = function (who, radius, phase, speed, radius2) {//basically orbitBot
+ mobs.spawn(who.position.x, who.position.y, 8, 12, "rgba(0,0,0, 1)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ Matter.Body.setDensity(me, 0.01); //normal is 0.001
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.showHealthBar = false;
+ me.isOrbital = true;
+ me.isShielded = true
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.bullet; //cat.player | cat.map | cat.body
+ me.do = function () {
+ //if host is gone
+ if (!who || !who.alive) {
+ this.death();
+ return
+ }
+ //set orbit
+ const time = simulation.cycle * speed + phase
+ const orbit = {
+ x: Math.cos(time),
+ y: Math.sin(time)
+ }
+ Matter.Body.setPosition(this, Vector.add(Vector.add(who.position, who.velocity), Vector.mult(orbit, radius + radius2)))
+ //damage player
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ const dmg = 0.013 * simulation.dmgScale
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: Math.sqrt(dmg) * 200,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ //this.death();
+ }
+ };
+ }
+ const sniper = function (x, y, radius = 30) {
+ mobs.spawn(x, y, 8, radius, '#00000000');
+ let me = mob[mob.length - 1];
+ me.accelMag = 0.0003
+ me.stroke = 'transparent';
+ //me.isBoss = true;
+ me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.seeAtDistance2 = 20000000 //14000 vision range
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position);
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.showHealthBar = false
+ Matter.Body.setDensity(me, 0.01)
+ me.fireDir = { x: 0, y: 0 }
+ me.seePlayerFreq = 0
+ me.repulsionRange = 400000 + radius * radius;
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob | cat.mobBullet
+ me.do = function () {
+ this.seePlayerCheck();
+ this.attraction();
+ this.repulsion();
+ this.search()
+ if (this.seePlayer.recall) {
+ const h = this.radius * 0.3;
+ const w = this.radius * 2;
+ const x = this.position.x - w / 2;
+ const y = this.position.y - w * 0.7;
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(x, y, w, h);
+ ctx.fillStyle = "rgba(0,255,255,0.7)";
+ ctx.fillRect(x, y, w * this.health, h);
+ }
+ if (this.health < 1) {
+ this.health += 0.0005; //regen
+ }
+ ctx.save()
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ if (this.seePlayer.recall > 0 && this.distanceToPlayer2() > this.repulsionRange) {
+ var grd2 = ctx.createLinearGradient(0, 0, -150, 0);
+ // grd2.addColorStop(0, 'rgba(255, 255, 155, 0.8)');
+ // grd2.addColorStop(1, 'rgba(255, 200, 0, 0.1)');
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(-18, -25);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(-18, 25);
+ ctx.lineTo(-50 - 100 * Math.random(), 0);
+ ctx.fill();
+ } else if (this.distanceToPlayer2() < this.repulsionRange) {
+ var grd2 = ctx.createLinearGradient(0, 0, 80, 0);
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(20, -16);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(20, 16);
+ ctx.lineTo(35 + 43 * Math.random(), 0);
+ ctx.fill();
+ }
+ ctx.restore()
+ ctx.save()
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.beginPath(); //eye
+ ctx.arc(15, 0, 3.5, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(255, 0, 0, ${this.health * this.health})`;
+ ctx.fill()
+ ctx.restore()
+ //set direction to turn to fire
+ if (this.seePlayer.recall && !(simulation.cycle % 30)) {
+ this.seePlayer.recall -= 10;
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ spawn.sniperBullet(this.position.x, this.position.y, 7 + Math.ceil(this.radius / 15), 5);
+ const v = 10 + 8 * simulation.accelScale;
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ }
+ };
+ }
+ const laserEM = function (x, y, radius = 30) {
+ mobs.spawn(x, y, 8, radius, '#00000000');
+ let me = mob[mob.length - 1];
+ me.accelMag = 0.0003
+ me.stroke = 'transparent';
+ //me.isBoss = true;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.seeAtDistance2 = 20000000 //14000 vision range
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position);
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.showHealthBar = false
+ Matter.Body.setDensity(me, 0.01)
+ me.seePlayerFreq = 0
+ me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position;
+ me.swordDamage = 0.025 * simulation.dmgScale
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob | cat.mobBullet
+ me.repulsionRange = 50000;
+ me.do = function () {
+ this.repulsion();
+ this.search()
+ if (this.seePlayer.recall) {
+ const h = this.radius * 0.3;
+ const w = this.radius * 2;
+ const x = this.position.x - w / 2;
+ const y = this.position.y - w * 0.7;
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(x, y, w, h);
+ ctx.fillStyle = "rgba(0,255,255,0.7)";
+ ctx.fillRect(x, y, w * this.health, h);
+ }
+ if (this.health < 1) {
+ this.health += 0.0005; //regen
+ }
+ if (this.seePlayer.recall) {
+ this.laserSword(this.position, Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x), 500 * Math.random());
+ }
+ ctx.save()
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ if (this.seePlayer.recall > 0 && this.distanceToPlayer2() > this.repulsionRange) {
+ var grd2 = ctx.createLinearGradient(0, 0, -150, 0);
+ // grd2.addColorStop(0, 'rgba(255, 255, 155, 0.8)');
+ // grd2.addColorStop(1, 'rgba(255, 200, 0, 0.1)');
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(-18, -25);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(-18, 25);
+ ctx.lineTo(-50 - 100 * Math.random(), 0);
+ ctx.fill();
+ } else if (this.distanceToPlayer2() < this.repulsionRange) {
+ var grd2 = ctx.createLinearGradient(0, 0, 80, 0);
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(20, -16);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(20, 16);
+ ctx.lineTo(35 + 43 * Math.random(), 0);
+ ctx.fill();
+ }
+ ctx.restore()
+ ctx.save()
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.beginPath(); //eye
+ ctx.arc(15, 0, 3.5, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(255, 0, 0, ${this.health * this.health})`;
+ ctx.fill()
+ ctx.restore()
+ this.seePlayerCheck();
+ this.attraction();
+ }
+ me.laserSword = function (where, angle, length) {
+ const sub = Vector.sub(this.seePlayer.position, this.position)
+ const unit = Vector.normalise(sub)
+ const path = [{
+ x: this.position.x + 20 * Math.cos(this.angle),
+ y: this.position.y + 20 * Math.sin(this.angle)
+ },
+ {
+ x: this.position.x + (120 + 400) * Math.sqrt(Math.random()) * Math.cos(this.angle),
+ y: this.position.y + (120 + 400) * Math.sqrt(Math.random()) * Math.sin(this.angle)
+ }
+ ];
+ this.seePlayer.recall -= 3;
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: vertices[j], v2: vertices[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: vertices[0], v2: vertices[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + length * Math.cos(angle), y: where.y + length * Math.sin(angle) };
+ // vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [player]);
+ if (best.who && (best.who === player) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "#50f";
+ ctx.lineWidth = 1.5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ ctx.lineWidth = 20;
+ ctx.strokeStyle = "rgba(80,0,255,0.07)";
+ ctx.stroke(); // Draw it
+
+ const Dx = Math.cos(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x));
+ const Dy = Math.sin(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x));
+ let xElec = this.position.x + 40 * Dx;
+ let yElec = this.position.y + 40 * Dy;
+ ctx.beginPath();
+ ctx.moveTo(xElec, yElec);
+ const step = 40
+ for (let i = 0; i < 6; i++) {
+ xElec += step * (Dx + 1.5 * (Math.random() - 0.5))
+ yElec += step * (Dy + 1.5 * (Math.random() - 0.5))
+ ctx.lineTo(xElec, yElec);
+ }
+ ctx.strokeStyle = "#50f";
+ ctx.lineWidth = 1.5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ };
+ if (powerUps.pass == undefined) {
+ let pass = { pass: true, activated: false };
+ Object.assign(powerUps, pass)
+ }
+ const loadOut = {
+ loadOut: {
+ name: "loadOut",
+ color: "#000000", //"hsl(248,100%,65%)",
+ size() { return 40 },
+ effect() {
+ if (m.alive) {
+ // tech.damage *= 2;
+ let text = "";
+ if (!tech.isSuperDeterminism) { text += `
${tech.isCancelTech ? "?" : "✕"}
`; };
+ text += `
Blessing Of Sal `;
+ text += `
`;
+ text += `
`;
+ text += `
`;
+ if (powerUps.pass == true) {
+ text += `
Press Shift to summon the
Mythical Las Slayer Drains Energy
`;
+ }
+ document.getElementById("choose-grid").innerHTML = text;
+ powerUps.showDraft();//no known bugs ig idk, im keep this as it is
+ }
+ },
+ choose(index) {
+ if (index == 1) {
+ tech.squirrelFx += 0.25;
+ tech.squirrelJump += 0.1;
+ m.setMovement();
+ powerUps.endDraft("buff");
+ } else if (index == 2) {
+ simulation.dmgScale *= 0.95;
+ powerUps.endDraft("buff");
+ } else if (index == 3) {
+ m.dmgScale *= 1.1;
+ powerUps.endDraft("buff");
+ } else if (index == 4) { //sword!
+ powerUps.pass = false;
+ addEventListener("keydown", function (event) {
+ if (event.key == "Shift" && powerUps.activated == false) {
+ sword()
+ powerUps.activated = true;
+ } else if (event.key == "Shift" && powerUps.activated == true) {
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].isSword) {
+ mob[i].death()
+ }
+ powerUps.activated = false;
+ }
+ }
+ })
+ powerUps.endDraft("buff");
+ }
+ }
+ }
+ }
+ Object.assign(powerUps, loadOut)
+ const restoreBoss = function (x, y, radius = 30) {
+ mobs.spawn(x, y, 8, radius, 'transparent');
+ let me = mob[mob.length - 1];
+ me.stroke = 'transparent';
+ let aim = '#FFFFFF';
+ me.accelMag = 0.0006
+ me.isBoss = true;
+ me.restoreBoss = true;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.seeAtDistance2 = 20000000 //14000 vision range
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.showHealthBar = false
+ Matter.Body.setDensity(me, m.maxHealth / (simulation.difficulty < 5 ? 0.5 : simulation.difficulty / simulation.difficultyMode))
+ me.seePlayerFreq = 0
+ me.swordDamage = 0.025 * simulation.dmgScale
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob | cat.mobBullet
+ me.repulsionRange = 500000;
+ me.isDropPowerUp = false;
+ //Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) });
+ let index = 0;
+ me.energy = 1;
+ me.maxEnergy = 1;
+ me.immuneCycle = 0;
+ me.cycle = 0;
+ me.onDeath = function () {
+ powerUps.spawn(this.position.x, this.position.y, "loadOut");
+ }
+ for (let i = 0; i < b.totalBots(); i++) { //normal orbitals look too boring, so...
+ orbital(me, 190 + 130 * tech.isOrbitBotUpgrade, (index / b.totalBots()) * 2 * Math.PI, 0.05, Math.floor(Math.sin(simulation.cycle / 10) * 100)); //who, radius, phase, speed
+ index++;
+ }
+ me.do = function () {
+ this.cycle++;
+ if (this.seePlayer.recall) { //fields
+ if (m.fieldMode == 0 && this.distanceToPlayer2() < 200000) {
+ if (Vector.magnitude(Vector.sub(m.pos, this.position)) - this.radius < m.fieldRange && Matter.Query.ray(map, m.pos, this.position).length === 0) {
+ this.pushM();
+ }
+ this.drawField();
+ // this.repel();
+ }
+ if (m.fieldMode == 2) {
+ if (this.distanceToPlayer2() < 200000) {
+ if (Vector.magnitude(Vector.sub(m.pos, this.position)) - this.radius < m.fieldRange && Matter.Query.ray(map, m.pos, this.position).length === 0) {
+ this.pushM();
+ }
+ this.drawField()
+ }
+ if (tech.isPerfectBrake) { //cap player and bullet speed around restoreBoss //mobs basically can't hit you when you have this, so to make it fair...
+ const wave = Math.cos(m.cycle * 0.022);
+ const range = 200 + 140 * wave + 150 * m.energy
+ const distance = Vector.magnitude(Vector.sub(this.position, m.pos))
+ const cap = this.immuneCycle > this.cycle ? 8 : 4
+ if (distance < range) {
+ if (player.speed > cap && Vector.dot(player.velocity, Vector.sub(this.position, m.pos)) > 0) { // if velocity is directed towards player
+ Matter.Body.setVelocity(player, Vector.mult(Vector.normalise(player.velocity), cap)); //set velocity to cap, but keep the direction
+ }
+ }
+ for (let i = 0; i < bullet.length; i++) {
+ const distance2 = Vector.magnitude(Vector.sub(this.position, bullet[i].position))
+ if (distance2 < range) {
+ if (bullet[i].speed > cap && Vector.dot(bullet[i].velocity, Vector.sub(this.position, bullet[i].position)) > 0) { // if velocity is directed towards player
+ Matter.Body.setVelocity(bullet[i], Vector.mult(Vector.normalise(bullet[i].velocity), cap)); //set velocity to cap, but keep the direction
+ }
+ }
+ }
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, range, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.08)";
+ ctx.fill();
+ }
+ }
+ if (m.fieldMode == 5 && this.distanceToPlayer2() < 200000) {
+ this.laserSword(this.position, Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x), 500 * Math.random());
+ }
+ if (m.fieldMode == 6) {
+ this.timeAttack();
+ }
+ if (m.fieldMode == 9) {
+ if (this.distanceToPlayer2() < 300000) {
+ this.teleportAway() //blink but reversed
+ }
+ }
+ }
+ if (m.immuneCycle > m.cycle) {
+ me.damageReduction = 0;
+ } else {
+ me.damageReduction = 1;
+ }
+ this.repulsion();
+ this.seePlayerCheck();
+ this.attraction();
+ this.lostPlayer();
+ if (this.seePlayer.recall) {
+ const h = this.radius * 0.3;
+ const w = this.radius * 2;
+ const x = this.position.x - w / 2;
+ const y = this.position.y - w * 0.7;
+ ctx.fillStyle = "rgba(10, 10, 10, 0.3)";
+ ctx.fillRect(x, y, w, h);
+ ctx.fillStyle = "rgba(0,0,0,0.7)";
+ ctx.fillRect(x, y, w * this.energy, h);
+ }
+ if (this.health < 1) {
+ this.health += 0.0001; //regen
+ } else if (this.health < 1) {
+ this.health += 0.00005; //reduced regen
+ }
+ if (this.energy < 0) {//energy thingy
+ this.energy = 0;
+ } else if (this.energy > this.maxEnergy) {
+ this.energy = this.maxEnergy;
+ } else if (this.energy < this.maxEnergy) {
+ this.energy += 0.001;
+ }
+ ctx.save()
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ if (this.seePlayer.recall > 0 && this.distanceToPlayer2() > this.repulsionRange) {
+ ctx.globalAlpha = (this.immuneCycle < this.cycle) ? 1 : 0.5
+ var grd2 = ctx.createLinearGradient(0, 0, -150, 0);
+ // grd2.addColorStop(0, 'rgba(255, 255, 155, 0.8)');
+ // grd2.addColorStop(1, 'rgba(255, 200, 0, 0.1)');
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(-18, -25);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(-18, 25);
+ ctx.lineTo(-50 - 100 * Math.random(), 0);
+ ctx.fill();
+ } else if (this.distanceToPlayer2() < this.repulsionRange) {
+ ctx.globalAlpha = (this.immuneCycle < this.cycle) ? 1 : 0.5
+ var grd2 = ctx.createLinearGradient(0, 0, 80, 0);
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(20, -16);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(20, 16);
+ ctx.lineTo(35 + 43 * Math.random(), 0);
+ ctx.fill();
+ }
+ ctx.restore()
+ ctx.save()
+ ctx.globalAlpha = (this.immuneCycle < this.cycle) ? 1 : 0.5
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ if (this.health > 0.5) {
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.beginPath(); //eye
+ ctx.arc(15, 0, 3.5, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(255, 0, 0, ${this.health * this.health})`;
+ ctx.fill()
+ ctx.restore()
+ } else {
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ if (!(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x) > -Math.PI / 2 && Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x) < Math.PI / 2)) ctx.scale(1, -1); //here is the flip
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(2, -6, 7, 0, 2 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(25, -6, 7, 0.25 * Math.PI, 1.6 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(2, -10, 9, 1.25 * Math.PI, 1.75 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(25, -10, 9, 1.25 * Math.PI, 1.4 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(18, 13, 10, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient;
+ ctx.fill();
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(18, 13, 6, 0, 2 * Math.PI);
+ ctx.fillStyle = "#555";
+ ctx.fill();
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(3, -6, 3, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(26, -6, 3, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.stroke();
+ ctx.restore();
+ }
+ if (m.fieldMode == 1) { //render over I think
+ if (this.energy > 0.1) {
+ this.harmonic3Phase();
+ }
+ }
+ if (m.fieldMode == 3) {
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ me.damageReduction = 0.5;
+ me.accelMag = 0.0012;
+ if (!(simulation.cycle % Math.floor(100 + 90 * Math.random() * simulation.CDScale))) {
+ this.diveAttack()
+ }
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, 1000, 0, 2 * Math.PI);
+ ctx.fillStyle = "#f5f5ff";
+ ctx.strokeStyle = "#f5f5ff55";
+ ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
+ ctx.globalCompositeOperation = "difference";
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over";
+ ctx.stroke()
+ ctx.setLineDash([]);
+ } else {
+ me.accelMag = 0.0006;
+ }
+ if (this.immuneCycle > this.cycle) {
+ this.damageReduction = 0;
+ } else {
+ if (m.fieldMode == 3) {
+ this.damageReduction = 0.5;
+ } else {
+ this.damageReduction = 1;
+ }
+ }
+ if (this.seePlayer.recall) { //fields
+ this.gun()
+ }
+ }
+ me.laserSword = function (where, angle, length) {
+ const sub = Vector.sub(this.seePlayer.position, this.position)
+ const unit = Vector.normalise(sub)
+ const path = [{
+ x: this.position.x + 20 * Math.cos(this.angle),
+ y: this.position.y + 20 * Math.sin(this.angle)
+ },
+ {
+ x: this.position.x + (120 + 400) * Math.sqrt(Math.random()) * Math.cos(this.angle),
+ y: this.position.y + (120 + 400) * Math.sqrt(Math.random()) * Math.sin(this.angle)
+ }
+ ];
+ this.seePlayer.recall -= 3;
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: vertices[j], v2: vertices[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: vertices[0], v2: vertices[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + length * Math.cos(angle), y: where.y + length * Math.sin(angle) };
+ // vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [player]);
+ if (best.who && (best.who === player) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(0,0,0,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 1.5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ ctx.lineWidth = 20;
+ ctx.strokeStyle = "rgba(0,0,0,0.07)";
+ ctx.stroke(); // Draw it
+
+ const Dx = Math.cos(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x));
+ const Dy = Math.sin(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x));
+ let xElec = this.position.x + 40 * Dx;
+ let yElec = this.position.y + 40 * Dy;
+ ctx.beginPath();
+ ctx.moveTo(xElec, yElec);
+ const step = 40
+ for (let i = 0; i < 6; i++) {
+ xElec += step * (Dx + 1.5 * (Math.random() - 0.5))
+ yElec += step * (Dy + 1.5 * (Math.random() - 0.5))
+ ctx.lineTo(xElec, yElec);
+ }
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 1.5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ me.drawField = function () {
+ if (m.fieldMode != 2) {
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x)
+ const range = m.fieldRange;
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, range, angle - Math.PI * m.fieldArc, angle + Math.PI * m.fieldArc, false);
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ let eye = 13;
+ if (m.fieldMode == 2) {
+ eye = 30
+ }
+ let aMag = 0.75 * Math.PI * m.fieldArc
+ let a = angle + aMag
+ let cp1x = this.position.x + 0.6 * range * Math.cos(a)
+ let cp1y = this.position.y + 0.6 * range * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, this.position.x + eye * Math.cos(angle), this.position.y + eye * Math.sin(angle))
+ a = angle - aMag
+ cp1x = this.position.x + 0.6 * range * Math.cos(a)
+ cp1y = this.position.y + 0.6 * range * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, this.position.x + 1 * range * Math.cos(angle - Math.PI * m.fieldArc), this.position.y + 1 * range * Math.sin(angle - Math.PI * m.fieldArc))
+ ctx.fill();
+ // ctx.lineTo(this.position.x + eye * Math.cos(angle), this.position.y + eye * Math.sin(angle));
+
+ //draw random lines in field for cool effect
+ let offAngle = angle + 1.7 * Math.PI * m.fieldArc * (Math.random() - 0.5);
+ ctx.beginPath();
+ eye = 15;
+ ctx.moveTo(this.position.x + eye * Math.cos(angle), this.position.y + eye * Math.sin(angle));
+ ctx.lineTo(this.position.x + range * Math.cos(offAngle), this.position.y + range * Math.sin(offAngle));
+ ctx.strokeStyle = "rgba(0,0,0,0.6)";
+ ctx.lineWidth = 1;
+ ctx.stroke();
+ } else {
+ ctx.beginPath();
+ const wave = Math.cos(m.cycle * 0.022);
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x)
+ ctx.arc(this.position.x, this.position.y, m.fieldRange, angle - Math.PI * m.fieldArc, angle + Math.PI * m.fieldArc, false);
+ ctx.lineWidth = 2.5 - 1.5 * wave;
+ ctx.stroke();
+ const curve = 0.57 + 0.04 * wave
+ const aMag = (1 - curve * 1.2) * Math.PI * m.fieldArc
+ let a = angle + aMag
+ let cp1x = this.position.x + curve * m.fieldRange * Math.cos(a)
+ let cp1y = this.position.y + curve * m.fieldRange * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, this.position.x + 30 * Math.cos(angle), this.position.y + 30 * Math.sin(angle))
+ a = angle - aMag
+ cp1x = this.position.x + curve * m.fieldRange * Math.cos(a)
+ cp1y = this.position.y + curve * m.fieldRange * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, this.position.x + 1 * m.fieldRange * Math.cos(angle - Math.PI * m.fieldArc), this.position.y + 1 * m.fieldRange * Math.sin(angle - Math.PI * m.fieldArc))
+ ctx.fill();
+ }
+ }
+ me.pushM = function () {
+ const unit = Vector.normalise(Vector.sub(this.position, player.position))
+ if (tech.blockDmg) {
+ Matter.Body.setVelocity(player, { x: 0.5 * player.velocity.x, y: 0.5 * player.velocity.y });
+ //draw electricity
+ const step = 40
+ ctx.beginPath();
+ for (let i = 0, len = 0.8 * tech.blockDmg; i < len; i++) {
+ let x = this.position.x - 20 * unit.x;
+ let y = this.position.y - 20 * unit.y;
+ ctx.moveTo(x, y);
+ for (let i = 0; i < 8; i++) {
+ x += step * (-unit.x + 1.5 * (Math.random() - 0.5))
+ y += step * (-unit.y + 1.5 * (Math.random() - 0.5))
+ ctx.lineTo(x, y);
+ }
+ }
+ if (m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles
+ m.damage(0.025 * simulation.dmgScale)
+ }
+ ctx.lineWidth = 3;
+ ctx.strokeStyle = "#000";
+ ctx.stroke();
+ }
+ const massRoot = Math.sqrt(Math.min(12, Math.max(0.15, player.mass))); // masses above 12 can start to overcome the push back //idk
+ Matter.Body.setVelocity(player, {
+ x: this.velocity.x - (15 * unit.x) / massRoot,
+ y: this.velocity.y - (15 * unit.y) / massRoot
+ });
+ }
+ me.diveAttack = function () {
+ const forceMag = this.accelMag * this.mass;
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ this.force.x += 150 * forceMag * Math.cos(angle);
+ this.force.y += 150 * forceMag * Math.sin(angle);
+ ctx.beginPath()
+ ctx.moveTo(this.position.x + Math.sin(angle), this.position.y + Math.cos(angle))
+ ctx.lineTo(this.seePlayer.position.x, this.seePlayer.position.y)
+ aim = '#000000';
+ ctx.stroke()
+ }
+ me.teleportAway = function () {//hehe
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ if (this.seePlayer.recall && !(simulation.cycle % 17)) {
+ const dist = Vector.sub(this.position, this.seePlayer.position);
+ const distMag = Vector.magnitude(dist);
+ const unitVector = Vector.normalise(dist);
+ const rando = (Math.random() - 0.5) * 50;
+ if (distMag < 20000) {
+ Matter.Body.translate(this, Vector.mult(unitVector, distMag + rando));
+ } else {
+ Matter.Body.translate(this, Vector.mult(unitVector, 20000 + rando));
+ }
+ }
+ ctx.lineTo(this.position.x, this.position.y);
+ ctx.lineWidth = radius * 2;
+ ctx.strokeStyle = "rgba(0,0,0,0.08)";
+ ctx.stroke();
+ if (!this.seePlayer.yes) {
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ if (this.seePlayer.recall && !(simulation.cycle % 17)) {
+ const dist = Vector.sub(this.seePlayer.position, this.position);
+ const distMag = Vector.magnitude(dist);
+ const unitVector = Vector.normalise(dist);
+ const rando = (Math.random() - 0.5) * 50;
+ if (distMag < 200000) {
+ Matter.Body.translate(this, Vector.mult(unitVector, distMag + rando));
+ } else {
+ Matter.Body.translate(this, Vector.mult(unitVector, 200000 + rando));
+ }
+ }
+ ctx.lineTo(this.position.x, this.position.y);
+ ctx.lineWidth = radius * 2;
+ ctx.strokeStyle = "rgba(0,0,0,0.08)";
+ ctx.stroke();
+ }
+ }
+ me.timeAttack = function () {
+ if (!simulation.isTimeSkipping || input.field) {
+ requestAnimationFrame(() => {
+ simulation.timePlayerSkip(5)
+ m.walk_cycle += m.flipLegs * m.Vx * 5
+ }); //just doing what lilgreenland did
+ }
+ }
+ me.harmonic3Phase = function () { //normal standard 3 different 2-d circles
+ if (tech.harmonics === 2) {
+ const fieldRange1 = (0.75 + 0.3 * Math.cos(m.cycle / 23)) * m.fieldRange * m.harmonicRadius
+ const fieldRange2 = (0.68 + 0.37 * Math.cos(m.cycle / 37)) * m.fieldRange * m.harmonicRadius
+ const fieldRange3 = (0.7 + 0.35 * Math.cos(m.cycle / 47)) * m.fieldRange * m.harmonicRadius
+ const netfieldRange = Math.max(fieldRange1, fieldRange2, fieldRange3)
+ ctx.fillStyle = "rgba(0,0,0," + Math.min(0.6, (0.04 + m.energy * (0.1 + 0.11 * Math.random()))) + ")";
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, fieldRange1, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, fieldRange2, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, fieldRange3, 0, 2 * Math.PI);
+ ctx.fill();
+ //360 block
+ if (Vector.magnitude(Vector.sub(player.position, this.position)) - this.radius < netfieldRange) {
+ me.pushM();
+ }
+ for (let i = 0; i < bullet.length; i++) {
+ if (Vector.magnitude(Vector.sub(bullet[i].position, this.position)) - this.radius < netfieldRange) {
+ const dx = bullet[i].position.x - this.position.x;
+ const dy = bullet[i].position.y - this.position.y;
+ const dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < m.fieldRange) {
+ const angle = Math.atan2(dy, dx);
+ const mag = (1500 * bullet[i].mass * simulation.g) / dist;
+ bullet[i].force.x += mag * Math.cos(angle);
+ bullet[i].force.y += mag * Math.sin(angle);
+ }
+ this.energy -= 0.0012;
+ }
+ }
+ } else {
+ const rotation = simulation.cycle * 0.0031
+ const phase = simulation.cycle * 0.023
+ const radius = m.fieldRange * m.harmonicRadius
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = "rgba(0,0,0,0.5)"
+ ctx.fillStyle = `rgba(0,0,0,${Math.min(0.6, m.energy * (0.11 + 0.1 * Math.random()) * (3 / tech.harmonics))})`;
+ // ctx.fillStyle = "rgba(0,0,0," + Math.min(0.7, m.energy * (0.22 - 0.01 * tech.harmonics) * (0.5 + 0.5 * Math.random())) + ")";
+ for (let i = 0; i < tech.harmonics; i++) {
+ ctx.beginPath();
+ ctx.ellipse(this.position.x, this.position.y, radius * Math.abs(Math.sin(phase + i / tech.harmonics * Math.PI)), radius, rotation + i / tech.harmonics * Math.PI, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.stroke();
+ }
+ //360 block
+ if (Vector.magnitude(Vector.sub(player.position, this.position)) - this.radius < radius) {
+ me.pushM();
+ }
+ for (let i = 0; i < bullet.length; i++) {
+ if (Vector.magnitude(Vector.sub(bullet[i].position, this.position)) - this.radius < radius) {
+ const dx = bullet[i].position.x - this.position.x;
+ const dy = bullet[i].position.y - this.position.y;
+ const dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < m.fieldRange) {
+ const angle = Math.atan2(dy, dx);
+ const mag = (1500 * bullet[i].mass * simulation.g) / dist;
+ bullet[i].force.x += mag * Math.cos(angle);
+ bullet[i].force.y += mag * Math.sin(angle);
+ }
+ this.energy -= 0.0012;
+ }
+ }
+ }
+ }
+ me.railGun = function () {
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ const X = this.position.x
+ const Y = this.position.y
+ const unitVector = { x: Math.cos(angle), y: Math.sin(angle) }
+ const unitVectorPerp = Vector.perp(unitVector)
+
+ function magField(mag, arc) {
+ ctx.moveTo(X, Y);
+ ctx.bezierCurveTo(
+ X + unitVector.x * mag, Y + unitVector.y * mag,
+ X + unitVector.x * mag + unitVectorPerp.x * arc, Y + unitVector.y * mag + unitVectorPerp.y * arc,
+ X + unitVectorPerp.x * arc, Y + unitVectorPerp.y * arc)
+ ctx.bezierCurveTo(
+ X - unitVector.x * mag + unitVectorPerp.x * arc, Y - unitVector.y * mag + unitVectorPerp.y * arc,
+ X - unitVector.x * mag, Y - unitVector.y * mag,
+ X, Y)
+ }
+ ctx.fillStyle = `rgba(50,0,100,0.05)`;
+ const magSize = 8 * c * tech.railChargeRate ** 3
+ const arcSize = 6 * c * tech.railChargeRate ** 3
+ for (let i = 3; i < 7; i++) {
+ const MAG = magSize * i * i * (0.93 + 0.07 * Math.random())
+ const ARC = arcSize * i * i * (0.93 + 0.07 * Math.random())
+ ctx.beginPath();
+ magField(MAG, ARC)
+ magField(MAG, -ARC)
+ ctx.fill();
+ }
+ }
+ me.waves = [];
+ me.doLongitudinal = function () {
+ if (!m.isBodiesAsleep) {
+ ctx.strokeStyle = "rgba(0,0,0,0.6)" //"000";
+ ctx.lineWidth = 2 * tech.wavePacketDamage
+ ctx.beginPath();
+ // const end = 1100 * tech.bulletsLastLonger / Math.sqrt(tech.waveReflections * 0.5) //should equal about 1767
+ const end = 1100 * tech.bulletsLastLonger * Math.pow(0.93, tech.waveReflections) //should equal about 1767
+ const damage = 0.0005 * simulation.dmgScale//normal damage for m basically shreds m, so had to nerf this
+ for (let i = this.waves.length - 1; i > -1; i--) {
+ const v1 = Vector.add(this.waves[i].position, Vector.mult(this.waves[i].unit1, this.waves[i].radius))
+ const v2 = Vector.add(this.waves[i].position, Vector.mult(this.waves[i].unit2, this.waves[i].radius))
+ //draw wave
+ ctx.moveTo(v1.x, v1.y)
+ ctx.arc(this.waves[i].position.x, this.waves[i].position.y, this.waves[i].radius, this.waves[i].angle, this.waves[i].angle + this.waves[i].arc);
+ //using small angle linear approximation of circle arc, this will not work if the arc gets large // https://stackoverflow.com/questions/13652518/efficiently-find-points-inside-a-circle-sector
+ let hits = Matter.Query.ray([player], v1, v2, 50) //Matter.Query.ray(bodies, startPoint, endPoint, [rayWidth])
+ for (let j = 0, len = Math.min(30, hits.length); j < len; j++) {
+ player.force.x += 0.01 * (Math.random() - 0.5) * player.mass
+ player.force.y += (0.01 * (Math.random() - 0.5) - simulation.g * 0.25) * player.mass //remove force of gravity
+ Matter.Body.setVelocity(player, { //friction
+ x: player.velocity.x * 0.95,
+ y: player.velocity.y * 0.95
+ });
+ m.damage(damage)
+ }
+ hits = Matter.Query.ray(body, v1, v2, 50)
+ for (let j = 0, len = Math.min(30, hits.length); j < len; j++) {
+ const who = hits[j].body
+ //make them shake around
+ who.force.x += 0.01 * (Math.random() - 0.5) * who.mass
+ who.force.y += (0.01 * (Math.random() - 0.5) - simulation.g * 0.25) * who.mass //remove force of gravity
+
+ let vertices = who.vertices;
+ const vibe = 25
+ ctx.moveTo(vertices[0].x + vibe * (Math.random() - 0.5), vertices[0].y + vibe * (Math.random() - 0.5));
+ for (let j = 1; j < vertices.length; j++) {
+ ctx.lineTo(vertices[j].x + vibe * (Math.random() - 0.5), vertices[j].y + vibe * (Math.random() - 0.5));
+ }
+ ctx.lineTo(vertices[0].x + vibe * (Math.random() - 0.5), vertices[0].y + vibe * (Math.random() - 0.5));
+
+ if (tech.isPhononBlock && !who.isNotHoldable && who.speed < 5 && who.angularSpeed < 0.1) {
+ if (Math.random() < 0.5) b.targetedBlock(who, 50 - Math.min(25, who.mass * 3)) // targetedBlock(who, speed = 50 - Math.min(20, who.mass * 2), range = 1600) {
+ // Matter.Body.setAngularVelocity(who, (0.25 + 0.12 * Math.random()) * (Math.random() < 0.5 ? -1 : 1));
+ who.torque += who.inertia * 0.001 * (Math.random() - 0.5)
+ }
+ }
+ // ctx.stroke(); //draw vibes
+ this.waves[i].radius += tech.waveBeamSpeed * 1.8 * this.waves[i].expanding //expand / move
+ if (this.waves[i].radius > end - 30) {
+ this.waves[i].expanding = -1
+ if (this.waves[i].reflection < 1) this.waves.splice(i, 1) //end
+ } else if (this.waves[i].radius < 25) {
+ this.waves[i].expanding = 1
+ if (this.waves[i].reflection < 1) this.waves.splice(i, 1) //end
+ }
+ }
+ ctx.stroke();
+ }
+ }
+ me.lasers = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ };
+
+ const seeRange = 7000;
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ const look = {
+ x: where.x + seeRange * Math.cos(angle),
+ y: where.y + seeRange * Math.sin(angle)
+ };
+ // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ vertexCollision(where, look, body);
+ if (!m.isCloak) vertexCollision(where, look, [player]);
+ if (best.who && (best.who === player) && m.immuneCycle < m.cycle) {
+ const dmg = 0.0011 * simulation.dmgScale;
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: dmg * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ //draw beam
+ if (best.dist2 === Infinity) best = look;
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.lineWidth = 10;
+ ctx.stroke();
+ }
+ me.pulse = function (charge, angle, where = this.position) {
+ let best;
+ angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x)
+ let explosionRadius = 5.5 * charge
+ let range = 5000
+ const path = [{
+ x: where.x + 20 * Math.cos(angle),
+ y: where.y + 20 * Math.sin(angle)
+ },
+ {
+ x: where.x + range * Math.cos(angle),
+ y: where.y + range * Math.sin(angle)
+ }
+ ];
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ };
+ //check for collisions
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ if (!best.who) {
+ vertexCollision(path[0], path[1], body);
+ vertexCollision(path[0], path[1], [player]);
+ vertexCollision(path[0], path[1], map);
+ if (best.dist2 != Infinity) { //if hitting something
+ path[path.length - 1] = {
+ x: best.x,
+ y: best.y
+ };
+ }
+ }
+ if (best.who) {
+ b.explosion(path[1], explosionRadius, "rgba(0,0,0,0)")
+ const off = explosionRadius * 1.2
+ b.explosion({ x: path[1].x + off * (Math.random() - 0.5), y: path[1].y + off * (Math.random() - 0.5) }, explosionRadius, "rgba(0,0,0,0.7)")
+ b.explosion({ x: path[1].x + off * (Math.random() - 0.5), y: path[1].y + off * (Math.random() - 0.5) }, explosionRadius, "rgba(0,0,0,0.7)")
+ }
+ //draw laser beam
+ ctx.beginPath();
+ ctx.moveTo(path[0].x, path[0].y);
+ ctx.lineTo(path[1].x, path[1].y);
+ if (charge > 50) {
+ ctx.strokeStyle = "rgba(0,0,0,0.10)"
+ ctx.lineWidth = 70
+ ctx.stroke();
+ }
+ ctx.strokeStyle = "rgba(0,0,0,0.25)"
+ ctx.lineWidth = 20
+ ctx.stroke();
+ ctx.strokeStyle = "#f00";
+ ctx.lineWidth = 4
+ ctx.stroke();
+
+ //draw little dots along the laser path
+ const sub = Vector.sub(path[1], path[0])
+ const mag = Vector.magnitude(sub)
+ for (let i = 0, len = Math.floor(mag * 0.0005 * charge); i < len; i++) {
+ const dist = Math.random()
+ simulation.drawList.push({
+ x: path[0].x + sub.x * dist + 10 * (Math.random() - 0.5),
+ y: path[0].y + sub.y * dist + 10 * (Math.random() - 0.5),
+ radius: 1.5 + 5 * Math.random(),
+ color: "rgba(0,0,0,0.5)",
+ time: Math.floor(9 + 25 * Math.random() * Math.random())
+ });
+ }
+ }
+ let c = 0
+ me.gun = function () {
+ if (b.activeGun == 0) {// nailgun
+ if (this.seePlayer.recall && !(simulation.cycle % 20)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ normalBullet(this.position.x, this.position.y);
+ const v = 10 + 8 * simulation.accelScale;
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ }
+ }
+ if (b.activeGun == 1) {// shotgun
+ if (this.seePlayer.recall && !(simulation.cycle % 90)) {
+ const side = 22
+ for (let i = 0; i < 12; i++) {
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ const dir = angle + (Math.random() - 0.5) * 1
+ const SPEED = 52 + Math.random() * 8
+ normalBullet(this.position.x + 35 * Math.cos(angle) + 15 * (Math.random() - 0.5), this.position.y + 35 * Math.sin(angle) + 15 * (Math.random() - 0.5))
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: SPEED * Math.cos(dir),
+ y: SPEED * Math.sin(dir)
+ });
+ }
+ }
+ } else if (b.activeGun == 2) { // super balls
+ if (this.seePlayer.recall && !(simulation.cycle % 20)) {
+ const num = 3;
+ const SPREAD = 0.13;
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ let dir = angle - SPREAD * (num - 1) / 2;
+ const SPEED = 33
+ for (let i = 0; i < num; i++) {
+ ball(this.position.x + 30 * Math.cos(angle), this.position.y + 30 * Math.sin(angle))
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: SPEED * Math.cos(dir),
+ y: SPEED * Math.sin(dir)
+ });
+ dir += SPREAD
+ }
+ }
+ } else if (b.activeGun == 3) { // wave
+ this.doLongitudinal()
+ const halfArc = 0.275
+ const anglex = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ const angle = anglex + 0.3 * (Math.random() - 0.5)
+ this.waves.push({
+ position: {
+ x: this.position.x + 25 * Math.cos(anglex),
+ y: this.position.y + 25 * Math.sin(anglex),
+ },
+ angle: angle - halfArc, //used in drawing ctx.arc
+ unit1: { x: Math.cos(angle - halfArc), y: Math.sin(angle - halfArc) }, //used for collision
+ unit2: { x: Math.cos(angle + halfArc), y: Math.sin(angle + halfArc) }, //used for collision
+ arc: halfArc * 2,
+ radius: 25,
+ reflection: 0,
+ expanding: 1,
+ resonanceCount: 0
+ })
+ } else if (b.activeGun == 4) { // missiles
+
+ } else if (b.activeGun == 5) { // grenades
+
+ } else if (b.activeGun == 6) { // spores
+ if (this.seePlayer.recall && !(simulation.cycle % 30)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ me.drop(this.position.x, this.position.y)
+ const v = 10 + 8 * simulation.accelScale + (Math.random() * 20 - Math.random() * 20);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ }
+ } else if (b.activeGun == 7) { // drones
+
+ } else if (b.activeGun == 8) { // foam
+ if (this.seePlayer.recall && !(simulation.cycle % 1)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ foamBullet(this.position.x, this.position.y, 7 + Math.ceil(this.radius / 15), 69);
+ const v = 10 + 8 * simulation.accelScale + (Math.random() * 20 - Math.random() * 20);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ }
+ } else if (b.activeGun == 9) { // harpoon - railgun
+ if (c > 1) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ this.railBullet(this.position.x, this.position.y);
+ const v = 10 + 80 * simulation.accelScale;
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ c = 0;
+ } else {
+ c += 0.02;
+ this.railGun();
+ }
+ } else if (b.activeGun == 10) { // laserMines
+ if (this.seePlayer.recall && !(simulation.cycle % 100)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ me.laserMine(this.position.x, this.position.y)
+ const v = 10 + 8 * simulation.accelScale + (Math.random() * 20 - Math.random() * 20);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ }
+ } else if (b.activeGun == 11) { // laser - pulse
+ //this.lasers(this.position, Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ //if (this.seePlayer.recall && !(simulation.cycle % 20)) {
+ if (c > 1) {
+ this.pulse(c * 100)
+ c = 0;
+ } else {
+ if (this.energy < 1 || this.energy > 0.5) {
+ c += 0.01;
+ ctx.beginPath();
+ const mag = Math.sqrt(c)
+ ctx.arc(this.position.x, this.position.y, c * 30, 0, 2 * Math.PI)
+ ctx.fillStyle = '#000000'
+ ctx.strokeStyle = 'transparent'
+ ctx.fill();
+ ctx.stroke();
+ this.energy -= 0.01;
+ ctx.strokeStyle = "#000000";
+ ctx.lineWidth = 1.5
+ // ctx.globalAlpha = 1;
+ } else {
+ c = 0;
+ this.energy += 0.1
+ }
+ }
+ //}
+ }
+ }
+ me.railBullet = function (x, y) {
+ mobs.spawn(x, y, 5, 20, "black");
+ let xy = mob[mob.length - 1];
+ xy.stroke = "black";
+ xy.vertices = Matter.Vertices.rotate(xy.vertices, Math.PI, xy.position);
+ xy.onHit = function () {
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: 20,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ };
+ Matter.Body.setDensity(xy, 0.00004); //normal is 0.001
+ xy.timeLeft = 220;
+ xy.frictionAir = -0.01;
+ xy.restitution = -1;
+ xy.leaveBody = false;
+ xy.isDropPowerUp = false;
+ //xy.inertia = Infinity;
+ xy.isBadTarget = true;
+ xy.isMobBullet = true;
+ xy.showHealthBar = false;
+ xy.collisionFilter.category = cat.mobBullet;
+ xy.collisionFilter.mask = cat.player;
+ let index = 0;
+ xy.do = function () {
+ this.timeLimit();
+ this.alwaysSeePlayer()
+ const setNoseShape = () => {
+ const mag = this.radius + this.radius * 10;
+ const angle = Math.atan2(me.seePlayer.position.y - this.position.y, me.seePlayer.position.x - this.position.x);
+ this.vertices[2].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[2].y = this.position.y + Math.sin(this.angle) * mag;
+ this.vertices[4].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[4].y = this.position.y + Math.sin(this.angle) * mag;
+ this.vertices[0].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[0].y = this.position.y + Math.sin(this.angle) * mag;
+ Matter.Body.setAngle(this, angle);
+ };
+ const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[2], this.position)), radius * 1000)
+ const spike2 = Vector.mult(Vector.normalise(Vector.sub(this.vertices[4], this.position)), radius * 1000)
+ const spike3 = Vector.mult(Vector.normalise(Vector.sub(this.vertices[0], this.position)), radius * 1000)
+ this.vertices[2].x = this.position.x + spike.x / 100
+ this.vertices[2].y = this.position.y + spike.y / 100
+ this.vertices[4].x = this.position.x + spike2.x / 75
+ this.vertices[4].y = this.position.y + spike2.y / 75
+ this.vertices[0].x = this.position.x + spike3.x / 75
+ this.vertices[0].y = this.position.y + spike3.y / 75
+ if (index == 0) {
+ setNoseShape();
+ index++;
+ }
+ if (Matter.Query.collides(this, map).length > 0 || Matter.Query.collides(this, body).length > 0) {
+ const slow = 0.69 //im sorry it looks cool though
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * slow,
+ y: this.velocity.y * slow
+ });
+ // simulation.drawList.push({ //add dmg to draw queue
+ // x: this.position.x,
+ // y: this.position.y,
+ // radius: 10,
+ // color: '#000000',
+ // time: simulation.drawTime
+ // });
+ if (this.velocity.x == 0 && this.velocity.y == 0) {
+ this.death();
+ }
+ this.frictionAir += 0.0001;
+ Matter.Body.setAngularVelocity(this, 0)
+ }
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles // I wasnt gonna add this but since ya'll would have killed me if I didn't I added this
+ const dmg = 0.013 * simulation.dmgScale;
+ m.damage(dmg);
+ // simulation.drawList.push({ //add dmg to draw queue
+ // x: this.position.x,
+ // y: this.position.y,
+ // radius: Math.sqrt(dmg) * 200,
+ // color: '#000000',
+ // time: simulation.drawTime
+ // });
+ }
+ };
+ }
+ me.laserMine = function (x, y) {
+ mobs.spawn(x, y, 3, 20, "#000000");
+ let xx = mob[mob.length - 1];
+ xx.stroke = "#00000000";
+ Matter.Body.setDensity(xx, 0.000005) //one tap
+ xx.isUnstable = true;
+ xx.timeLeft = 40 + Math.floor(180 * Math.random())
+ xx.leaveBody = false;
+ xx.isDropPowerUp = false;
+ xx.collisionFilter.mask = cat.bullet | cat.player
+ xx.showHealthBar = false;
+ //xx.vertices = Matter.Vertices.rotate(xx.vertices, Math.PI, xx.position);
+ me.onHit = function () {
+ this.death();
+ };
+ xx.do = function () {
+ this.timeLimit();
+ Matter.Body.setAngularVelocity(this, 0.01)
+ ctx.beginPath();
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = "#00000000"
+ for (let i = 0; i < this.vertices.length; i++) {
+ const where = this.vertices[i]
+ const endPoint = Vector.add(where, Vector.mult(Vector.normalise(Vector.sub(where, this.position)), 2500))
+ me.lasers(this.vertices[0], this.angle + Math.PI / 3);
+ me.lasers(this.vertices[1], this.angle + Math.PI);
+ me.lasers(this.vertices[2], this.angle - Math.PI / 3);
+ }
+ ctx.strokeStyle = randomColor({
+ hue: "#FF00FF"
+ });
+ ctx.stroke();
+ ctx.save()
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
+ ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
+ ctx.lineTo(this.vertices[2].x, this.vertices[2].y);
+ ctx.fillStyle = "#000000";
+ ctx.strokeStyle = "transparent";
+ ctx.fill();
+ ctx.closePath();
+ ctx.stroke();
+ ctx.restore()
+ }
+ }
+ me.seeker = function (x, y) {
+ mobs.spawn(x, y, sides = 5, radius = 5, "rgb(0,0,0)");
+ let yy = mob[mob.length - 1];
+ yy.stroke = "transparent";
+ yy.onHit = function () {
+ this.explode(this.mass * 20);
+ };
+ Matter.Body.setDensity(yy, 0.000015); //normal is 0.001
+ yy.timeLeft = 420 //* (0.8 + 0.4 * Math.random());
+ yy.accelMag = 0.00017 * simulation.accelScale; //* (0.8 + 0.4 * Math.random())
+ yy.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
+ yy.restitution = 0.5;
+ yy.leaveBody = false;
+ yy.isDropPowerUp = false;
+ yy.isBadTarget = true;
+ yy.isMobBullet = true;
+ yy.showHealthBar = false;
+ yy.collisionFilter.category = cat.mobBullet;
+ yy.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
+ let index = 0;
+ yy.do = function () {
+ this.alwaysSeePlayer()
+ this.timeLimit();
+ this.attraction();
+ };
+ }
+ me.drop = function (x, y) {
+ mobs.spawn(x, y, sides = 90, radius = 30, "rgb(0,255,100,0.7)");
+ let yyy = mob[mob.length - 1];
+ yyy.stroke = "transparent";
+ yyy.onDeath = function () {
+ for (let i = 0, len = 5; i < len; i++) {
+ me.seeker(this.position.x, this.position.y)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: Math.random() * 30 - Math.random() * 30,
+ y: Math.random() * 30 - Math.random() * 30
+ });
+ }
+ };
+ Matter.Body.setDensity(yyy, 0.000015); //normal is 0.001
+ yyy.timeLeft = 60 //* (0.8 + 0.4 * Math.random());
+ yyy.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
+ yyy.restitution = 0.5;
+ yyy.leaveBody = false;
+ yyy.isDropPowerUp = false;
+ yyy.isBadTarget = true;
+ yyy.isMobBullet = true;
+ yyy.showHealthBar = false;
+ yyy.collisionFilter.category = cat.mobBullet;
+ yyy.collisionFilter.mask = null;
+ yyy.maxRadius = 30;
+ let index = 0;
+ yyy.do = function () {
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ Matter.Body.setPosition(this, player.position)
+ if (player.speed > 2.5) Matter.Body.setVelocity(player, Vector.mult(player.velocity, 0.94))
+ }
+ this.alwaysSeePlayer()
+ this.timeLimit();
+ ctx.save()
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y)
+ ctx.fillStyle = "black";
+ ctx.arc(this.position.x, this.position.y, this.maxRadius, 0, 2 * Math.PI)
+ ctx.stroke()
+ ctx.fill()
+ ctx.restore()
+ if (this.maxRadius > 0) {
+ this.maxRadius -= 0.5;
+ }
+ };
+ }
+ };
+ restoreBoss(-13350, -1800);
+ laserEM(-6500 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200), -3400 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200));
+ sniper(-9275 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200), -3325 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200));
+ laserEM(-5750 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200), -850 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200));
+ sniper(-3600 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200), -1325 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200));
+ laserEM(1425 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200), -800 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200));
+ //restoreBoss(-350, -3225);
+ wire();
+ wire();
+ wire();
+ wire();
+ wire();
+ color.map = '#00000000';
+ level.customTopLayer = () => {
+ if (dong.position.x > -3825) {
+ dong.force.y -= dong.mass * simulation.g;
+ } else {
+ dong.force.y += dong.mass * simulation.g;
+ }
+ Matter.Body.setAngularVelocity(dong, -0.5)
+ if (destroyed == false) {
+ door.isClosing = false;
+ } else {
+ door.isClosing = true;
+ }
+ door.openClose();
+ door.draw()
+ for (let i = 0, len = map.length; i < len; i++) { //so boss bar renders over the map
+ // ctx.beginPath()
+ // //ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
+ // ctx.fillRect(map[i].vertices[0].x , map[i].vertices[0].y, Math.abs(map[i].vertices[0].x - map[i].vertices[1].x), Math.abs(map[i].vertices[1].y - map[i].vertices[2].y))
+ // //ctx.strokeRect(map[i].vertices[0].x , map[i].vertices[0].y, Math.abs(map[i].vertices[0].x - map[i].vertices[1].x), Math.abs(map[i].vertices[1].y - map[i].vertices[2].y))
+ // ctx.fillStyle = "rgba(68,68,68)"
+ // //ctx.strokeStyle = "transparent"
+ // ctx.stroke()
+ // ctx.fill()
+ ctx.beginPath();
+ ctx.moveTo(map[i].vertices[0].x, map[i].vertices[0].y);
+ for (let j = 0, length = map[i].vertices.length; j < length; j++) {
+ ctx.lineTo(map[i].vertices[j].x, map[i].vertices[j].y);
+ }
+ ctx.lineTo(map[i].vertices[0].x, map[i].vertices[0].y);
+ ctx.fillStyle = "rgba(68,68,68)";
+ ctx.strokeStyle = "transparent";
+ ctx.fill();
+ ctx.stroke();
+ // ctx.setLineDash([]);
+ }
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].restoreBoss) {
+ ctx.save();
+ ctx.setTransform(1, 0, 0.5, 1, 0, 0); //slanted
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(canvas.width2 / 2, canvas.height2 / 10, canvas.width2, 30);
+ ctx.fillStyle = "rgba(0,0,0,0.7)";
+ ctx.fillRect(canvas.width2 / 2, canvas.height2 / 10, canvas.width2 * mob[i].health, 30);
+ ctx.restore();
+ }
+ }
+ };
+ simulation.enableConstructMode() //landgreen if you see this can you remove im probably gonna forget
+ for (let i = 0; i < spawn.bossTypeSpawnOrder.length * Math.random(); i++) {
+ spawn.bossTypeSpawnOrder.splice(i * Math.floor(Math.random() * spawn.bossTypeSpawnOrder.length), 1, "restoreBoss") //meh good enough
+ }
+ const obj = { restoreBoss };
+ Object.assign(spawn, obj); //ez
+ },
+ superNgonBros() {
+ simulation.makeTextLog(`
Super N-gon Bros by
DesBoot `);
+
+ let bowserKilled = 0
+ let flagY = -750
+ let flagReached = 0
+ const elevator1 = level.elevator(3975, -11650, 450, 50, -13100, 0.003)
+ const elevator2 = level.elevator(5575, -11650, 450, 50, -13100, 0.003)
+ let firstElevatorY = -11650
+
+ const portal = level.portal({ x: 3990, y: 100 }, 1.5 * Math.PI, { x: 100, y: -13500 }, -1.5 * Math.PI)
+ const portal2 = level.portal({ x: 7135, y: -12270 }, -1 * Math.PI, { x: 12325, y: -2000 }, -1.5 * Math.PI)
+
+ const bowser = function (x, y, radius = 150) { //define the mob the same as spawn mob code
+ mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
+ let me = mob[mob.length - 1];
+ me.accelMag = 0.05;
+ me.g = 0.002; //required if using this.gravity
+ me.frictionAir = 0.01;
+ me.friction = 1
+ me.frictionStatic = 1
+ me.restitution = 0;
+ me.delay = 80 * simulation.CDScale;
+ me.randomHopFrequency = 200 + Math.floor(Math.random() * 150);
+ me.randomHopCD = simulation.cycle + me.randomHopFrequency;
+ Matter.Body.rotate(me, Math.random() * Math.PI);
+ spawn.shield(me, x, y);
+ me.do = function () {
+ //spawn.grenade(me.position.x, me.position.y);
+ // //const v = 5 * simulation.accelScale;
+ // Matter.Body.setVelocity(mob[mob.length - 1], {
+ // x: this.velocity.x + this.fireDir.x * v + Math.random(),
+ // y: this.velocity.y + this.fireDir.y * v + Math.random()
+ // });
+ this.gravity();
+ this.seePlayerCheck();
+ this.checkStatus();
+ if (this.seePlayer.recall) {
+ if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
+ this.cd = simulation.cycle + this.delay;
+ const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ this.force.x += forceMag * Math.cos(angle) * 0.5;
+ this.force.y += (forceMag * Math.sin(angle) - (Math.random() * 0.07 + 0.1) * this.mass) * 0.7; //antigravity
+ if (Math.random() < 0.5) {
+ spawn.grenade(me.position.x, me.position.y - 250 * Math.random(), 500);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: -5,
+ y: 0
+ });
+ } else {
+ spawn.bullet(this.position.x, this.position.y, 25);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: -25,
+ y: -25
+ });
+ }
+ }
+ } else {
+ //randomly hob if not aware of player
+ if (this.randomHopCD < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
+ this.randomHopCD = simulation.cycle + this.randomHopFrequency;
+ //slowly change randomHopFrequency after each hop
+ this.randomHopFrequency = Math.max(100, this.randomHopFrequency + (0.5 - Math.random()) * 200);
+ const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass * (0.1 + Math.random() * 0.3);
+ const angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI;
+ this.force.x += forceMag * Math.cos(angle);
+ this.force.y += forceMag * Math.sin(angle) - 0.07 * this.mass; //antigravity
+ spawn.grenade(me.position.x, me.position.y - 250 * Math.random(), 500);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: -5,
+ y: 0
+ });
+ }
+ }
+ };
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ bowserKilled = 1
+ }
+
+ }
+
+ bowser(20500, -400) //call the mob
+ //fire(15300, -200)
+ const brick = function (x, y, angle = Math.PI * 0.5, radius = 53) {//credit to Richard0820 for the code
+ mobs.spawn(x, y, 4, radius, "#ab6101");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ Matter.Body.setDensity(me, 999999)
+ me.collisionFilter.mask = cat.player | cat.mob | cat.bullet;
+ me.constraint = Constraint.create({
+ pointA: {
+ x: me.position.x,
+ y: me.position.y
+ },
+ bodyB: me,
+ stiffness: 0,
+ damping: 0
+ });
+ me.do = function () {
+ this.isStunned = true;
+ if (this.health < 1) {
+ this.health += 0.001; //regen
+ }
+ this.checkStatus();
+ Matter.Body.setAngle(me, angle);
+ if ((player.velocity.y < 0 && player.position.y > me.position.y || player.velocity.y > 30 && player.position.y < me.position.y) && Math.abs(player.position.x - me.position.x) < 50 && Math.abs(player.position.y - me.position.y) < 150) {
+ me.death()
+ }
+ };
+
+ me.onHit = function () {
+
+ if (player.velocity.y < 0 && player.position.y > me.position.y || player.velocity.y > 30 && player.position.y < me.position.y) {
+
+ me.death()
+
+ }
+ }
+ me.onDeath = function () {
+ if (Math.random() < 0.1) {
+ spawn.randomSmallMob(me.position.x, me.position.y - 75);
+ simulation.makeTextLog('mob')
+ } else {
+ if (Math.random() < 0.07) {
+ powerUps.spawn(me.position.x, me.position.y + (75 * (player.velocity.y / Math.abs(player.velocity.y))), "tech", true);
+ simulation.makeTextLog('tech')
+ } else {
+ if (Math.random() < 0.4) {
+ powerUps.spawn(me.position.x, me.position.y + (75 * (player.velocity.y / Math.abs(player.velocity.y))), "heal", true);
+ simulation.makeTextLog('heal')
+ } else {
+ //if (Math.random() < 0.8){
+ powerUps.spawn(me.position.x, me.position.y + (75 * (player.velocity.y / Math.abs(player.velocity.y))), "ammo", true);
+ simulation.makeTextLog('ammo')
+ //}
+ }
+ }
+ }
+ }
+ Composite.add(engine.world, me.constraint);
+ }
+ simulation.enableConstructMode()
+ let firstMobsSpawned = 1
+ let secondMobsSpawned = 0
+ let thirdMobsSpawned = 0
+ let fourthMobsSpawned = 0
+ let firstMobsReached = 0
+ let secondMobsReached = 0
+ let thirdMobsReached = 0
+ let fourthMobsReached = 0
+ let finalRoomReached = 0
+ let undergroundMobsSpawned = 0
+ let undergroundMobsReached = 0
+
+
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 22100;
+ level.exit.y = -40;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#a2a5ff";
+ // color.map = "#444" //custom map color
+
+ level.custom = () => {
+ if (player.position.x > 14950 && flagReached == 0) {
+ flagReached = 1
+ }
+ if (flagReached == 1 && flagY < -150) {
+ flagY += 5
+ }
+ ctx.fillStyle = "rgba(64,64,64,0.97)"
+ ctx.fillRect(4200, -13100, 2, 1450)
+ ctx.fillRect(5800, -13100, 2, 1450)
+ if (firstElevatorY < -12099) {
+ firstElevatorY = -11650
+ } else {
+ firstElevatorY -= 5
+ }
+
+ //simulation.makeTextLog(firstElevatorY)
+ elevator1.move();
+ elevator2.move();
+ if (player.position.x > 0 && player.position.y < -9000 && player.position.y > -10000) {
+ //m.death()
+ m.damage(0.05 * simulation.difficultyMode)
+ Matter.Body.setPosition(player, {
+ x: 275,
+ y: -12175
+ });
+ }
+
+ portal[2].query()
+ portal[3].query()
+ portal2[2].query()
+ portal2[3].query()
+ //simulation.makeTextLog(firstBlockBroken)
+ level.exit.drawAndCheck();
+ if (player.position.x > 4100 && secondMobsReached == 0) {
+ secondMobsSpawned = 1
+ }
+ if (player.position.x > 7000 && thirdMobsReached == 0) {
+ thirdMobsSpawned = 1
+ }
+ if (player.position.x > 14300 && fourthMobsReached == 0) {
+ fourthMobsSpawned = 1
+ }
+ if (player.position.y < -11000 && undergroundMobsReached == 0) {
+ undergroundMobsSpawned = 1
+ }//player.position.x > 14300 &&
+ if (m.onGround) {
+ if (Math.abs(player.velocity.x) > 0.3) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x + (0.1 * (Math.abs(player.velocity.x) / player.velocity.x)),
+ y: player.velocity.y + 0.2
+ });
+ } else {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 0.2
+ });
+ }
+ } else {
+ if (input.down) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 2
+ });
+ } else {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 0.2
+ });
+ }
+ }
+
+ level.enter.draw();
+ if (finalRoomReached == 0 && player.position.x > 21150) {
+ finalRoomReached = 1
+ simulation.makeTextLog('Thank you M, but our techs are in another castle!')
+ }
+ //mobs
+ if (firstMobsSpawned == 1 && firstMobsReached == 0) {
+ spawn.randomSmallMob(1260, -75);
+ spawn.randomMob(2100, -75, 0.4);
+ spawn.randomSmallMob(2400, -75);
+ spawn.randomSmallMob(2500, -75);
+ spawn.randomMob(2900, -75, 0.2);
+ spawn.randomMob(3400, -75, 0.4);
+ spawn.randomMob(3400, -75, 0.4);
+ firstMobsReached = 1
+ }
+ if (secondMobsSpawned == 1 && secondMobsReached == 0) {
+ spawn.randomSmallMob(4400, -75);
+ spawn.randomSmallMob(5500, -75);
+ spawn.randomSmallMob(5835.6, -402.4);
+ spawn.randomSmallMob(5835.6, -402.4);
+ spawn.randomSmallMob(6543.2, -730.0);
+ spawn.randomMob(6795.4, -162.4, 0.1);
+ spawn.randomMob(6795.4, -162.4, 0.1);
+ secondMobsReached = 1
+ }
+ if (thirdMobsSpawned == 1 && thirdMobsReached == 0) {
+ spawn.randomMob(8465.6, -469.9, 0.1);
+ spawn.randomMob(9839.6, -444.5, 0.4);
+ spawn.randomSmallMob(11033.2, -155.3);
+ spawn.randomMob(12161.3, -85.1, 0.3);
+ spawn.randomMob(12161.3, -85.1, 0.3);
+ spawn.randomMob(13399.8, -93.4, 0.4);
+ thirdMobsReached = 1
+
+ }
+ if (fourthMobsSpawned == 1 && fourthMobsReached == 0) {
+ spawn.randomSmallMob(16500, -400);
+ spawn.randomSmallMob(19278.9, -211.1);
+ spawn.randomMob(18839.0, -463.2, 0.3);
+ spawn.randomMob(18036.9, -205.9, 0.3);
+ spawn.randomMob(16950.4, -365.2, 0.4);
+ spawn.randomMob(16355.6, -390.8, 0.1);
+
+ fourthMobsReached = 1
+
+ }
+ if (undergroundMobsSpawned == 1 && undergroundMobsReached == 0) {
+ spawn.randomSmallMob(1140.0, -12228.0);
+ spawn.randomSmallMob(2429.9, -12371.2);
+ spawn.randomSmallMob(4899.4, -12139.6);
+ spawn.randomMob(18839.0, -463.2, 0.3);
+ spawn.randomMob(2844.5, -12281.0, 0.2);
+ spawn.randomMob(4967.5, -12550.8, 0.4);
+ spawn.randomMob(6696.9, -12437.9, 0.1);
+
+ undergroundMobsReached = 1
+
+ }
+ portal[0].draw();
+ portal[1].draw();
+ portal[2].draw();
+ portal[3].draw();
+ portal2[0].draw();
+ portal2[1].draw();
+ portal2[2].draw();
+ portal2[3].draw();
+ };
+ level.customTopLayer = () => {
+ //spawn.mapRect(886, firstElevatorY + 10000, 75, 5);
+
+ ctx.fillStyle = "rgba(64,64,64,0.97)"
+ ctx.fillRect(3928, -300, 120, 500)
+ //6940, -12360, 200, 5
+ ctx.fillRect(6940, -12350, 170, 120)
+ ctx.fillRect(7090, -12380, 120, 200)
+ ctx.fillRect(14980, -750, 10, 750)//flagpole
+ ctx.beginPath()
+ ctx.moveTo(14980, flagY)
+ ctx.lineTo(14905, flagY)
+ ctx.lineTo(14980, flagY + 75)
+ ctx.fill()
+
+ };
+
+
+
+ brick(923.5, -262);
+ spawn.mapRect(886, -304, 75, 5);
+ spawn.mapRect(886, -229, 75, 5);
+ spawn.mapRect(883, -304, 5, 80);
+ spawn.mapRect(958, -304, 5, 80);
+ brick(1250.5, -262);
+ spawn.mapRect(1138, -304, 375, 5);
+ spawn.mapRect(1138, -229, 375, 5);
+ brick(1400.5, -262);
+ brick(1325.5, -562);
+ spawn.mapRect(1288, -604, 75, 5);
+ spawn.mapRect(1288, -529, 75, 5);
+ spawn.mapRect(1285, -604, 5, 80);
+ spawn.mapRect(1360, -604, 5, 80);
+ brick(5787.5, -262);
+ spawn.mapRect(5675, -304, 225, 5);
+ spawn.mapRect(5675, -229, 225, 5);
+ brick(6987.5, -562);
+ spawn.mapRect(6725, -604, 300, 5);
+ spawn.mapRect(6725, -529, 300, 5);
+ spawn.mapRect(7025, -604, 5, 80);
+ brick(7887.5, -262);//4 separated blocks in the middle
+ spawn.mapRect(7850, -304, 75, 5);
+ spawn.mapRect(7850, -225, 75, 5);
+ spawn.mapRect(7850, -304, 5, 80);
+ spawn.mapRect(7925, -304, 5, 84);
+ brick(8112.5, -262);
+ spawn.mapRect(8075, -304, 75, 5);
+ spawn.mapRect(8075, -225, 75, 5);
+ spawn.mapRect(8075, -304, 5, 80);
+ spawn.mapRect(8150, -304, 5, 84);
+ brick(8337.5, -262);
+ spawn.mapRect(8300, -304, 75, 5);
+ spawn.mapRect(8300, -225, 75, 5);
+ spawn.mapRect(8300, -304, 5, 80);
+ spawn.mapRect(8375, -304, 5, 84);
+ brick(8112.5, -562);
+ spawn.mapRect(8075, -604, 75, 5);
+ spawn.mapRect(8075, -525, 75, 5);
+ spawn.mapRect(8075, -604, 5, 80);
+ spawn.mapRect(8150, -604, 5, 84);
+ brick(9612.5, -562);
+ spawn.mapRect(9500, -604, 300, 5);
+ spawn.mapRect(9500, -525, 300, 5);
+ spawn.mapRect(9647.5, -600, 5, 75);
+ brick(9687.5, -562);
+ brick(12887.5, -262);
+ spawn.mapRect(12700, -304, 300, 5);
+ spawn.mapRect(12700, -225, 300, 5);
+ brick(5212.5, -12337.5);
+ spawn.mapRect(4725, -12377, 525, 5);
+ spawn.mapRect(4725, -12303, 525, 5);
+ spawn.mapRect(5250, -12377, 5, 79);
+
+
+
+
+
+ spawn.mapRect(-100, 0, 4033, 2000);
+ spawn.mapRect(4043, 0, 882, 2000);
+ spawn.mapRect(3909.5, 203.6, 150, 2000);
+ spawn.mapRect(1138, -300, 75, 75);
+ spawn.mapRect(1288, -300, 75, 75);
+ spawn.mapRect(1438, -300, 75, 75);
+ spawn.mapRect(1738, -150, 150, 75);//pipe 1
+ spawn.mapRect(1753, -150, 120, 150);
+ spawn.mapRect(2488, -225, 150, 75);//pipe 2
+ spawn.mapRect(2503, -225, 120, 225);
+ spawn.mapRect(3088, -300, 150, 75);//pipe 3
+ spawn.mapRect(3103, -300, 120, 300);
+ spawn.mapRect(3913, -300, 20, 75);//pipe 4
+ spawn.mapRect(3928, -300, 5, 300);
+ spawn.mapRect(4043, -300, 20, 75);
+ spawn.mapRect(4043, -300, 5, 300);
+
+ spawn.mapRect(5225, 0, 1125, 2000);
+ spawn.mapRect(6575, 0, 4900, 2000);
+ spawn.mapRect(5675, -300, 75, 75);
+ spawn.mapRect(5825, -300, 75, 75);
+ spawn.mapRect(5900, -600, 600, 75);
+ spawn.mapRect(6725, -600, 225, 75);
+ spawn.mapRect(6950, -300, 75, 75);
+ spawn.mapRect(7400, -300, 150, 75);
+
+ spawn.mapRect(8750, -300, 75, 75);
+ spawn.mapRect(8975, -600, 225, 75);//raised platform
+ spawn.mapRect(9575, -300, 150, 75);
+ spawn.mapRect(9500, -600, 75, 75);//upper block with double bricks
+ spawn.mapRect(9725, -600, 75, 75);
+ spawn.mapRect(9950, -75, 300, 75);//staircase
+ spawn.mapRect(10025, -150, 225, 75);
+ spawn.mapRect(10100, -225, 150, 75);
+ spawn.mapRect(10175, -300, 75, 75);
+
+ spawn.mapRect(10475, -75, 300, 75);
+ spawn.mapRect(10475, -150, 225, 75);
+ spawn.mapRect(10475, -225, 150, 75);
+ spawn.mapRect(10475, -300, 75, 75);
+
+ spawn.mapRect(11100, -75, 375, 75);//staircase 2
+ spawn.mapRect(11175, -150, 300, 75);
+ spawn.mapRect(11250, -225, 225, 75);
+ spawn.mapRect(11325, -300, 150, 75);
+
+ spawn.mapRect(11725, -75, 300, 75);
+ spawn.mapRect(11725, -150, 225, 75);
+ spawn.mapRect(11725, -225, 150, 75);
+ spawn.mapRect(11725, -300, 75, 75);
+
+ spawn.mapRect(11725, 0, 5975, 2000);//platform after the staircase
+ spawn.mapRect(12325, -150, 150, 75);//exit pipe
+ spawn.mapRect(12340, -150, 120, 300);
+ spawn.mapRect(12700, -300, 150, 75);
+ spawn.mapRect(12925, -300, 75, 75);
+ spawn.mapRect(13525, -150, 150, 72);//final pipe
+ spawn.mapRect(13540, -150, 120, 150);
+ spawn.mapRect(13675, -75, 675, 75);//final staircase
+ spawn.mapRect(13750, -150, 600, 75);
+ spawn.mapRect(13825, -225, 525, 75);
+ spawn.mapRect(13900, -300, 450, 75);
+ spawn.mapRect(13975, -375, 375, 75);
+ spawn.mapRect(14050, -450, 300, 75);
+ spawn.mapRect(14125, -525, 225, 75);
+ spawn.mapRect(14200, -600, 150, 75);
+
+ //flag
+ spawn.mapRect(14950, -75, 75, 75);
+
+
+
+ spawn.mapRect(1750, -4600, 500, 25);//loss
+ spawn.mapRect(2000, -4850, 25, 500);
+ spawn.mapRect(1800, -4800, 25, 150);
+ spawn.mapRect(2075, -4800, 25, 150);
+ spawn.mapRect(2150, -4775, 25, 125);
+ spawn.mapRect(1875, -4550, 25, 150);
+ spawn.mapRect(1800, -4550, 25, 150);
+ spawn.mapRect(2075, -4550, 25, 150);
+ spawn.mapRect(2123, -4430, 100, 25);
+ // spawn.mapRect(-250, -600, 500, 25);
+ // spawn.mapRect(-250, -600, 500, 25);
+
+ //underground area
+ spawn.mapRect(0, -12000, 2025, 2000);
+ spawn.mapRect(2325, -12225, 150, 2000);
+ spawn.mapRect(2775, -12000, 900, 2000);
+ spawn.mapRect(3525, -12300, 150, 300);
+ spawn.mapRect(3450, -12225, 75, 300);
+ spawn.mapRect(3375, -12150, 75, 300);
+ spawn.mapRect(3300, -12075, 75, 300);
+ spawn.mapRect(4725, -12375, 450, 75);
+ spawn.mapRect(4725, -12000, 600, 2000);
+ spawn.mapRect(-100, -13500, 100, 3500);
+ spawn.mapRect(-100, -13500, 100, 3500);
+ spawn.mapRect(6375, -12225, 1650, 2000);
+ spawn.mapRect(7225, -13225, 2850, 3000);
+ spawn.mapRect(-100, -13700, 100, 200);//roof
+ spawn.mapRect(-100, -13700, 3775, 100);
+ spawn.mapRect(6450, -13225, 1000, 100);
+ spawn.mapRect(7090, -13225, 120, 885);//pipe
+ //spawn.mapRect(6940, -12360, 200, 120);
+ spawn.mapRect(6940, -12350, 200, 5);
+ spawn.mapRect(6950, -12240, 140, 5);
+ spawn.mapRect(6940, -12365, 75, 15);
+ spawn.mapRect(6940, -12235, 75, 15);
+
+ //castle
+ spawn.mapRect(17700, 0, 4975, 2000);
+ spawn.mapRect(18600, -225, 375, 2225);
+ spawn.mapRect(19500, -225, 450, 2225);
+ spawn.mapRect(19500, -825, 450, 225);
+ spawn.mapRect(15924, -1575, 6751, 750);
+ spawn.mapRect(19950, -225, 975, 75);
+ spawn.mapRect(20925, -300, 225, 300);
+ spawn.mapRect(21000, -825, 150, 300);
+ spawn.mapRect(15924, -225, 1776, 2225);
+ spawn.mapRect(17175, -825, 525, 225);
+ spawn.mapRect(22600, -825, 75, 825);
+
+
+
+ // powerUps.spawnStartingPowerUps(1475, -1175);
+ // spawn.debris(750, -2200, 3700, 16); //16 debris per level
+ // spawn.bodyRect(1540, -1110, 300, 25, 0.9);
+ // spawn.randomSmallMob(1300, -70);
+ // spawn.randomMob(2650, -975, 0.8);
+ // spawn.randomGroup(1700, -900, 0.4);
+ // if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300);
+ // spawn.secondaryBossChance(100, -1500)
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ underpass() {
+ simulation.makeTextLog(`
underpass by
Richard0820 `);
+
+ let key = false;
+ const door = level.door(2650, -825, 50, 250, 250, 10);
+ const elevator = level.elevator(-11050, -650, 450, 75, -2975, 0.003, { up: 0.1, down: 0.1 })
+ const slimePit = level.hazard(-4775, -350, 1975, 175);
+ const boost = level.boost(137.5, -600, 75, 25);
+ let base = Matter.Bodies.rectangle(-4375, -1000, 100, 100, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let left = Matter.Bodies.rectangle(-4375 + 50, -1000 - 50, 50, 50, {//not actually left/right
+ density: 0.05,
+ isNotHoldable: true,
+ isStatic: false
+ });
+ let right = Matter.Bodies.rectangle(-4375 - 50, -1000 - 50, 50, 50, {
+ density: 0.05,
+ isNotHoldable: true,
+ isStatic: false
+ });
+ let left2 = Matter.Bodies.rectangle(-4375 - 50, -1000 + 50, 50, 50, {
+ density: 0.05,
+ isNotHoldable: true,
+ isStatic: false
+ });
+ let right2 = Matter.Bodies.rectangle(-4375 + 50, -1000 + 50, 50, 50, {
+ density: 0.05,
+ isNotHoldable: true,
+ isStatic: false
+ });
+ dong = Matter.Body.create({
+ parts: [base, left, right, left2, right2]
+ });
+ body[body.length] = base;
+ body[body.length] = left;
+ body[body.length] = right;
+ body[body.length] = left2;
+ body[body.length] = right2;
+ Matter.Composite.add(engine.world, dong)
+ Matter.Composite.add(engine.world, Constraint.create({
+ pointA: { x: -3825, y: -975 },
+ bodyB: dong,
+ stiffness: 0.2,
+ damping: 0.1
+ }));
+ composite[composite.length] = dong;
+ setTimeout(function () {
+ dong.collisionFilter.category = cat.body;
+ dong.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mobBullet | cat.mob //| cat.map
+ }, 1000);
+ level.custom = () => {
+ ctx.save()
+ ctx.beginPath()
+ ctx.fillStyle = "#80808077";
+ ctx.strokeStyle = "#80808022";
+ ctx.fillRect(225, -1025, 2400, 450);
+ ctx.fillRect(-2950, -1025, 3100, 450);
+ ctx.fillRect(-7050, -1025, 2400, 450);
+ ctx.fillRect(-10575, -3975, 4525, 1025);
+ ctx.fillRect(-4650, -1700, 1700, 1100);
+ ctx.fillRect(-11150, -3575, 575, 3050);
+ ctx.fillRect(-11900, -1000, 750, 475);
+ ctx.fill()
+ ctx.stroke()
+ ctx.restore()
+ ctx.save()
+ ctx.beginPath()
+ ctx.fillStyle = "#d8dadf";
+ ctx.strokeStyle = "#d8dadf";
+ ctx.moveTo(-2950, -600);
+ ctx.lineTo(-3730, -1725);
+ ctx.lineTo(-3730, -600);
+
+ ctx.moveTo(-4650, -600);
+ ctx.lineTo(-3925, -1725);
+ ctx.lineTo(-3925, -575);
+
+ ctx.moveTo(-10575, -3425); //NE section
+ ctx.lineTo(-10100, -2975);
+ ctx.lineTo(-10575, -2975);
+
+ // ctx.moveTo(-7625, -3800);
+ // ctx.lineTo(-6750, -2975);
+ // ctx.lineTo(-7625, -2975);
+
+ ctx.moveTo(-7975, -2975);
+ ctx.lineTo(-7625, -3800);
+ ctx.lineTo(-7350, -2950);
+
+ ctx.moveTo(-6750, -2975);
+ ctx.lineTo(-7075, -3800);
+ ctx.lineTo(-7350, -2950);
+
+ // ctx.moveTo(-7975, -2975);
+ // ctx.lineTo(-7075, -3800);
+ // ctx.lineTo(-7075, -2975);
+
+ ctx.moveTo(-11900, -950);
+ ctx.lineTo(-11900, -550);
+ ctx.lineTo(-11500, -550);
+
+ ctx.fillRect(-3925, -1675, 200, 1075);
+ ctx.fillRect(-7625, -3800, 550, 875);
+ ctx.clearRect(-10600, -4000, 525, 475);
+ ctx.clearRect(-10100, -4000, 500, 300);
+ ctx.clearRect(-9625, -4000, 500, 175);
+ ctx.fillRect(-11125, -3600, 550, 50);
+ ctx.fillRect(-10600, -3400, 50, 425);
+ ctx.fillRect(-11925, -925, 45, 375);
+ ctx.fillRect(-3950, -1675, 75, 1100);
+ ctx.fillRect(-3925, -625, 950, 50);
+ ctx.fillRect(-4650, -600, 1700, 375);
+ ctx.fillRect(-14550, -2400, 2650, 2050);
+ //ctx.clearRect(-11050, -3000, 475, 50);
+
+ ctx.moveTo(-11150, -3575);
+ ctx.lineTo(-10575, -2150);
+ ctx.lineTo(-10575, -3575);
+
+ ctx.stroke()
+ ctx.fill()
+ ctx.restore()
+ boost.query()
+ slimePit.query()
+ if (Matter.Query.collides(dong, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ const dmg = 0.05 * Math.min(simulation.dmgScale, simulation.difficulty);
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: dong.position.x,
+ y: dong.position.y,
+ radius: Math.sqrt(dmg) * 200,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ }
+ for (let i = 0; i < mob.length; i++) {
+ if (Matter.Query.collides(dong, [mob[i]]).length > 0) {
+ const dmg = 1;
+ mob[i].damage(dmg, true);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: dong.position.x,
+ y: dong.position.y,
+ radius: Math.sqrt(dmg) * 50,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ break
+ }
+ }
+ level.exit.drawAndCheck();
+ ctx.beginPath()
+ ctx.fillStyle = '#68686822';
+ ctx.fillRect(-25, -2175, 100, 200);
+ ctx.fill()
+ ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
+ ctx.moveTo(-3825, -975)
+ ctx.lineTo(dong.position.x, dong.position.y)
+ ctx.stroke();
+ ctx.setLineDash([]);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: dong.position.x,
+ y: dong.position.y,
+ radius: 10,
+ color: color.block,
+ time: 20
+ });
+ ctx.beginPath()
+ ctx.fillStyle = `rgba(68,68,68, ${3 * Math.sin(simulation.cycle * 0.015)})`
+ ctx.fillRect(-3000, -2175, 175, 25);
+ ctx.fillRect(-2850, -2300, 25, 150);
+ ctx.fillRect(-3000, -2300, 175, 25);
+ ctx.fillRect(-3000, -2425, 25, 150);
+ ctx.fillRect(-3000, -2425, 175, 25);
+ ctx.fill()
+ ctx.fillStyle = `rgba(68,68,68, ${5 * Math.sin(simulation.cycle * 0.015)})`
+ ctx.fillRect(-2725, -2425, 25, 275);
+ ctx.fillRect(-2725, -2425, 175, 25);
+ ctx.fillRect(-2575, -2425, 25, 275);
+ ctx.fillRect(-2725, -2300, 175, 25);
+ ctx.fill()
+ ctx.fillStyle = `rgba(68,68,68, ${7 * Math.sin(simulation.cycle * 0.015)})`
+ ctx.fillRect(-2450, -2425, 25, 275);
+ ctx.fillRect(-2450, -2175, 175, 25);
+ ctx.fill()
+ ctx.stroke();
+ ctx.fillStyle = `#00FFFF22`;
+ ctx.fillRect(-7650, -2975 - 100, 600, 2375 + 100)
+ ctx.fill()
+ ctx.fillStyle = `#00FFFF66`
+ ctx.fillRect(-7650 + Math.floor(Math.random() * 600), -2975 - 100, 5, 2375 + 100)
+ ctx.fillRect(-7650 + Math.floor(Math.random() * 600), -2975 - 100, 5, 2375 + 100)
+ ctx.fillStyle = `rgba(68, 68, 68)`
+ ctx.fillRect(-7675, -3075, 50, 125);
+ ctx.fillRect(-7075, -3075, 50, 125);
+ ctx.fillRect(-7725, -3025, 75, 75);
+ ctx.fillRect(-7050, -3025, 75, 75);
+ ctx.fill()
+ for (let i = 0, len = body.length; i < len; ++i) { //push blocks away vertically
+ if (body[i].position.x > -7625 && body[i].position.x < -7075 && body[i].position.y > -2975 - 100 && body[i].position.y < -625) {
+ body[i].force.y -= simulation.g * body[i].mass + 0.012;
+ }
+ }
+ for (let i = 0, len = bullet.length; i < len; ++i) { //push bullets away vertically
+ if (bullet[i].position.x > -7625 && bullet[i].position.x < -7075 && bullet[i].position.y > -2975 - 100 && bullet[i].position.y < -625) {
+ bullet[i].force.y -= simulation.g * bullet[i].mass;
+ }
+ }
+ for (let i = 0, len = powerUp.length; i < len; ++i) { //push powerups away vertically
+ if (powerUp[i].position.x > -7625 && powerUp[i].position.x < -7075 && powerUp[i].position.y > -2975 - 100 && powerUp[i].position.y < -625) {
+ powerUp[i].force.y -= simulation.g * powerUp[i].mass + 0.12;
+ }
+ }
+ for (let i = 0, len = mob.length; i < len; ++i) { //push mobs away vertically
+ if (mob[i].position.x > -7625 && mob[i].position.x < -7075 && mob[i].position.y > -2975 - 100 && mob[i].position.y < -625) {
+ mob[i].force.y -= simulation.g * mob[i].mass + 0.0012;
+ }
+ }
+ if (m.pos.x > -7625 && m.pos.x < -7075 && m.pos.y > -2975 - 100 && m.pos.y < -625) {
+ player.force.y -= m.mass * simulation.g + (input.down ? 0 : 0.012 * 2);
+
+ }
+ ctx.save()
+ ctx.beginPath();
+ ctx.fillStyle = `rgba(0,250,250, 0.05)`;
+ ctx.fillRect(2625, -1000, 350, 450);
+ ctx.fill()
+ ctx.restore()
+ elevator.move()
+ if (mob.length <= 5) {
+ key = true;
+ }
+ if (key) {
+ level.exit.x = 2775;
+ level.exit.y = -650;
+ } else {
+
+ ctx.save()
+ ctx.beginPath();
+ ctx.moveTo(2775, -650 + 30);
+ ctx.lineTo(2775, -650 - 80);
+ ctx.bezierCurveTo(2775, -650 - 170, 2775 + 100, -650 - 170, 2775 + 100, -650 - 80);
+ ctx.lineTo(2775 + 100, -650 + 30);
+ ctx.lineTo(2775, -650 + 30);
+ ctx.fillStyle = "#00ffff";
+ ctx.fill();
+ ctx.restore()
+
+ const omega = new Image(); //the seal hehe
+ let width = Math.random() * 40; //Math.max(Math.sin(m.cycle * 0.05), Math.cos(m.cycle * 0.05)) *
+ let length = Math.random() * 40; //Math.max(Math.sin(m.cycle * 0.05), Math.cos(m.cycle * 0.05)) *
+ omega.src = "https://raw.githubusercontent.com/Whyisthisnotavalable/image-yy/main/MOSHED-2023-4-20-12-55-58-removebg-preview.png"; //"https://raw.githubusercontent.com/Whyisthisnotavalable/image-yy/main/omegafr.png";
+ ctx.drawImage(omega, 2775 + 50 - width, -650 - 50 - length, width * 2, length * 2)
+ ctx.save()
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.beginPath()
+ // ctx.font = "80px monospace";
+ // ctx.fillText("Ω", 2775 + 50, -650 - 50);
+ ctx.strokeStyle = "gray";
+ ctx.arc(2775 + 50, -650 - 50, 100 * Math.abs(Math.sin(m.cycle * 0.07)) + 10, 0 + Math.sin(m.cycle * 0.1 * Math.PI), 0 + Math.cos(m.cycle * 0.1 + Math.PI))
+ ctx.shadowBlur = 10;
+ ctx.shadowColor = "black";
+ ctx.stroke()
+ //ctx.fill()
+ ctx.restore()
+ ctx.save()
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.beginPath()
+ // ctx.font = "80px monospace";
+ // ctx.fillText("Ω", 2775 + 50, -650 - 50);
+ ctx.strokeStyle = "gray";
+ ctx.arc(2775 + 50, -650 - 50, 90 * Math.abs(Math.sin(m.cycle * 0.08)) + 10, 0 + Math.cos(m.cycle * 0.1 * Math.PI), 0 + Math.sin(m.cycle * 0.1 + Math.PI))
+ ctx.shadowBlur = 10;
+ ctx.shadowColor = "black";
+ ctx.stroke()
+ //ctx.fill()
+ ctx.restore()
+ ctx.save()
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.beginPath()
+ // ctx.font = "80px monospace";
+ // ctx.fillText("Ω", 2775 + 50, -650 - 50);
+ ctx.strokeStyle = "gray";
+ ctx.arc(2775 + 50, -650 - 50, 80 * Math.abs(Math.sin(m.cycle * 0.09)) + 10, 0 + Math.tan(m.cycle * 0.1 * Math.PI), 0 + Math.tan(m.cycle * 0.1 + Math.PI))
+ ctx.shadowBlur = 10;
+ ctx.shadowColor = "black";
+ ctx.stroke()
+ //ctx.fill()
+ ctx.setLineDash([]);
+ ctx.restore()
+ }
+ };
+ level.setPosToSpawn(30, -2000); //normal spawn
+ level.exit.x = 1375;
+ level.exit.y = -1500;
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom + 800)
+ document.body.style.backgroundColor = "#d8dadf";
+ spawn.mapRect(-225, -1950, 350, 75);
+ spawn.mapRect(225, -1950, 50, 75);
+ spawn.mapRect(-250, -2025, 50, 150);
+ spawn.mapRect(250, -2025, 50, 150);
+ spawn.mapRect(-250, -2250, 50, 125);
+ spawn.mapRect(-225, -2325, 500, 100);
+ spawn.mapRect(250, -2250, 50, 125);
+ spawn.mapRect(-100, -2400, 250, 100);
+ spawn.mapRect(-25, -2475, 100, 100);
+ spawn.mapRect(125, -2350, 50, 50);
+ spawn.mapRect(-125, -2350, 50, 50);
+ spawn.mapRect(-50, -2425, 50, 50);
+ spawn.mapRect(50, -2425, 50, 50);
+ spawn.mapRect(-250, -2350, 50, 50);
+ spawn.mapRect(250, -2350, 50, 50);
+ spawn.mapRect(-75, -1975, 200, 50);
+ spawn.mapRect(-50, -2000, 150, 50);
+ spawn.mapRect(100, -1950, 50, 75);
+ spawn.mapRect(-75, -2250, 200, 50);
+ spawn.mapRect(-50, -2225, 150, 50);
+ spawn.mapRect(-2950, -1900, 3100, 900);
+ spawn.mapRect(225, -1900, 2875, 900);
+ spawn.mapRect(-2950, -600, 6050, 450);
+ spawn.mapRect(-3050, -500, 200, 350);
+ spawn.mapRect(-3150, -400, 200, 250);
+ spawn.mapRect(-3250, -300, 200, 150);
+ spawn.mapRect(2950, -1050, 150, 500);
+ spawn.mapRect(-4675, -1900, 1825, 200);
+ spawn.mapRect(-5325, -1900, 675, 900);
+ spawn.mapRect(-5325, -250, 2100, 100);
+ spawn.mapRect(-5325, -600, 675, 450); // -
+ spawn.mapRect(-4700, -500, 150, 350);
+ spawn.mapRect(-4650, -400, 200, 250);
+ spawn.mapRect(-4550, -300, 200, 150);
+ spawn.mapRect(-3875, -1025, 100, 100);
+ spawn.mapRect(-3800, -1050, 50, 50);
+ spawn.mapRect(-3900, -1050, 50, 50);
+ spawn.mapRect(-3800, -950, 50, 50);
+ spawn.mapRect(-3900, -950, 50, 50);
+ spawn.mapRect(-6925, -1175, 1700, 175);
+ spawn.mapRect(-6925, -600, 1725, 175);
+ spawn.mapRect(-7700, -600, 800, 425);// -
+ spawn.mapRect(-7800, -2950, 175, 2775);
+ spawn.mapRect(-7075, -2950, 175, 1950);
+ spawn.mapRect(-9150, -2975, 1525, 175);
+ spawn.mapRect(-7075, -2975, 1150, 175);
+ spawn.mapRect(-6100, -3900, 175, 1100);
+ spawn.mapRect(-9150, -3975, 3225, 175);
+ spawn.mapRect(-9175, -3850, 75, 75);
+ spawn.mapRect(-9625, -3825, 500, 150);
+ spawn.mapRect(-9650, -3725, 75, 75);
+ spawn.mapRect(-10100, -3700, 500, 150);
+ spawn.mapRect(-10100, -2975, 975, 175);
+ spawn.mapRect(-10125, -3600, 75, 75);
+ spawn.mapRect(-10575, -3575, 500, 150);
+ spawn.mapRect(-10575, -2975, 500, 175);
+ spawn.mapRect(-11325, -2975, 250, 175);
+ spawn.mapRect(-11325, -3575, 175, 775);
+ // spawn.mapRect(-11325, -3575, 800, 150);
+ spawn.mapRect(-11225, -2975, 150, 2000);
+ spawn.mapRect(-10575, -2975, 150, 2500);
+ spawn.mapRect(-11650, -550, 1225, 150);
+ spawn.mapRect(-11650, -1100, 575, 150);
+ spawn.mapRect(-14675, -2525, 2925, 150);
+ spawn.mapRect(-11900, -2525, 150, 1575);
+ spawn.mapRect(-11850, -1100, 250, 150);
+ spawn.mapRect(-11875, -550, 275, 150);
+ spawn.mapRect(-11900, -550, 150, 350);
+ spawn.mapRect(-14675, -2525, 150, 2300);
+ spawn.mapRect(-14675, -375, 2925, 175);
+ spawn.mapRect(2725, -625, 250, 50);
+ spawn.mapRect(2625, -1025, 100, 225);
+ spawn.mapRect(2700, -1025, 300, 125);
+ spawn.mapRect(2625, -612.5, 125, 50);
+ spawn.mapRect(-3950, -1725, 250, 50);
+ spawn.mapRect(-7650, -3825, 600, 50);
+ spawn.mapRect(-13900, -2400, 200, 50);
+ spawn.mapVertex(-11957, -430, '-175 175 0 175 0 0');
+ spawn.mapVertex(-14470, -430, '175 175 0 175 0 0');
+ spawn.mapVertex(-11957, -2319, '-175 -175 0 -175 0 0');
+ spawn.mapVertex(-14470, -2319, '0 0 0 -175 175 -175');
+ //spawn.mapRect(-13900, -2150, 1375, 125);
+ // const sword = function() { //the ultimate blade of las destruction // NO SWORD NO DROPS >:(
+ // mobs.spawn(player.position.x, player.position.y, 5, 30, "transparent");
+ // let me = mob[mob.length - 1];
+ // Matter.Body.setDensity(me, 1);
+ // me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position);
+ // me.collisionFilter.category = cat.bullet;
+ // me.collisionFilter.mask = cat.mob | cat.mobBullet;
+ // me.isDropPowerUp = false;
+ // me.isShielded = true;
+ // me.showHealthBar = false;
+ // me.isUnblockable = true;
+ // me.leaveBody = false;
+ // me.isBadTarget = true;
+ // me.stroke = "transparent";
+ // me.isSword = true;
+ // let index = 0;
+ // let radius = 50;
+ // // const len = cons.length;
+ // // cons[len] = Constraint.create({
+ // // pointA: player.position,
+ // // bodyB: me,
+ // // stiffness: 0.14,
+ // // damping: 0.5
+ // // });
+ // // setTimeout(function(){
+ // // Composite.add(engine.world, cons[cons.length - 1]);
+ // // }, 1)
+ // // cons[len].length = 100 + 1.5 * radius;
+ // me.do = function() {
+ // // this.health = Infinity;//just in case
+ // // for(let i = 0; i < mob.length; i++) {
+ // // if(Matter.Query.collides(this, [mob[i]]).length > 0 && !mob[i].isSword) {
+ // // const dmg = 0.25;//do not nerf
+ // // mob[i].damage(dmg, true);
+ // // simulation.drawList.push({ //add dmg to draw queue
+ // // x: mob[i].position.x,
+ // // y: mob[i].position.y,
+ // // radius: Math.sqrt(dmg) * 50,
+ // // color: simulation.mobDmgColor,
+ // // time: simulation.drawTime
+ // // });
+ // // break
+ // // }
+ // // }
+ // Matter.Body.setPosition(this, {
+ // x: player.position.x + Math.cos(m.angle) * 100,
+ // y: player.position.y - (input.down ? 0 : 30) + Math.sin(m.angle) * 100
+ // })
+ // // this.force.x = Math.cos(m.angle) * 350;
+ // // this.force.y = Math.sin(m.angle) * 350;
+ // Matter.Body.setAngle(this, m.angle + Math.PI * 2);
+ // const setNoseShape = () => {
+ // const mag = radius + radius * 10;
+ // this.vertices[2].x = this.position.x + Math.cos(this.angle) * mag;
+ // this.vertices[2].y = this.position.y + Math.sin(this.angle) * mag;
+ // this.vertices[4].x = this.position.x + Math.cos(this.angle) * mag;
+ // this.vertices[4].y = this.position.y + Math.sin(this.angle) * mag;
+ // this.vertices[0].x = this.position.x + Math.cos(this.angle) * mag;
+ // this.vertices[0].y = this.position.y + Math.sin(this.angle) * mag;
+ // };
+ // const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[2], this.position)), radius * 100)
+ // const spike2 = Vector.mult(Vector.normalise(Vector.sub(this.vertices[4], this.position)), radius * 500)
+ // const spike3 = Vector.mult(Vector.normalise(Vector.sub(this.vertices[0], this.position)), radius * 500)
+ // this.vertices[2].x = this.position.x + spike.x / 100
+ // this.vertices[2].y = this.position.y + spike.y / 100
+ // this.vertices[4].x = this.position.x + spike2.x / 75
+ // this.vertices[4].y = this.position.y + spike2.y / 75
+ // this.vertices[0].x = this.position.x + spike3.x / 75
+ // this.vertices[0].y = this.position.y + spike3.y / 75
+ // if(index == 0) {
+ // setNoseShape();
+ // index++;
+ // }
+ // ctx.save()
+ // ctx.beginPath();
+ // const vertices = this.vertices;
+ // ctx.lineWidth = 100;
+ // ctx.moveTo(vertices[0].x, vertices[0].y);
+ // for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
+ // ctx.lineTo(vertices[0].x, vertices[0].y);
+ // const gradient = ctx.createRadialGradient(this.position.x, this.position.y, 15, this.position.x, this.position.y, Math.abs(275 * Math.sin(simulation.cycle / 50)) + 15);
+ // // Add three color stops
+ // gradient.addColorStop(0, m.eyeFillColor);
+ // gradient.addColorStop(0.9, "white");
+ // gradient.addColorStop(1, "darkgray");
+ // ctx.fillStyle = gradient;
+ // ctx.strokeStyle = "transparent";
+ // ctx.shadowBlur = 10;
+ // ctx.shadowColor = m.eyeFillColor;
+ // ctx.fill();
+ // ctx.stroke();
+ // ctx.restore()
+
+ // const Dx = Math.cos(m.angle);
+ // const Dy = Math.sin(m.angle);
+ // let xElec = this.position.x + 10 * Dx;
+ // let yElec = this.position.y + 10 * Dy;
+ // ctx.beginPath();
+ // ctx.moveTo(xElec, yElec);
+ // const step = 40
+ // for (let i = 0; i < 6; i++) {
+ // xElec += step * (Dx + 1.5 * (Math.random() - 0.5))
+ // yElec += step * (Dy + 1.5 * (Math.random() - 0.5))
+ // ctx.lineTo(xElec, yElec);
+ // }
+ // ctx.strokeStyle = m.eyeFillColor;
+ // ctx.lineWidth = 1.5;
+ // ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ // ctx.stroke(); // Draw it
+ // ctx.setLineDash([]);
+ // if(this.alive && m.energy > 0) {
+ // const gradient = ctx.createRadialGradient(this.position.x, this.position.y, 0, this.position.x, this.position.y, Math.abs(20 * Math.cos(simulation.cycle / 50)));
+ // // Add three color stops
+ // gradient.addColorStop(0, m.eyeFillColor);
+ // gradient.addColorStop(0.9, "white");
+ // gradient.addColorStop(1, "gray");
+ // ctx.save()
+ // ctx.beginPath()
+ // ctx.moveTo(this.position.x, this.position.y)
+ // ctx.arc(this.position.x, this.position.y, 20, 0, 2 * Math.PI)
+ // ctx.fillStyle = gradient;
+ // ctx.strokeStyle = "transparent";
+ // ctx.shadowBlur = 10;
+ // ctx.shadowColor = m.eyeFillColor;
+ // ctx.fill()
+ // ctx.stroke()
+ // ctx.restore()
+ // m.energy -= 0.002;
+
+ // ctx.save()
+ // ctx.translate(this.vertices[2].x, this.vertices[2].y)
+ // ctx.rotate(m.angle + Math.PI / 2)
+ // ctx.beginPath()
+ // ctx.font = "16px Arial";
+ // ctx.fillStyle = "black";
+ // ctx.strokeStyle = "black";
+ // // ctx.fillText("Θ", 0,0 - 110)
+ // // ctx.fillText("ά", 0,15 - 110)
+ // // ctx.fillText("ν", 0,30 - 110)
+ // // ctx.fillText("α", 0,45 - 110)
+ // // ctx.fillText("τ", 0,60 - 110)
+ // // ctx.fillText("ο", 0,75 - 110)
+ // // ctx.fillText("ς", 0,90 - 110)
+ // ctx.fillText("Ω", 0,55)
+ // ctx.fill()
+ // ctx.stroke()
+ // ctx.restore()
+
+ // simulation.drawList.push({
+ // x: this.position.x + Math.floor(Math.random() * 300 - Math.random() * 300),
+ // y: this.position.y + Math.floor(Math.random() * 300 - Math.random() * 300),
+ // radius: 2,
+ // color: m.eyeFillColor,
+ // time: simulation.drawTime
+ // });
+ // } else {
+ // this.death()
+ // powerUps.activated = false
+ // }
+ // // me.onDeath = function() {
+ // // this.removeCons();
+ // // };
+ // }
+ // }
+ //setTimeout(function() {sword();}, 100);
+ const wire = function () {
+ const breakingPoint = -1600;
+ const spawnx = -13800 + Math.floor(Math.random() * 100 - Math.random() * 100);
+ mobs.spawn(spawnx, -2375, 0, 2, "transparent");
+ let me = mob[mob.length - 1];
+ let boss = mob[0];
+ me.collisionFilter.category = cat.body;
+ me.collisionFilter.mask = cat.map;
+ me.g = 0.0003; //required for gravity
+ me.restitution = 0;
+ me.stroke = "transparent"
+ me.freeOfWires = false;
+ me.frictionAir = 0.01;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.isBadTarget = true;
+ me.isUnblockable = true;
+ const wireX = spawnx;
+ const wireY = -2375;
+ //const randomw = Math.floor(Math.random() * 100 - Math.random() * 100);
+ const width = Math.abs(10 + Math.floor(Math.random() * 10 - Math.random() * 10));
+ const randomx = Math.floor(30 * Math.random() - 30 * Math.random());
+ const randomy = Math.floor(10 * Math.random() - 10 * Math.random())
+ me.do = function () {
+ if (this.freeOfWires) {
+ this.gravity();
+ } else {
+ if (boss.position.y > breakingPoint) {
+ this.freeOfWires = true;
+ this.force.y -= -0.0006;
+ this.force.x += Math.random() * boss.velocity.x / 10000;
+ this.fill = "#111";
+ }
+ //move mob to mob
+ Matter.Body.setPosition(this, {
+ x: boss.position.x + randomx,
+ y: boss.position.y + randomy
+ })
+ }
+ //draw wire
+ ctx.beginPath();
+ ctx.moveTo(wireX, wireY);
+ ctx.quadraticCurveTo(wireX, -100, this.position.x, this.position.y);
+ ctx.lineWidth = width;
+ ctx.lineCap = "butt";
+ ctx.strokeStyle = "#111";
+ ctx.stroke();
+ ctx.lineCap = "round";
+ };
+ }
+
+ const ball = function (x, y, radius = 11 * tech.bulletSize, sides = 70) {//superball //also, why is it called superballs?
+ mobs.spawn(x, y, sides, radius, "rgba(0,0,0)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.onHit = function () {
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: 20,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ };
+ Matter.Body.setDensity(me, 0.00001); //normal is 0.001
+ me.timeLeft = 500;
+ me.friction = 0;
+ me.restitution = 1;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ //me.inertia = Infinity;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.map | cat.body;
+ let index = 0;
+ me.do = function () {
+ this.timeLimit();
+ this.alwaysSeePlayer()
+ this.force.y += this.mass * 0.0012;
+ }
+ }
+ const normalBullet = function (x, y, radius = 9, sides = 3) {
+ //bullets
+ mobs.spawn(x, y, sides, radius, "rgba(0,0,0)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position);
+ me.onHit = function () {
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: 20,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ };
+ Matter.Body.setDensity(me, 0.00004); //normal is 0.001
+ me.timeLeft = 220;
+ me.frictionAir = -0.01;
+ me.restitution = -1;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ //me.inertia = Infinity;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = null;
+ me.boss = null;
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].restoreBoss) {
+ me.boss = mob[i];
+ }
+ }
+ let index = 0;
+ me.do = function () {
+ this.timeLimit();
+ this.alwaysSeePlayer()
+ const setNoseShape = () => {
+ const mag = this.radius + this.radius * 10;
+ this.vertices[1].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[1].y = this.position.y + Math.sin(this.angle) * mag;
+ const angle = Math.atan2(this.position.y - me.boss.position.y, this.position.x - me.boss.position.x);
+ Matter.Body.setAngle(this, angle);
+ };
+ const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), radius * 1000)
+ this.vertices[1].x = this.position.x + spike.x / 100
+ this.vertices[1].y = this.position.y + spike.y / 100
+ if (index == 0) {
+ setNoseShape();
+ index++;
+ }
+ if (Matter.Query.collides(this, map).length > 0 || Matter.Query.collides(this, body).length > 0) {
+ const slow = 0.69 //im sorry it looks cool though
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * slow,
+ y: this.velocity.y * slow
+ });
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: 10,
+ color: '#000000',
+ time: simulation.drawTime
+ });
+ if (this.velocity.x == 0 && this.velocity.y == 0) {
+ this.death();
+ }
+ this.frictionAir += 0.0001;
+ Matter.Body.setAngularVelocity(this, 0)
+ }
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles // I wasnt gonna add this but since ya'll would have killed me if I didn't I added this
+ const dmg = 0.013 * simulation.dmgScale;
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: Math.sqrt(dmg) * 200,
+ color: '#000000',
+ time: simulation.drawTime
+ });
+ }
+ };
+ }
+ const foamBullet = function (x, y, radius = 9, sides = 70) { //bullets
+ mobs.spawn(x, y, sides, radius, "rgb(0,0,0)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ Matter.Body.setDensity(me, 0.00005); //normal is 0.001
+ me.timeLeft = 120;
+ // me.g = 0.0005; //required if using this.gravity
+ me.accelMag = 0.00006;
+ me.isVerticesChange = true
+ me.delay = 360 * simulation.CDScale;
+ me.spikeVertex = 0;
+ me.spikeLength = 0;
+ me.isSpikeGrowing = false;
+ me.spikeGrowth = 0;
+ me.isSpikeReset = false;
+ me.frictionAir = 0;
+ me.restitution = 0;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.isUnblockable = true;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.body //| cat.bullet;// | cat.player;
+ me.do = function () {
+ if (this.distanceToPlayer2() < 40000) {
+ this.force = Vector.mult(Vector.normalise(Vector.sub(player.position, this.position)), this.mass * 0.004)
+ const slow = 0.99999999999999999;
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * slow,
+ y: this.velocity.y * slow
+ });
+ }
+ // this.gravity();
+ this.timeLimit();
+ // for (let i = 0, len = this.vertices.length; i < len; i++) {
+ // const dist = Vector.sub(this.seePlayer.position, this.vertices[i]);
+ // const distMag = Vector.magnitude(dist);
+ // const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[i], this.position)), radius * distMag)
+ // this.vertices[i].x = this.position.x + spike.x / 100
+ // this.vertices[i].y = this.position.y + spike.y / 100
+ // }
+ if (this.radius < 50) {
+ const scale = 1.05;
+ Matter.Body.scale(this, scale, scale);
+ this.radius *= scale;
+ }
+ if (Matter.Query.collides(this, map).length > 0 || Matter.Query.collides(this, body).length > 0 && this.speed < 10) {
+ const slow = 0.97
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * slow,
+ y: this.velocity.y * slow
+ });
+ const SCALE = 0.9
+ Matter.Body.scale(this, SCALE, SCALE);
+ this.radius *= SCALE;
+ if (this.radius < 1) {
+ this.death()
+ }
+ } else {
+ this.attach();
+ }
+
+ };
+ me.attach = function () {
+ if (Matter.Query.collides(this, [player]).length > 0) {
+ Matter.Body.setPosition(this, player.position)
+ if (player.speed > 2.5) Matter.Body.setVelocity(player, Vector.mult(player.velocity, 0.94))
+ Matter.Body.setAngularVelocity(player, player.angularVelocity * 0.9);
+ m.damage(0.00003); //balanced? not sure
+ }
+ }
+ };
+
+ const orbital = function (who, radius, phase, speed, radius2) {//basically orbitBot
+ mobs.spawn(who.position.x, who.position.y, 8, 12, "rgba(0,0,0, 1)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ Matter.Body.setDensity(me, 0.01); //normal is 0.001
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.showHealthBar = false;
+ me.isOrbital = true;
+ me.isShielded = true
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.bullet; //cat.player | cat.map | cat.body
+ me.do = function () {
+ //if host is gone
+ if (!who || !who.alive) {
+ this.death();
+ return
+ }
+ //set orbit
+ const time = simulation.cycle * speed + phase
+ const orbit = {
+ x: Math.cos(time),
+ y: Math.sin(time)
+ }
+ Matter.Body.setPosition(this, Vector.add(Vector.add(who.position, who.velocity), Vector.mult(orbit, radius + radius2)))
+ //damage player
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ const dmg = 0.013 * simulation.dmgScale
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: Math.sqrt(dmg) * 200,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ //this.death();
+ }
+ };
+ }
+ const missile = function (where, speed = 0.007, size = 1) {
+ mobs.spawn(where.x, where.y, 3, 20, '#000000');
+ let me = mob[mob.length - 1];
+ me.accelMag = speed;
+ Matter.Body.setDensity(me, 0.0000000000001);
+ me.stroke = 'transparent';
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.map | cat.body;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.onHit = function () {
+ b.explosion(this.position, (tech.isMissileBig ? 230 : 180) + 60 * Math.random())
+ this.death()
+ }
+ me.do = function () {
+ this.seePlayerByHistory();
+ this.alwaysSeePlayer();
+ this.attraction();
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ Matter.Body.setAngle(this, angle);
+ // ctx.beginPath()
+ // ctx.strokeStyle = "rgba(255,155,0,0.5)";
+ // ctx.lineWidth = 15;
+ // ctx.arc(this.vertices[0].x, this.vertices[0].x, 15, 0, 2 * Math.PI);
+ // ctx.stroke()
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: 10,
+ color: `rgba(255,155,0,${Math.random()})`,
+ time: simulation.drawTime
+ });
+ }
+ }
+ const railBullet = function (x, y) {
+ mobs.spawn(x, y, 5, 20, "black");
+ let me = mob[mob.length - 1];
+ me.stroke = "black";
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position);
+ me.onHit = function () {
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: 20,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ };
+ Matter.Body.setDensity(me, 0.00004); //normal is 0.001
+ me.timeLeft = 220;
+ me.frictionAir = -0.01;
+ me.restitution = -1;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ //me.inertia = Infinity;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.player;
+ const radius = 30;
+ let index = 0;
+ me.do = function () {
+ this.timeLimit();
+ this.alwaysSeePlayer()
+ const setNoseShape = () => {
+ const mag = me.radius + me.radius * 10;
+ const angle = Math.atan2(me.seePlayer.position.y - this.position.y, me.seePlayer.position.x - this.position.x);
+ me.vertices[2].x = this.position.x + Math.cos(this.angle) * mag;
+ me.vertices[2].y = this.position.y + Math.sin(this.angle) * mag;
+ me.vertices[4].x = this.position.x + Math.cos(this.angle) * mag;
+ me.vertices[4].y = this.position.y + Math.sin(this.angle) * mag;
+ me.vertices[0].x = this.position.x + Math.cos(this.angle) * mag;
+ me.vertices[0].y = this.position.y + Math.sin(this.angle) * mag;
+ Matter.Body.setAngle(this, angle);
+ };
+ const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[2], me.position)), radius * 1000)
+ const spike2 = Vector.mult(Vector.normalise(Vector.sub(this.vertices[4], me.position)), radius * 1000)
+ const spike3 = Vector.mult(Vector.normalise(Vector.sub(this.vertices[0], me.position)), radius * 1000)
+ me.vertices[2].x = this.position.x + spike.x / 100
+ me.vertices[2].y = this.position.y + spike.y / 100
+ me.vertices[4].x = this.position.x + spike2.x / 75
+ me.vertices[4].y = this.position.y + spike2.y / 75
+ me.vertices[0].x = this.position.x + spike3.x / 75
+ me.vertices[0].y = this.position.y + spike3.y / 75
+ if (index == 0) {
+ setNoseShape();
+ index++;
+ }
+ if (Matter.Query.collides(this, map).length > 0 || Matter.Query.collides(this, body).length > 0) {
+ const slow = 0.69 //im sorry it looks cool though
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * slow,
+ y: this.velocity.y * slow
+ });
+ // simulation.drawList.push({ //add dmg to draw queue
+ // x: this.position.x,
+ // y: this.position.y,
+ // radius: 10,
+ // color: '#000000',
+ // time: simulation.drawTime
+ // });
+ if (this.velocity.x == 0 && this.velocity.y == 0) {
+ this.death();
+ }
+ this.frictionAir += 0.0001;
+ Matter.Body.setAngularVelocity(this, 0)
+ }
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles // I wasnt gonna add this but since ya'll would have killed me if I didn't I added this
+ const dmg = 0.013 * simulation.dmgScale;
+ m.damage(dmg);
+ // simulation.drawList.push({ //add dmg to draw queue
+ // x: this.position.x,
+ // y: this.position.y,
+ // radius: Math.sqrt(dmg) * 200,
+ // color: '#000000',
+ // time: simulation.drawTime
+ // });
+ }
+ };
+ }
+ const grenade = function (x, y, lifeSpan = 90 + Math.ceil(60 / simulation.accelScale), pulseRadius = Math.min(550, 250 + simulation.difficulty * 3), size = 3) {
+ mobs.spawn(x, y, 4, size, "rgb(0,0,0)"); //rgb(215,80,190)
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.onHit = function () {
+ this.explode(this.mass);
+ };
+ Matter.Body.setDensity(me, 0.00004); //normal is 0.001
+
+ me.lifeSpan = lifeSpan;
+ me.timeLeft = me.lifeSpan;
+ // me.g = 0.0002; //required if using this.gravity
+ me.frictionAir = 0;
+ me.restitution = 0.8;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.onDeath = function () {
+ //damage player if in range
+ if (Vector.magnitude(Vector.sub(player.position, this.position)) < pulseRadius && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage
+ m.damage(0.015 * simulation.dmgScale);
+ }
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: pulseRadius,
+ color: "rgba(0,0,0,0.3)",
+ time: simulation.drawTime
+ });
+ };
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.map | cat.body | cat.player
+ // me.collisionFilter.mask = 0
+ me.do = function () {
+ this.timeLimit();
+ ctx.save()
+ ctx.beginPath(); //draw explosion outline
+ ctx.arc(this.position.x, this.position.y, pulseRadius * (1.01 - this.timeLeft / this.lifeSpan), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ ctx.fillStyle = "rgba(0,0,0,0.05)";
+ ctx.fill();
+ ctx.restore()
+ };
+ }
+ const sniper = function (x, y, radius = 30) {
+ mobs.spawn(x, y, 8, radius, '#00000000');
+ let me = mob[mob.length - 1];
+ me.accelMag = 0.0003
+ me.stroke = 'transparent';
+ //me.isBoss = true;
+ me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.seeAtDistance2 = 20000000 //14000 vision range
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position);
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.showHealthBar = false
+ Matter.Body.setDensity(me, 0.01)
+ me.fireDir = { x: 0, y: 0 }
+ me.seePlayerFreq = 0
+ me.repulsionRange = 400000 + radius * radius;
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob | cat.mobBullet
+ me.do = function () {
+ this.seePlayerCheck();
+ this.attraction();
+ this.repulsion();
+ this.search()
+ if (this.seePlayer.recall) {
+ const h = this.radius * 0.3;
+ const w = this.radius * 2;
+ const x = this.position.x - w / 2;
+ const y = this.position.y - w * 0.7;
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(x, y, w, h);
+ ctx.fillStyle = "rgba(0,255,255,0.7)";
+ ctx.fillRect(x, y, w * this.health, h);
+ }
+ if (this.health < 1) {
+ this.health += 0.0005; //regen
+ }
+ ctx.save()
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ if (this.seePlayer.recall > 0 && this.distanceToPlayer2() > this.repulsionRange) {
+ var grd2 = ctx.createLinearGradient(0, 0, -150, 0);
+ // grd2.addColorStop(0, 'rgba(255, 255, 155, 0.8)');
+ // grd2.addColorStop(1, 'rgba(255, 200, 0, 0.1)');
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(-18, -25);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(-18, 25);
+ ctx.lineTo(-50 - 100 * Math.random(), 0);
+ ctx.fill();
+ } else if (this.distanceToPlayer2() < this.repulsionRange) {
+ var grd2 = ctx.createLinearGradient(0, 0, 80, 0);
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(20, -16);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(20, 16);
+ ctx.lineTo(35 + 43 * Math.random(), 0);
+ ctx.fill();
+ }
+ ctx.restore()
+ ctx.save()
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.beginPath(); //eye
+ ctx.arc(15, 0, 3.5, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(255, 0, 0, ${this.health * this.health})`;
+ ctx.fill()
+ ctx.restore()
+ //set direction to turn to fire
+ if (this.seePlayer.recall && !(simulation.cycle % 30)) {
+ this.seePlayer.recall -= 10;
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ spawn.sniperBullet(this.position.x, this.position.y, 7 + Math.ceil(this.radius / 15), 5);
+ const v = 10 + 8 * simulation.accelScale;
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ }
+ };
+ }
+ const laserEM = function (x, y, radius = 30) {
+ mobs.spawn(x, y, 8, radius, '#00000000');
+ let me = mob[mob.length - 1];
+ me.accelMag = 0.0003
+ me.stroke = 'transparent';
+ //me.isBoss = true;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.seeAtDistance2 = 20000000 //14000 vision range
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position);
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.showHealthBar = false
+ Matter.Body.setDensity(me, 0.01)
+ me.seePlayerFreq = 0
+ me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position;
+ me.swordDamage = 0.025 * simulation.dmgScale
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob | cat.mobBullet
+ me.repulsionRange = 50000;
+ me.do = function () {
+ this.repulsion();
+ this.search()
+ if (this.seePlayer.recall) {
+ const h = this.radius * 0.3;
+ const w = this.radius * 2;
+ const x = this.position.x - w / 2;
+ const y = this.position.y - w * 0.7;
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(x, y, w, h);
+ ctx.fillStyle = "rgba(0,255,255,0.7)";
+ ctx.fillRect(x, y, w * this.health, h);
+ }
+ if (this.health < 1) {
+ this.health += 0.0005; //regen
+ }
+ if (this.seePlayer.recall) {
+ this.laserSword(this.position, Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x), 500 * Math.random());
+ }
+ ctx.save()
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ if (this.seePlayer.recall > 0 && this.distanceToPlayer2() > this.repulsionRange) {
+ var grd2 = ctx.createLinearGradient(0, 0, -150, 0);
+ // grd2.addColorStop(0, 'rgba(255, 255, 155, 0.8)');
+ // grd2.addColorStop(1, 'rgba(255, 200, 0, 0.1)');
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(-18, -25);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(-18, 25);
+ ctx.lineTo(-50 - 100 * Math.random(), 0);
+ ctx.fill();
+ } else if (this.distanceToPlayer2() < this.repulsionRange) {
+ var grd2 = ctx.createLinearGradient(0, 0, 80, 0);
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(20, -16);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(20, 16);
+ ctx.lineTo(35 + 43 * Math.random(), 0);
+ ctx.fill();
+ }
+ ctx.restore()
+ ctx.save()
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.beginPath(); //eye
+ ctx.arc(15, 0, 3.5, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(255, 0, 0, ${this.health * this.health})`;
+ ctx.fill()
+ ctx.restore()
+ this.seePlayerCheck();
+ this.attraction();
+ }
+ me.laserSword = function (where, angle, length) {
+ const sub = Vector.sub(this.seePlayer.position, this.position)
+ const unit = Vector.normalise(sub)
+ const path = [{
+ x: this.position.x + 20 * Math.cos(this.angle),
+ y: this.position.y + 20 * Math.sin(this.angle)
+ },
+ {
+ x: this.position.x + (120 + 400) * Math.sqrt(Math.random()) * Math.cos(this.angle),
+ y: this.position.y + (120 + 400) * Math.sqrt(Math.random()) * Math.sin(this.angle)
+ }
+ ];
+ this.seePlayer.recall -= 3;
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: vertices[j], v2: vertices[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: vertices[0], v2: vertices[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + length * Math.cos(angle), y: where.y + length * Math.sin(angle) };
+ // vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [player]);
+ if (best.who && (best.who === player) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "#50f";
+ ctx.lineWidth = 1.5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ ctx.lineWidth = 20;
+ ctx.strokeStyle = "rgba(80,0,255,0.07)";
+ ctx.stroke(); // Draw it
+
+ const Dx = Math.cos(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x));
+ const Dy = Math.sin(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x));
+ let xElec = this.position.x + 40 * Dx;
+ let yElec = this.position.y + 40 * Dy;
+ ctx.beginPath();
+ ctx.moveTo(xElec, yElec);
+ const step = 40
+ for (let i = 0; i < 6; i++) {
+ xElec += step * (Dx + 1.5 * (Math.random() - 0.5))
+ yElec += step * (Dy + 1.5 * (Math.random() - 0.5))
+ ctx.lineTo(xElec, yElec);
+ }
+ ctx.strokeStyle = "#50f";
+ ctx.lineWidth = 1.5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ };
+ // if(powerUps.pass == undefined) {
+ // let pass = {pass:true, activated:false};
+ // Object.assign(powerUps, pass)
+ // }
+ // const loadOut = {
+ // loadOut: {
+ // name: "loadOut",
+ // color: "#000000", //"hsl(248,100%,65%)",
+ // size() { return 40 },
+ // effect() {
+ // if(m.alive) {
+ // // tech.damage *= 2;
+ // let text = "";
+ // if (!tech.isSuperDeterminism) { text += `
${tech.isCancelTech ? "?":"✕"}
`; };
+ // text += `
Blessing Of Sal `;
+ // text += `
`;
+ // text += `
`;
+ // text += `
`;
+ // if(powerUps.pass == true) {
+ // text += `
Press Shift to summon the
Mythical Las Slayer Drains Energy
`;
+ // }
+ // document.getElementById("choose-grid").innerHTML = text;
+ // powerUps.showDraft();//no known bugs ig idk, im keep this as it is
+ // }
+ // },
+ // choose(index) {
+ // if(index == 1) {
+ // tech.squirrelFx += 0.25;
+ // tech.squirrelJump += 0.1;
+ // m.setMovement();
+ // powerUps.endDraft("buff");
+ // } else if(index == 2) {
+ // simulation.dmgScale *= 0.95;
+ // powerUps.endDraft("buff");
+ // } else if(index == 3) {
+ // m.dmgScale *= 1.1;
+ // powerUps.endDraft("buff");
+ // } else if(index == 4) { //sword!
+ // powerUps.pass = false;
+ // addEventListener("keydown", function(event) {
+ // if(event.key == "Shift" && powerUps.activated == false) {
+ // sword()
+ // powerUps.activated = true;
+ // } else if(event.key == "Shift" && powerUps.activated == true) {
+ // for(let i = 0; i < mob.length; i++) {
+ // if(mob[i].isSword) {
+ // mob[i].death()
+ // }
+ // powerUps.activated = false;
+ // }
+ // }
+ // })
+ // powerUps.endDraft("buff");
+ // }
+ // }
+ // }
+ // }
+ // Object.assign(powerUps, loadOut)
+ const restoreBoss = function (x, y, radius = 30) { //ATTENTION LANDGREEN: RESTOREBOSS WILL NOT DROP ANY TECH, NOR WILL THERE BE ANY IN THE MAP. DO NOT ADD ANY TECH TO MY MAP
+ mobs.spawn(x, y, 8, radius, 'transparent');
+ let me = mob[mob.length - 1];
+ me.stroke = 'transparent';
+ let aim = '#FFFFFF';
+ me.accelMag = 0.0006
+ me.isBoss = true;
+ me.restoreBoss = true;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.seeAtDistance2 = 20000000 //14000 vision range
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.showHealthBar = false
+ Matter.Body.setDensity(me, m.maxHealth / (simulation.difficulty < 5 ? 0.5 : simulation.difficulty / simulation.difficultyMode))
+ me.seePlayerFreq = 0
+ me.swordDamage = 0.025 * simulation.dmgScale
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob | cat.mobBullet
+ me.repulsionRange = 500000;
+ me.isDropPowerUp = false;
+ //Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) });
+ let index = 0;
+ me.curlRange = 10000; //xd
+ me.fieldPhase = 0;
+ me.energy = 1;
+ me.maxEnergy = 1;
+ me.immuneCycle = 0;
+ me.cycle = 0;
+ // me.onDeath = function() {
+ // powerUps.spawn(this.position.x, this.position.y, "loadOut");
+ // }
+ for (let i = 0; i < b.totalBots(); i++) { //normal orbitals look too boring, so...
+ orbital(me, 190 + 130 * tech.isOrbitBotUpgrade, (index / b.totalBots()) * 2 * Math.PI, 0.05, Math.floor(Math.sin(simulation.cycle / 10) * 100)); //who, radius, phase, speed
+ index++;
+ }
+ me.do = function () {
+ if (this.position.x > -11500 && this.position.x < 10510) {// doesn't get one tapped by the elevator
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.map | cat.mob | cat.mobBullet;
+ } else {
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob | cat.mobBullet;
+ }
+ this.cycle++;
+ if ((Matter.Query.ray(map, player.position, this.position).length === 0) == false) {
+ this.seePlayer.recall = null;
+ }
+ if (this.seePlayer.recall) { //fields
+ if (m.fieldMode == 0 && this.distanceToPlayer2() < 200000) {
+ if (Vector.magnitude(Vector.sub(m.pos, this.position)) - this.radius < m.fieldRange) {
+ this.pushM();
+ }
+ this.drawField();
+ // this.repel();
+ }
+ if (m.fieldMode == 2) {
+ if (this.distanceToPlayer2() < 200000) {
+ if (Vector.magnitude(Vector.sub(m.pos, this.position)) - this.radius < m.fieldRange) {
+ this.pushM();
+ }
+ this.drawField()
+ }
+ if (tech.isPerfectBrake) { //cap player and bullet speed around restoreBoss //mobs basically can't hit you when you have this, so to make it fair...
+ const wave = Math.cos(m.cycle * 0.022);
+ const range = 200 + 140 * wave + 150 * m.energy
+ const distance = Vector.magnitude(Vector.sub(this.position, m.pos))
+ const cap = this.immuneCycle > this.cycle ? 8 : 4
+ if (distance < range) {
+ if (player.speed > cap && Vector.dot(player.velocity, Vector.sub(this.position, m.pos)) > 0) { // if velocity is directed towards player
+ Matter.Body.setVelocity(player, Vector.mult(Vector.normalise(player.velocity), cap)); //set velocity to cap, but keep the direction
+ }
+ }
+ for (let i = 0; i < bullet.length; i++) {
+ const distance2 = Vector.magnitude(Vector.sub(this.position, bullet[i].position))
+ if (distance2 < range) {
+ if (bullet[i].speed > cap && Vector.dot(bullet[i].velocity, Vector.sub(this.position, bullet[i].position)) > 0) { // if velocity is directed towards player
+ Matter.Body.setVelocity(bullet[i], Vector.mult(Vector.normalise(bullet[i].velocity), cap)); //set velocity to cap, but keep the direction
+ }
+ }
+ }
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, range, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.08)";
+ ctx.fill();
+ }
+ }
+ if (m.fieldMode == 5 && this.distanceToPlayer2() < 200000) {
+ this.laserSword(this.position, Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x), 500 * Math.random());
+ }
+ if (m.fieldMode == 9) {
+ if (this.distanceToPlayer2() < 300000) {
+ this.teleportAway() //blink but reversed
+ }
+ }
+ }
+ if (m.immuneCycle > m.cycle) {
+ me.damageReduction = 0;
+ } else {
+ me.damageReduction = 1;
+ }
+ this.repulsion();
+ this.seePlayerCheck();
+ this.attraction();
+ this.lostPlayer();
+ if (this.speed > 10) { // speed cap
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * 0.99,
+ y: this.velocity.y * 0.99
+ });
+ }
+ if (this.seePlayer.recall) {
+ const angle = Math.atan2(this.position.y - player.position.y, this.position.x - player.position.x);
+ let positionR = { x: 500 * Math.cos(angle) + mob[0].position.x, y: 500 * Math.sin(angle) + mob[0].position.y };
+ let isWall = (Matter.Query.ray(map, mob[0].position, positionR).length === 0);
+ let isBlock = (Matter.Query.ray(body, mob[0].position, positionR).length === 0);
+ if (isWall == false || isBlock == false) {
+ this.force.x -= Math.cos(angle) * 10;
+ this.force.y -= Math.sin(angle) * 10;
+ }
+ }
+ if (this.seePlayer.recall) {
+ const angle = Math.atan2(this.position.y - player.position.y, this.position.x - player.position.x) - Math.PI * 1.5;
+ let positionR = { x: 5000 * Math.cos(angle) + mob[0].position.x, y: 5000 * Math.sin(angle) + mob[0].position.y };
+ let isBullet = (Matter.Query.ray(bullet, mob[0].position, positionR).length === 0);
+ if (isBullet == false) {
+ this.force.x -= Math.cos(angle) * 30;
+ this.force.y -= Math.sin(angle) * 30;
+ }
+ }
+ if (this.seePlayer.recall) {
+ const angle = Math.atan2(this.position.y - player.position.y, this.position.x - player.position.x) - Math.PI * 2.5;
+ let positionR = { x: 5000 * Math.cos(angle) + mob[0].position.x, y: 5000 * Math.sin(angle) + mob[0].position.y };
+ let isBullet = (Matter.Query.ray(bullet, mob[0].position, positionR).length === 0);
+ if (isBullet == false) {
+ this.force.x -= Math.cos(angle) * 30;
+ this.force.y -= Math.sin(angle) * 30;
+ }
+ }
+ if (this.seePlayer.recall) {
+ const h = this.radius * 0.3;
+ const w = this.radius * 2;
+ const x = this.position.x - w / 2;
+ const y = this.position.y - w * 0.7;
+ ctx.fillStyle = "rgba(10, 10, 10, 0.3)";
+ ctx.fillRect(x, y, w, h);
+ ctx.fillStyle = "rgba(0,0,0,0.7)";
+ ctx.fillRect(x, y, w * this.energy, h);
+ }
+ if (this.health < 1) {
+ this.health += 0.0001; //regen
+ } else if (this.health < 1) {
+ this.health += 0.00005; //reduced regen
+ }
+ if (this.energy < 0) {//energy thingy
+ this.energy = 0;
+ } else if (this.energy > this.maxEnergy) {
+ this.energy = this.maxEnergy;
+ } else if (this.energy < this.maxEnergy) {
+ this.energy += 0.001;
+ }
+ ctx.save()
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ if (this.seePlayer.recall > 0 && this.distanceToPlayer2() > this.repulsionRange) {
+ ctx.globalAlpha = (this.immuneCycle < this.cycle) ? 1 : 0.5
+ var grd2 = ctx.createLinearGradient(0, 0, -150, 0);
+ // grd2.addColorStop(0, 'rgba(255, 255, 155, 0.8)');
+ // grd2.addColorStop(1, 'rgba(255, 200, 0, 0.1)');
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(-18, -25);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(-18, 25);
+ ctx.lineTo(-50 - 100 * Math.random(), 0);
+ ctx.fill();
+ } else if (this.distanceToPlayer2() < this.repulsionRange) {
+ ctx.globalAlpha = (this.immuneCycle < this.cycle) ? 1 : 0.5
+ var grd2 = ctx.createLinearGradient(0, 0, 80, 0);
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(20, -16);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(20, 16);
+ ctx.lineTo(35 + 43 * Math.random(), 0);
+ ctx.fill();
+ }
+ ctx.restore()
+ ctx.save()
+ ctx.globalAlpha = (this.immuneCycle < this.cycle) ? 1 : 0.5
+ ctx.translate(this.position.x, this.position.y)
+ ctx.rotate(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ if (this.health > 0.5) {
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.beginPath(); //eye
+ ctx.arc(15, 0, 3.5, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(255, 0, 0, ${this.health * this.health})`;
+ ctx.fill()
+ ctx.restore()
+ } else {
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ if (!(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x) > -Math.PI / 2 && Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x) < Math.PI / 2)) ctx.scale(1, -1); //here is the flip
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(2, -6, 7, 0, 2 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(25, -6, 7, 0.25 * Math.PI, 1.6 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(2, -10, 9, 1.25 * Math.PI, 1.75 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(25, -10, 9, 1.25 * Math.PI, 1.4 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(18, 13, 10, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient;
+ ctx.fill();
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(18, 13, 6, 0, 2 * Math.PI);
+ ctx.fillStyle = "#555";
+ ctx.fill();
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(3, -6, 3, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(26, -6, 3, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.stroke();
+ ctx.restore();
+ }
+ if (m.fieldMode == 1) { //render over I think
+ if (this.energy > 0.1) {
+ this.harmonic3Phase();
+ }
+ }
+ if (m.fieldMode == 7) {
+ this.locatePlayer();
+ }
+ if (m.fieldMode == 8) {
+ me.pilotWave()
+ }
+ if (m.fieldMode == 3) {
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ me.damageReduction = 0.5;
+ me.accelMag = 0.0012;
+ if (!(simulation.cycle % Math.floor(100 + 90 * Math.random() * simulation.CDScale))) {
+ this.diveAttack()
+ }
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, 1000, 0, 2 * Math.PI);
+ ctx.fillStyle = "#f5f5ff";
+ ctx.strokeStyle = "#f5f5ff55";
+ ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
+ ctx.globalCompositeOperation = "difference";
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over";
+ ctx.stroke()
+ ctx.setLineDash([]);
+ } else {
+ me.accelMag = 0.0006;
+ }
+ if (this.immuneCycle > this.cycle) {
+ this.damageReduction = 0;
+ } else {
+ if (m.fieldMode == 3) {
+ this.damageReduction = 0.5;
+ } else {
+ this.damageReduction = 1;
+ }
+ }
+ if (m.fieldMode == 6) {
+ this.timeAttack();
+ ctx.globalCompositeOperation = "saturation"
+ ctx.fillStyle = "#ccc";
+ ctx.fillRect(-50000, -50000, 100000, 100000)
+ ctx.globalCompositeOperation = "source-over"
+ // stop time
+ // m.isBodiesAsleep = true;
+ // function sleep(who) {
+ // for (let i = 0, len = who.length; i < len; ++i) {
+ // if (!who[i].isSleeping) {
+ // who[i].storeVelocity = who[i].velocity
+ // who[i].storeAngularVelocity = who[i].angularVelocity
+ // }
+ // Matter.Sleeping.set(who[i], true)
+ // }
+ // }
+ // sleep(mob);
+ // sleep(body);
+ // sleep(bullet);
+ // sleep([player]);
+ // simulation.cycle--;
+ }
+ if (this.seePlayer.recall) { //fields
+ this.gun()
+ }
+ }
+ me.laserSword = function (where, angle, length) {
+ const sub = Vector.sub(this.seePlayer.position, this.position)
+ const unit = Vector.normalise(sub)
+ const path = [{
+ x: this.position.x + 20 * Math.cos(this.angle),
+ y: this.position.y + 20 * Math.sin(this.angle)
+ },
+ {
+ x: this.position.x + (120 + 400) * Math.sqrt(Math.random()) * Math.cos(this.angle),
+ y: this.position.y + (120 + 400) * Math.sqrt(Math.random()) * Math.sin(this.angle)
+ }
+ ];
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: vertices[j], v2: vertices[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: vertices[0], v2: vertices[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + length * Math.cos(angle), y: where.y + length * Math.sin(angle) };
+ // vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [player]);
+ if (best.who && (best.who === player) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(0,0,0,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 1.5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ ctx.lineWidth = 20;
+ ctx.strokeStyle = "rgba(0,0,0,0.07)";
+ ctx.stroke(); // Draw it
+
+ const Dx = Math.cos(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x));
+ const Dy = Math.sin(Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x));
+ let xElec = this.position.x + 40 * Dx;
+ let yElec = this.position.y + 40 * Dy;
+ ctx.beginPath();
+ ctx.moveTo(xElec, yElec);
+ const step = 40
+ for (let i = 0; i < 6; i++) {
+ xElec += step * (Dx + 1.5 * (Math.random() - 0.5))
+ yElec += step * (Dy + 1.5 * (Math.random() - 0.5))
+ ctx.lineTo(xElec, yElec);
+ }
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 1.5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ me.drawField = function () {
+ if (m.fieldMode != 2) {
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x)
+ const range = m.fieldRange;
+ ctx.save()
+ ctx.beginPath();
+ ctx.fillStyle = "rgba(0,0,0," + Math.min(0.6, (0.04 + m.energy * (0.1 + 0.11 * Math.random()))) + ")";
+ ctx.arc(this.position.x, this.position.y, range, angle - Math.PI * m.fieldArc, angle + Math.PI * m.fieldArc, false);
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ let eye = 13;
+ if (m.fieldMode == 2) {
+ eye = 30
+ }
+ let aMag = 0.75 * Math.PI * m.fieldArc
+ let a = angle + aMag
+ let cp1x = this.position.x + 0.6 * range * Math.cos(a)
+ let cp1y = this.position.y + 0.6 * range * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, this.position.x + eye * Math.cos(angle), this.position.y + eye * Math.sin(angle))
+ a = angle - aMag
+ cp1x = this.position.x + 0.6 * range * Math.cos(a)
+ cp1y = this.position.y + 0.6 * range * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, this.position.x + 1 * range * Math.cos(angle - Math.PI * m.fieldArc), this.position.y + 1 * range * Math.sin(angle - Math.PI * m.fieldArc))
+ ctx.fill();
+ // ctx.lineTo(this.position.x + eye * Math.cos(angle), this.position.y + eye * Math.sin(angle));
+
+ //draw random lines in field for cool effect
+ let offAngle = angle + 1.7 * Math.PI * m.fieldArc * (Math.random() - 0.5);
+ ctx.beginPath();
+ eye = 15;
+ ctx.moveTo(this.position.x + eye * Math.cos(angle), this.position.y + eye * Math.sin(angle));
+ ctx.lineTo(this.position.x + range * Math.cos(offAngle), this.position.y + range * Math.sin(offAngle));
+ ctx.strokeStyle = "rgba(0,0,0,0.6)";
+ ctx.lineWidth = 1;
+ ctx.stroke();
+ ctx.restore()
+ } else {
+ ctx.save()
+ ctx.beginPath();
+ const wave = Math.cos(m.cycle * 0.022);
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x)
+ ctx.arc(this.position.x, this.position.y, m.fieldRange, angle - Math.PI * m.fieldArc, angle + Math.PI * m.fieldArc, false);
+ ctx.lineWidth = 2.5 - 1.5 * wave;
+ ctx.stroke();
+ const curve = 0.57 + 0.04 * wave
+ const aMag = (1 - curve * 1.2) * Math.PI * m.fieldArc
+ let a = angle + aMag
+ let cp1x = this.position.x + curve * m.fieldRange * Math.cos(a)
+ let cp1y = this.position.y + curve * m.fieldRange * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, this.position.x + 30 * Math.cos(angle), this.position.y + 30 * Math.sin(angle))
+ a = angle - aMag
+ cp1x = this.position.x + curve * m.fieldRange * Math.cos(a)
+ cp1y = this.position.y + curve * m.fieldRange * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, this.position.x + 1 * m.fieldRange * Math.cos(angle - Math.PI * m.fieldArc), this.position.y + 1 * m.fieldRange * Math.sin(angle - Math.PI * m.fieldArc))
+ ctx.fill();
+ ctx.restore()
+ }
+ }
+ me.pushM = function () {
+ const unit = Vector.normalise(Vector.sub(this.position, player.position))
+ if (tech.blockDmg) {
+ Matter.Body.setVelocity(player, { x: 0.5 * player.velocity.x, y: 0.5 * player.velocity.y });
+ //draw electricity
+ const step = 40
+ ctx.beginPath();
+ for (let i = 0, len = 0.8 * tech.blockDmg; i < len; i++) {
+ let x = this.position.x - 20 * unit.x;
+ let y = this.position.y - 20 * unit.y;
+ ctx.moveTo(x, y);
+ for (let i = 0; i < 8; i++) {
+ x += step * (-unit.x + 1.5 * (Math.random() - 0.5))
+ y += step * (-unit.y + 1.5 * (Math.random() - 0.5))
+ ctx.lineTo(x, y);
+ }
+ }
+ if (m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles
+ m.damage(0.025 * simulation.dmgScale)
+ }
+ ctx.lineWidth = 3;
+ ctx.strokeStyle = "#000";
+ ctx.stroke();
+ }
+ const massRoot = Math.sqrt(Math.min(12, Math.max(0.15, player.mass))); // masses above 12 can start to overcome the push back //idk
+ Matter.Body.setVelocity(player, {
+ x: this.velocity.x - (15 * unit.x) / massRoot,
+ y: this.velocity.y - (15 * unit.y) / massRoot
+ });
+ }
+ me.diveAttack = function () {
+ const forceMag = this.accelMag * this.mass;
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ this.force.x += 150 * forceMag * Math.cos(angle);
+ this.force.y += 150 * forceMag * Math.sin(angle);
+ ctx.beginPath()
+ ctx.moveTo(this.position.x + Math.sin(angle), this.position.y + Math.cos(angle))
+ ctx.lineTo(this.seePlayer.position.x, this.seePlayer.position.y)
+ aim = '#000000';
+ ctx.stroke()
+ }
+ me.phase = 2 * Math.PI * Math.random();
+ me.index2 = 0;
+ me.pilotWave = function () {
+ const rotate = this.cycle * 0.008;
+ this.fieldPhase += 0.002;
+ const off1 = 1 + 0.01 * Math.sin(this.fieldPhase);
+ const off2 = 1 - 0.01 * Math.cos(this.fieldPhase);
+ ctx.save()
+ ctx.beginPath();
+ ctx.ellipse(player.position.x, player.position.y, 1.2 * 200 * off1, 1.2 * 150 * off2, rotate, 0, 2 * Math.PI);
+ ctx.globalCompositeOperation = "exclusion"; //"exclusion" "difference";
+ ctx.fillStyle = "#ffffff"; //"#eef";
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over";
+ ctx.beginPath();
+ ctx.ellipse(player.position.x, player.position.y, 1.2 * 200 * off1, 1.2 * 150 * off2, rotate, 0, 2 * Math.PI * m.energy / m.maxEnergy);
+ ctx.strokeStyle = "#000000";
+ ctx.lineWidth = 4;
+ ctx.stroke();
+ ctx.restore()
+ const range = this.curlRange / 15, mag = -50;
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ const applyCurl = function (center, array, isAntiGravity = true) {
+ for (let i = 0; i < array.length; ++i) {
+ if (!array[i].isNotHoldable) {
+ const sub = Vector.sub(center, array[i].position)
+ const radius2 = Vector.magnitudeSquared(sub);
+
+ //if too close, like center mob or shield, don't curl // if too far don't curl
+ if (radius2 < range * range && radius2 > 10000) {
+ const curlVector = Vector.mult(Vector.perp(Vector.normalise(sub)), mag)
+ //apply curl force
+ if (array[i].isMobBullet) {
+ Matter.Body.setVelocity(array[i], {
+ x: array[i].velocity.x * 0.97 + curlVector.x * 0.06 - (Math.cos(angle) * 5),
+ y: array[i].velocity.y * 0.97 + curlVector.y * 0.06 - (Math.sin(angle) * 5)
+ })
+ } else {
+ Matter.Body.setVelocity(array[i], {
+ x: array[i].velocity.x * 0.94 + curlVector.x * 0.06 - (Math.cos(angle) * 5),
+ y: array[i].velocity.y * 0.94 + curlVector.y * 0.06 - (Math.sin(angle) * 5)
+ })
+ }
+ if (isAntiGravity) array[i].force.y -= 0.8 * simulation.g * array[i].mass
+ }
+ }
+ }
+ }
+ applyCurl(this.position, [player]);
+ }
+ me.teleportAway = function () {//hehe
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ if (this.seePlayer.recall && !(simulation.cycle % 17)) {
+ const dist = Vector.sub(this.position, this.seePlayer.position);
+ const distMag = Vector.magnitude(dist);
+ const unitVector = Vector.normalise(dist);
+ const rando = (Math.random() - 0.5) * 50;
+ if (distMag < 20000) {
+ Matter.Body.translate(this, Vector.mult(unitVector, distMag + rando));
+ } else {
+ Matter.Body.translate(this, Vector.mult(unitVector, 20000 + rando));
+ }
+ }
+ ctx.lineTo(this.position.x, this.position.y);
+ ctx.lineWidth = radius * 2;
+ ctx.strokeStyle = "rgba(0,0,0,0.08)";
+ ctx.stroke();
+ if (!this.seePlayer.yes) {
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ if (this.seePlayer.recall && !(simulation.cycle % 17)) {
+ const dist = Vector.sub(this.seePlayer.position, this.position);
+ const distMag = Vector.magnitude(dist);
+ const unitVector = Vector.normalise(dist);
+ const rando = (Math.random() - 0.5) * 50;
+ if (distMag < 200000) {
+ Matter.Body.translate(this, Vector.mult(unitVector, distMag + rando));
+ } else {
+ Matter.Body.translate(this, Vector.mult(unitVector, 200000 + rando));
+ }
+ }
+ ctx.lineTo(this.position.x, this.position.y);
+ ctx.lineWidth = radius * 2;
+ ctx.strokeStyle = "rgba(0,0,0,0.08)";
+ ctx.stroke();
+ }
+ }
+ me.timeAttack = function () {
+ if (this.seePlayer.recall && !(simulation.cycle % 30) || this.distanceToPlayer2() < 300) {
+ requestAnimationFrame(() => {
+ simulation.timePlayerSkip(45)
+ simulation.loop(); //ending with a wipe and normal loop fixes some very minor graphical issues where things are draw in the wrong locations
+ }); //wrapping in animation frame prevents errors, probably
+ }
+ }
+ me.harmonic3Phase = function () { //normal standard 3 different 2-d circles
+ if (tech.harmonics === 2) {
+ const fieldRange1 = (0.75 + 0.3 * Math.cos(m.cycle / 23)) * m.fieldRange * m.harmonicRadius
+ const fieldRange2 = (0.68 + 0.37 * Math.cos(m.cycle / 37)) * m.fieldRange * m.harmonicRadius
+ const fieldRange3 = (0.7 + 0.35 * Math.cos(m.cycle / 47)) * m.fieldRange * m.harmonicRadius
+ const netfieldRange = Math.max(fieldRange1, fieldRange2, fieldRange3)
+ ctx.fillStyle = "rgba(0,0,0," + Math.min(0.6, (0.04 + m.energy * (0.1 + 0.11 * Math.random()))) + ")";
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, fieldRange1, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, fieldRange2, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, fieldRange3, 0, 2 * Math.PI);
+ ctx.fill();
+ //360 block
+ if (Vector.magnitude(Vector.sub(player.position, this.position)) - this.radius < netfieldRange) {
+ me.pushM();
+ }
+ for (let i = 0; i < bullet.length; i++) {
+ if (Vector.magnitude(Vector.sub(bullet[i].position, this.position)) - this.radius < netfieldRange) {
+ const dx = bullet[i].position.x - this.position.x;
+ const dy = bullet[i].position.y - this.position.y;
+ const dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < m.fieldRange) {
+ const angle = Math.atan2(dy, dx);
+ const mag = (1500 * bullet[i].mass * simulation.g) / dist;
+ bullet[i].force.x += mag * Math.cos(angle);
+ bullet[i].force.y += mag * Math.sin(angle);
+ }
+ this.energy -= 0.0012;
+ }
+ }
+ } else {
+ const rotation = simulation.cycle * 0.0031
+ const phase = simulation.cycle * 0.023
+ const radius = m.fieldRange * m.harmonicRadius
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = "rgba(0,0,0,0.5)"
+ ctx.fillStyle = `rgba(0,0,0,${Math.min(0.6, m.energy * (0.11 + 0.1 * Math.random()) * (3 / tech.harmonics))})`;
+ // ctx.fillStyle = "rgba(0,0,0," + Math.min(0.7, m.energy * (0.22 - 0.01 * tech.harmonics) * (0.5 + 0.5 * Math.random())) + ")";
+ for (let i = 0; i < tech.harmonics; i++) {
+ ctx.beginPath();
+ ctx.ellipse(this.position.x, this.position.y, radius * Math.abs(Math.sin(phase + i / tech.harmonics * Math.PI)), radius, rotation + i / tech.harmonics * Math.PI, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.stroke();
+ }
+ //360 block
+ if (Vector.magnitude(Vector.sub(player.position, this.position)) - this.radius < radius) {
+ me.pushM();
+ }
+ for (let i = 0; i < bullet.length; i++) {
+ if (Vector.magnitude(Vector.sub(bullet[i].position, this.position)) - this.radius < radius) {
+ const dx = bullet[i].position.x - this.position.x;
+ const dy = bullet[i].position.y - this.position.y;
+ const dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < m.fieldRange) {
+ const angle = Math.atan2(dy, dx);
+ const mag = (1500 * bullet[i].mass * simulation.g) / dist;
+ bullet[i].force.x += mag * Math.cos(angle);
+ bullet[i].force.y += mag * Math.sin(angle);
+ }
+ this.energy -= 0.0012;
+ }
+ }
+ }
+ }
+ me.railGun = function () {
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ const X = this.position.x
+ const Y = this.position.y
+ const unitVector = { x: Math.cos(angle), y: Math.sin(angle) }
+ const unitVectorPerp = Vector.perp(unitVector)
+
+ function magField(mag, arc) {
+ ctx.moveTo(X, Y);
+ ctx.bezierCurveTo(
+ X + unitVector.x * mag, Y + unitVector.y * mag,
+ X + unitVector.x * mag + unitVectorPerp.x * arc, Y + unitVector.y * mag + unitVectorPerp.y * arc,
+ X + unitVectorPerp.x * arc, Y + unitVectorPerp.y * arc)
+ ctx.bezierCurveTo(
+ X - unitVector.x * mag + unitVectorPerp.x * arc, Y - unitVector.y * mag + unitVectorPerp.y * arc,
+ X - unitVector.x * mag, Y - unitVector.y * mag,
+ X, Y)
+ }
+ ctx.fillStyle = `rgba(50,20,100,0.05)`;
+ const magSize = 8 * c * tech.railChargeRate ** 3
+ const arcSize = 6 * c * tech.railChargeRate ** 3
+ for (let i = 3; i < 7; i++) {
+ const MAG = magSize * i * i * (0.93 + 0.07 * Math.random())
+ const ARC = arcSize * i * i * (0.93 + 0.07 * Math.random())
+ ctx.beginPath();
+ magField(MAG, ARC)
+ magField(MAG, -ARC)
+ ctx.fill();
+ }
+ }
+ me.waves = [];
+ me.doLongitudinal = function () {
+ if (!m.isBodiesAsleep) {
+ ctx.strokeStyle = "rgba(0,0,0,0.6)" //"000";
+ ctx.lineWidth = 2 * tech.wavePacketDamage
+ ctx.beginPath();
+ // const end = 1100 * tech.bulletsLastLonger / Math.sqrt(tech.waveReflections * 0.5) //should equal about 1767
+ const end = 1100 * tech.bulletsLastLonger * Math.pow(0.93, tech.waveReflections) //should equal about 1767
+ const damage = 0.0005 * simulation.dmgScale//normal damage for m basically shreds m, so had to nerf this
+ for (let i = this.waves.length - 1; i > -1; i--) {
+ const v1 = Vector.add(this.waves[i].position, Vector.mult(this.waves[i].unit1, this.waves[i].radius))
+ const v2 = Vector.add(this.waves[i].position, Vector.mult(this.waves[i].unit2, this.waves[i].radius))
+ //draw wave
+ ctx.moveTo(v1.x, v1.y)
+ ctx.arc(this.waves[i].position.x, this.waves[i].position.y, this.waves[i].radius, this.waves[i].angle, this.waves[i].angle + this.waves[i].arc);
+ //using small angle linear approximation of circle arc, this will not work if the arc gets large // https://stackoverflow.com/questions/13652518/efficiently-find-points-inside-a-circle-sector
+ let hits = Matter.Query.ray([player], v1, v2, 50) //Matter.Query.ray(bodies, startPoint, endPoint, [rayWidth])
+ for (let j = 0, len = Math.min(30, hits.length); j < len; j++) {
+ player.force.x += 0.01 * (Math.random() - 0.5) * player.mass
+ player.force.y += (0.01 * (Math.random() - 0.5) - simulation.g * 0.25) * player.mass //remove force of gravity
+ Matter.Body.setVelocity(player, { //friction
+ x: player.velocity.x * 0.95,
+ y: player.velocity.y * 0.95
+ });
+ m.damage(damage)
+ }
+ hits = Matter.Query.ray(body, v1, v2, 50)
+ for (let j = 0, len = Math.min(30, hits.length); j < len; j++) {
+ const who = hits[j].body
+ //make them shake around
+ who.force.x += 0.01 * (Math.random() - 0.5) * who.mass
+ who.force.y += (0.01 * (Math.random() - 0.5) - simulation.g * 0.25) * who.mass //remove force of gravity
+
+ let vertices = who.vertices;
+ const vibe = 25
+ ctx.moveTo(vertices[0].x + vibe * (Math.random() - 0.5), vertices[0].y + vibe * (Math.random() - 0.5));
+ for (let j = 1; j < vertices.length; j++) {
+ ctx.lineTo(vertices[j].x + vibe * (Math.random() - 0.5), vertices[j].y + vibe * (Math.random() - 0.5));
+ }
+ ctx.lineTo(vertices[0].x + vibe * (Math.random() - 0.5), vertices[0].y + vibe * (Math.random() - 0.5));
+
+ if (tech.isPhononBlock && !who.isNotHoldable && who.speed < 5 && who.angularSpeed < 0.1) {
+ if (Math.random() < 0.5) b.targetedBlock(who, 50 - Math.min(25, who.mass * 3)) // targetedBlock(who, speed = 50 - Math.min(20, who.mass * 2), range = 1600) {
+ // Matter.Body.setAngularVelocity(who, (0.25 + 0.12 * Math.random()) * (Math.random() < 0.5 ? -1 : 1));
+ who.torque += who.inertia * 0.001 * (Math.random() - 0.5)
+ }
+ }
+ // ctx.stroke(); //draw vibes
+ this.waves[i].radius += tech.waveBeamSpeed * 1.8 * this.waves[i].expanding //expand / move
+ if (this.waves[i].radius > end - 30) {
+ this.waves[i].expanding = -1
+ if (this.waves[i].reflection < 1) this.waves.splice(i, 1) //end
+ } else if (this.waves[i].radius < 25) {
+ this.waves[i].expanding = 1
+ if (this.waves[i].reflection < 1) this.waves.splice(i, 1) //end
+ }
+ }
+ ctx.stroke();
+ }
+ }
+ me.lasers = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ };
+
+ const seeRange = 7000;
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ const look = {
+ x: where.x + seeRange * Math.cos(angle),
+ y: where.y + seeRange * Math.sin(angle)
+ };
+ // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ vertexCollision(where, look, body);
+ if (!m.isCloak) vertexCollision(where, look, [player]);
+ if (best.who && (best.who === player) && m.immuneCycle < m.cycle) {
+ const dmg = 0.0011 * simulation.dmgScale;
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: dmg * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ //draw beam
+ if (best.dist2 === Infinity) best = look;
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.lineWidth = 10;
+ ctx.stroke();
+ }
+ me.pulse = function (charge, angle, where = this.position) {
+ let best;
+ angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x)
+ let explosionRadius = 5.5 * charge
+ let range = 5000
+ const path = [{
+ x: where.x + 20 * Math.cos(angle),
+ y: where.y + 20 * Math.sin(angle)
+ },
+ {
+ x: where.x + range * Math.cos(angle),
+ y: where.y + range * Math.sin(angle)
+ }
+ ];
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ };
+ //check for collisions
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ if (!best.who) {
+ vertexCollision(path[0], path[1], body);
+ vertexCollision(path[0], path[1], [player]);
+ vertexCollision(path[0], path[1], map);
+ if (best.dist2 != Infinity) { //if hitting something
+ path[path.length - 1] = {
+ x: best.x,
+ y: best.y
+ };
+ }
+ }
+ if (best.who) {
+ b.explosion(path[1], explosionRadius, "rgba(0,0,0,0)")
+ const off = explosionRadius * 1.2
+ b.explosion({ x: path[1].x + off * (Math.random() - 0.5), y: path[1].y + off * (Math.random() - 0.5) }, explosionRadius, "rgba(0,0,0,0.7)")
+ b.explosion({ x: path[1].x + off * (Math.random() - 0.5), y: path[1].y + off * (Math.random() - 0.5) }, explosionRadius, "rgba(0,0,0,0.7)")
+ }
+ //draw laser beam
+ ctx.beginPath();
+ ctx.moveTo(path[0].x, path[0].y);
+ ctx.lineTo(path[1].x, path[1].y);
+ if (charge > 50) {
+ ctx.strokeStyle = "rgba(0,0,0,0.10)"
+ ctx.lineWidth = 70
+ ctx.stroke();
+ }
+ ctx.strokeStyle = "rgba(0,0,0,0.25)"
+ ctx.lineWidth = 20
+ ctx.stroke();
+ ctx.strokeStyle = "#f00";
+ ctx.lineWidth = 4
+ ctx.stroke();
+
+ //draw little dots along the laser path
+ const sub = Vector.sub(path[1], path[0])
+ const mag = Vector.magnitude(sub)
+ for (let i = 0, len = Math.floor(mag * 0.0005 * charge); i < len; i++) {
+ const dist = Math.random()
+ simulation.drawList.push({
+ x: path[0].x + sub.x * dist + 10 * (Math.random() - 0.5),
+ y: path[0].y + sub.y * dist + 10 * (Math.random() - 0.5),
+ radius: 1.5 + 5 * Math.random(),
+ color: "rgba(0,0,0,0.5)",
+ time: Math.floor(9 + 25 * Math.random() * Math.random())
+ });
+ }
+ }
+ let c = 0
+ me.gun = function () {
+ if (b.activeGun == 0) {// nailgun
+ if (this.seePlayer.recall && !(simulation.cycle % 20)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ const dist = Vector.magnitudeSquared(Vector.sub(this.position, player.position));
+ const unit = Vector.normalise(Vector.sub(Vector.add(player.position, Vector.mult(player.velocity, Math.sqrt(dist) / 60)), this.position))
+ normalBullet(this.position.x, this.position.y);
+ const v = 10 + 8 * simulation.accelScale;
+ Matter.Body.setVelocity(mob[mob.length - 1], Vector.mult(unit, 0.009 * this.mass))
+ // Matter.Body.setVelocity(mob[mob.length - 1], {
+ // x: this.velocity.x + this.fireDir.x * v,
+ // y: this.velocity.y + this.fireDir.y * v
+ // });
+ }
+ }
+ if (b.activeGun == 1) {// shotgun
+ if (this.seePlayer.recall && !(simulation.cycle % 90)) {
+ const side = 22
+ for (let i = 0; i < 12; i++) {
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ const dir = angle + (Math.random() - 0.5) * 1
+ const SPEED = 52 + Math.random() * 8
+ normalBullet(this.position.x + 35 * Math.cos(angle) + 15 * (Math.random() - 0.5), this.position.y + 35 * Math.sin(angle) + 15 * (Math.random() - 0.5))
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: SPEED * Math.cos(dir),
+ y: SPEED * Math.sin(dir)
+ });
+ }
+ }
+ } else if (b.activeGun == 2) { // super balls
+ if (this.seePlayer.recall && !(simulation.cycle % 20)) {
+ const num = 3;
+ const SPREAD = 0.13;
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ let dir = angle - SPREAD * (num - 1) / 2;
+ const SPEED = 33
+ for (let i = 0; i < num; i++) {
+ ball(this.position.x + 30 * Math.cos(angle), this.position.y + 30 * Math.sin(angle))
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: SPEED * Math.cos(dir),
+ y: SPEED * Math.sin(dir)
+ });
+ dir += SPREAD
+ }
+ }
+ } else if (b.activeGun == 3) { // wave
+ this.doLongitudinal()
+ const halfArc = 0.275
+ const anglex = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ const angle = anglex + 0.3 * (Math.random() - 0.5)
+ this.waves.push({
+ position: {
+ x: this.position.x + 25 * Math.cos(anglex),
+ y: this.position.y + 25 * Math.sin(anglex),
+ },
+ angle: angle - halfArc, //used in drawing ctx.arc
+ unit1: { x: Math.cos(angle - halfArc), y: Math.sin(angle - halfArc) }, //used for collision
+ unit2: { x: Math.cos(angle + halfArc), y: Math.sin(angle + halfArc) }, //used for collision
+ arc: halfArc * 2,
+ radius: 25,
+ reflection: 0,
+ expanding: 1,
+ resonanceCount: 0
+ })
+ } else if (b.activeGun == 4) { // missiles
+ if (this.seePlayer.recall && !(simulation.cycle % 30)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ missile(this.position);
+ const v = 10 + 8 * simulation.accelScale + (Math.random() * 20 - Math.random() * 20);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ }
+ } else if (b.activeGun == 5) { // grenades
+ if (this.seePlayer.recall && !(simulation.cycle % 30)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ grenade(this.position.x, this.position.y)
+ const v = 10 + 8 * simulation.accelScale + (Math.random() * 20 - Math.random() * 20);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ }
+ } else if (b.activeGun == 6) { // spores
+ if (this.seePlayer.recall && !(simulation.cycle % 30)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ me.drop(this.position.x, this.position.y)
+ const v = 10 + 8 * simulation.accelScale + (Math.random() * 20 - Math.random() * 20);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ }
+ } else if (b.activeGun == 7) { // drones
+ ctx.save()
+ ctx.lineWidth = "8";
+ ctx.strokeStyle = "rgba(100, 0, 150, 0.1)";
+ ctx.beginPath();
+ for (let i = 0, len = bullet.length; i < len; ++i) {
+ const dx = bullet[i].position.x - this.position.x;
+ const dy = bullet[i].position.y - this.position.y;
+ const dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist < 500) {
+ ctx.moveTo(this.position.x + dist, this.position.y);
+ ctx.arc(this.position.x, this.position.y, dist, 0, 2 * Math.PI)
+ //ctx.lineTo(bullet[i].position.x, bullet[i].position.y);
+ const angle = Math.atan2(dy, dx);
+ const mag = (1500 * bullet[i].mass * simulation.g) / (dist * 0.05);
+ bullet[i].force.x += mag * Math.cos(angle);
+ bullet[i].force.y += mag * Math.sin(angle);
+ }
+ }
+ ctx.stroke();
+ ctx.restore()
+ } else if (b.activeGun == 8) { // foam
+ if (this.seePlayer.recall && !(simulation.cycle % 1)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ foamBullet(this.position.x, this.position.y, 7 + Math.ceil(this.radius / 15), 69);
+ const v = 10 + 8 * simulation.accelScale + (Math.random() * 20 - Math.random() * 20);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ }
+ } else if (b.activeGun == 9) { // harpoon - railgun
+ if (c > 1) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ railBullet(this.position.x, this.position.y);
+ const v = 10 + 80 * simulation.accelScale;
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ c = 0;
+ } else {
+ c += 0.02;
+ this.railGun();
+ }
+ } else if (b.activeGun == 10) { // laserMines
+ if (this.seePlayer.recall && !(simulation.cycle % 100)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ me.laserMine(this.position.x, this.position.y)
+ const v = 10 + 8 * simulation.accelScale + (Math.random() * 20 - Math.random() * 20);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v,
+ y: this.velocity.y + this.fireDir.y * v
+ });
+ }
+ } else if (b.activeGun == 11) { // laser - pulse
+ //this.lasers(this.position, Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x))
+ //if (this.seePlayer.recall && !(simulation.cycle % 20)) {
+ if (c > 1) {
+ this.pulse(c * 100)
+ c = 0;
+ } else {
+ if (this.energy < 1 || this.energy > 0.5) {
+ c += 0.01;
+ ctx.beginPath();
+ const mag = Math.sqrt(c)
+ ctx.arc(this.position.x, this.position.y, c * 30, 0, 2 * Math.PI)
+ ctx.fillStyle = '#000000'
+ ctx.strokeStyle = 'transparent'
+ ctx.fill();
+ ctx.stroke();
+ this.energy -= 0.01;
+ ctx.strokeStyle = "#000000";
+ ctx.lineWidth = 1.5
+ // ctx.globalAlpha = 1;
+ } else {
+ c = 0;
+ this.energy += 0.1
+ }
+ }
+ //}
+ }
+ }
+ me.laserMine = function (x, y) {
+ mobs.spawn(x, y, 3, 20, "#000000");
+ let xx = mob[mob.length - 1];
+ xx.stroke = "#00000000";
+ Matter.Body.setDensity(xx, 0.000005) //one tap
+ xx.isUnstable = true;
+ xx.timeLeft = 40 + Math.floor(180 * Math.random())
+ xx.leaveBody = false;
+ xx.isDropPowerUp = false;
+ xx.collisionFilter.mask = cat.bullet | cat.player | cat.map
+ xx.showHealthBar = false;
+ //xx.vertices = Matter.Vertices.rotate(xx.vertices, Math.PI, xx.position);
+ me.onHit = function () {
+ this.death();
+ };
+ xx.do = function () {
+ this.timeLimit();
+ Matter.Body.setAngularVelocity(this, 0.01)
+ ctx.beginPath();
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = "#00000000"
+ for (let i = 0; i < this.vertices.length; i++) {
+ const where = this.vertices[i]
+ const endPoint = Vector.add(where, Vector.mult(Vector.normalise(Vector.sub(where, this.position)), 2500))
+ me.lasers(this.vertices[0], this.angle + Math.PI / 3);
+ me.lasers(this.vertices[1], this.angle + Math.PI);
+ me.lasers(this.vertices[2], this.angle - Math.PI / 3);
+ }
+ ctx.strokeStyle = "black";
+ ctx.stroke();
+ ctx.save()
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
+ ctx.lineTo(this.vertices[1].x, this.vertices[1].y);
+ ctx.lineTo(this.vertices[2].x, this.vertices[2].y);
+ ctx.fillStyle = "#000000";
+ ctx.strokeStyle = "transparent";
+ ctx.fill();
+ ctx.closePath();
+ ctx.stroke();
+ ctx.restore()
+ }
+ }
+ me.seeker = function (x, y) {
+ mobs.spawn(x, y, sides = 5, radius = 5, "rgb(0,0,0)");
+ let yy = mob[mob.length - 1];
+ yy.stroke = "transparent";
+ yy.onHit = function () {
+ this.explode(this.mass * 20);
+ };
+ Matter.Body.setDensity(yy, 0.000015); //normal is 0.001
+ yy.timeLeft = 420 //* (0.8 + 0.4 * Math.random());
+ yy.accelMag = 0.00017 * simulation.accelScale; //* (0.8 + 0.4 * Math.random())
+ yy.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
+ yy.restitution = 0.5;
+ yy.leaveBody = false;
+ yy.isDropPowerUp = false;
+ yy.isBadTarget = true;
+ yy.isMobBullet = true;
+ yy.showHealthBar = false;
+ yy.collisionFilter.category = cat.mobBullet;
+ yy.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
+ let index = 0;
+ yy.do = function () {
+ this.alwaysSeePlayer()
+ this.timeLimit();
+ this.attraction();
+ };
+ }
+ me.drop = function (x, y) {
+ mobs.spawn(x, y, sides = 90, radius = 30, "rgb(0,255,100,0.7)");
+ let yyy = mob[mob.length - 1];
+ yyy.stroke = "transparent";
+ yyy.onDeath = function () {
+ for (let i = 0, len = 5; i < len; i++) {
+ me.seeker(this.position.x, this.position.y)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: Math.random() * 30 - Math.random() * 30,
+ y: Math.random() * 30 - Math.random() * 30
+ });
+ }
+ };
+ Matter.Body.setDensity(yyy, 0.000015); //normal is 0.001
+ yyy.timeLeft = 60 //* (0.8 + 0.4 * Math.random());
+ yyy.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
+ yyy.restitution = 0.5;
+ yyy.leaveBody = false;
+ yyy.isDropPowerUp = false;
+ yyy.isBadTarget = true;
+ yyy.isMobBullet = true;
+ yyy.showHealthBar = false;
+ yyy.collisionFilter.category = cat.mobBullet;
+ yyy.collisionFilter.mask = null;
+ yyy.maxRadius = 30;
+ let index = 0;
+ yyy.do = function () {
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ Matter.Body.setPosition(this, player.position)
+ if (player.speed > 2.5) Matter.Body.setVelocity(player, Vector.mult(player.velocity, 0.94))
+ }
+ if (Matter.Query.collides(this, map).length > 0) {
+ Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.1))
+ }
+ this.alwaysSeePlayer()
+ this.timeLimit();
+ ctx.save()
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y)
+ ctx.fillStyle = "black";
+ ctx.arc(this.position.x, this.position.y, this.maxRadius, 0, 2 * Math.PI)
+ ctx.stroke()
+ ctx.fill()
+ ctx.restore()
+ if (this.maxRadius > 0) {
+ this.maxRadius -= 0.5;
+ }
+ };
+ }
+ };
+ restoreBoss(-13350, -1800);
+ laserEM(-6500 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200), -3400 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200));
+ sniper(-9275 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200), -3325 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200));
+ laserEM(-5750 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200), -850 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200));
+ sniper(-3600 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200), -1325 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200));
+ laserEM(1425 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200), -800 + Math.floor(Math.random() * 200) - Math.floor(Math.random() * 200));
+ //restoreBoss(-350, -3225);
+ wire();
+ wire();
+ wire();
+ wire();
+ wire();
+ color.map = '#00000000';
+ level.customTopLayer = () => {
+ if (dong.position.x > -3825) {
+ dong.force.y -= dong.mass * simulation.g;
+ } else {
+ dong.force.y += dong.mass * simulation.g;
+ }
+ Matter.Body.setAngularVelocity(dong, -0.5)
+ if (key == true) {
+ door.isClosing = false;
+ } else {
+ door.isClosing = true;
+ }
+ door.openClose();
+ door.draw()
+ for (let i = 0, len = map.length; i < len; i++) { //so boss bar renders over the map
+ ctx.beginPath();
+ ctx.moveTo(map[i].vertices[0].x, map[i].vertices[0].y);
+ for (let j = 0, length = map[i].vertices.length; j < length; j++) {
+ ctx.lineTo(map[i].vertices[j].x, map[i].vertices[j].y);
+ }
+ ctx.lineTo(map[i].vertices[0].x, map[i].vertices[0].y);
+ ctx.fillStyle = "rgba(68,68,68)";
+ ctx.strokeStyle = "transparent";
+ ctx.fill();
+ ctx.stroke();
+ // ctx.setLineDash([]);
+ }
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].restoreBoss) {
+ ctx.save();
+ ctx.setTransform(1, 0, 0.5, 1, 0, 0); //slanted
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(canvas.width2 / 2, canvas.height2 / 10, canvas.width2, 30);
+ ctx.fillStyle = "rgba(0,0,0,0.7)";
+ ctx.fillRect(canvas.width2 / 2, canvas.height2 / 10, canvas.width2 * mob[i].health, 30);
+ ctx.restore();
+ }
+ }
+ };
+ const obj = { restoreBoss };
+ Object.assign(spawn, obj); //for next map, gonna be a rpg-like thingy I think
+ },
+ map() {
+
+ const elevator = level.elevator(-80.4, -931.6, 180, 50, -1550)
+ 15900 && player.position.x < 16300 && player.position.y > -960.2
+ const slime = level.hazard(15900, -960, 400, 6000);
+ const slime2 = level.hazard(15147.2, -1782.4, 2000, 822);
+ const boost1 = level.boost(5950, -20, 700)
+ const boost2 = level.boost(21088, -1672, 700)
+ const boost3 = level.boost(19390, -31, 1700)
+ const boost4 = level.boost(19390, -31, 1700)
+ const boost5 = level.boost(17274, -1242, 1000)
+ const portal = level.portal({ x: 443, y: -1636 }, Math.PI, { x: 21391.9, y: -1806.3 }, -Math.PI)
+ const portal2 = level.portal({ x: 16838.3, y: -626.7 }, Math.PI, { x: 16882.8, y: -2566.5 }, -Math.PI)
+ const buttonDoor = level.button(21889, -10)
+ const door = level.door(19119, -2133, 110, 510, 480)
+ const buttonDoor2 = level.button(18711, -2210)
+ const door2 = level.door(17041, -412, 110, 510, 480)
+ const buttonDoor3 = level.button(20456.6, -1636.2)
+ const door3 = level.door(20238, -781.4, 88, 452, 412)
+ //y=-1485
+
+ simulation.enableConstructMode()
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 15316;
+ level.exit.y = -84;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#001738";
+ color.map = "#444" //custom map color
+
+
+
+ level.custom = () => {
+ //spawn.mapRect(22330, -2688.75, 400, 800);
+ //spawn.mapRect(22330, -1793.5, 400, 800);//-46.25*2=-92.5
+ //spawn.mapRect(22330, -804.25, 400, 800);//-46.25*3
+
+ ctx.fillStyle = "rgba(63,247,251,0.8)"
+ ctx.fillRect(22330, -2713.75, 550, 700) //15845.0, -1262.2
+ ctx.fillRect(22330, -1743.5, 550, 700)
+ ctx.fillRect(22330, -754.25, 550, 700)
+ ctx.fillRect(15845.0, -1262.2, 550, 300)
+ ctx.fillStyle = "rgba(235,235,235,0.9)"
+ ctx.fillRect(-192, -1973, 6484, 2071)
+ ctx.fillRect(15109.5, -2867.5, 7284, 2971)
+ ctx.fillStyle = "rgba(35,35,35,0.8)"
+ ctx.fillRect(15145.9, -960, 200, 25)
+
+ ctx.fillStyle = "rgba(255,255,255,0.9)"
+ ctx.fillRect(-677.3, -610.9, 15, 15)
+ ctx.fillRect(-910.4, 458.3, 15, 15)
+ ctx.fillRect(-1029.0, 713.7, 15, 15)
+ ctx.fillRect(42.6, 1332.2, 15, 15)
+ ctx.fillRect(277.3, 751.8, 15, 15)
+ ctx.fillRect(797.1, 553.2, 15, 15)
+ ctx.fillRect(-1458.9, 340.9, 15, 15)
+ ctx.fillRect(-1780.0, -54.6, 15, 15)
+ ctx.fillRect(-1260.3, -686.4, 15, 15)
+ ctx.fillRect(-2064.3, -394.6, 15, 15)
+ ctx.fillRect(-1815.7, 1156.2, 15, 15)
+ ctx.fillRect(-1998.1, 1118.4, 15, 15)
+
+
+
+ buttonDoor.query();
+ buttonDoor.draw();
+ buttonDoor2.query();
+ buttonDoor2.draw();
+ buttonDoor3.query();
+ buttonDoor3.draw();
+ slime.query();
+ slime2.query();
+
+ ctx.fillStyle = `hsla(160, 100%, 43%,${0.3 + 0.07 * Math.random()})`
+ ctx.fillRect(15900 + 400 * Math.random(), -1360, 2, 6000)
+ if (buttonDoor.isUp) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ if (buttonDoor2.isUp) {
+ door2.isClosing = true
+ } else {
+ door2.isClosing = false
+ }
+ if (buttonDoor3.isUp) {
+ door3.isClosing = true
+ } else {
+ door3.isClosing = false
+ }
+ door.openClose();
+ door2.openClose();
+ door3.openClose();
+ portal[2].query()
+ portal[3].query()
+ portal2[2].query()
+ portal2[3].query()
+
+ boost1.query();
+ boost2.query();
+ boost3.query();
+ boost4.query();
+ boost5.query();
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ };
+
+
+ level.customTopLayer = () => {
+ door.draw();
+ door2.draw();
+ door3.draw();
+
+ portal[0].draw();
+ portal[1].draw();
+ portal[2].draw();
+ portal[3].draw();
+ portal2[0].draw();
+ portal2[1].draw();
+ portal2[2].draw();
+ portal2[3].draw();
+ elevator.move()
+
+ if (player.position.x > 15900 && player.position.x < 16300 && player.position.y > -1360.2) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 10
+ });
+ } else {
+
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y - 0.2
+ });
+
+ }
+
+ };
+
+
+ //1273.2, -1404.7
+
+ //first ship base
+ spawn.mapRect(-300, 0, 6684, 100); //lower floor
+ spawn.mapRect(-300, -2071, 154, 2071); //far right wall
+ spawn.mapRect(2511, -300, 1309, 308); //left big block
+ spawn.mapRect(3820, -184, 1309, 184); //right big block
+ spawn.mapRect(-300, -739, 2549, 100); //upper right floor
+ spawn.mapRect(2056, -1309, 2764, 169); //upper center floor
+ spawn.mapRect(2056, -1309, 193, 650); //upper left floor wall
+ spawn.mapRect(4636, -1309, 193, 793); //upper right floor wall
+ spawn.mapRect(4821, -654, 955, 138); //upper right floor
+ spawn.mapRect(6237, -2071, 147, 2071); //far right wall
+ spawn.mapRect(-300, -2071, 6684, 154); //roof
+
+ //first ship details
+ spawn.mapRect(245, -360, 70, 400); //start room wall
+ spawn.mapRect(500, -1929, 154, 462);
+ spawn.mapRect(185, -1517, 469, 77);
+ spawn.mapRect(2773, -682, 469, 77); //walls in 1st room
+ spawn.mapRect(3743, -566, 77, 469);
+ spawn.mapRect(3947, -851, 469, 77);
+ spawn.mapRect(5313, -1309, 1000, 70); //walls in second area
+ spawn.mapRect(4818, -1006, 400, 70);
+ spawn.mapRect(4768, -1626, 800, 70);
+ spawn.mapRect(4760, -1626, 70, 400);
+
+
+ //first ship blocks/debris
+ spawn.debris(3267.6, -797.1, 700, 5); //16 debris per level
+ spawn.debris(1626.0, -372.5, 1700, 8); //16 debris per level
+ spawn.debris(1880.1, -1508.9, 3700, 16); //16 debris per level
+ spawn.debris(5335.3, -1431.6, 3700, 16); //16 debris per level
+ spawn.debris(1563.8, -1087.9, 700, 5); //16 debris per level
+ spawn.bodyRect(1540, -1110, 218, 125, 0.9);
+
+
+
+ //first ship mobs
+ spawn.randomMob(2903.9, -754.5, 0.7);
+ spawn.randomMob(5577.0, -217.0, 0.6);
+ spawn.randomMob(765.8, -1029.7, 0.5);
+ spawn.randomMob(20079.4, -2219.7, 0.6);
+ spawn.randomMob(20079.4, -2219.7, 0.7);
+ spawn.randomMob(20890.9, -1306.0, 0.5);
+ spawn.randomMob(21284.2, -983.1, 0.5);
+ spawn.randomMob(20381.0, -254.2, 0.7);
+ spawn.randomMob(21027.8, -473.8, 0.6);
+ spawn.randomMob(19448.2, -1323.3, 0.6);
+ spawn.randomMob(18397.7, -711.2, 0.6);
+ spawn.randomMob(15547.2, -2249.6, 0.6);
+ spawn.randomSmallMob(16114.6, -2524.2);
+ spawn.randomSmallMob(15378.9, -2549.6);
+
+ spawn.randomSmallMob(893.5, -120.8);
+ spawn.randomSmallMob(3521.8, -419.6);
+ spawn.randomSmallMob(4386.2, -439.6);
+ spawn.randomSmallMob(5667.0, -847.8);
+ spawn.randomSmallMob(3158.5, -1581.8);
+ spawn.randomSmallMob(3866.7, -1483.2);
+ spawn.randomSmallMob(4652.3, -1729.4);
+ spawn.randomSmallMob(1068.7, -106.1);
+ spawn.randomSmallMob(3545.0, -413.0);
+ spawn.randomSmallMob(4231.7, -446.3);
+ spawn.randomSmallMob(1456.4, -1014.8);
+ spawn.randomSmallMob(20432.4, -1374.3);
+ spawn.randomSmallMob(20381.0, -254.2);
+ spawn.randomSmallMob(20353.4, -1845.8);
+ spawn.randomSmallMob(20353.4, -1845.8);
+ spawn.randomSmallMob(20648.1, -136.8);
+ spawn.randomSmallMob(20024.4, -2213.1);
+ spawn.randomSmallMob(17438.7, -876.7);
+
+
+
+ //second ship mobs
+ spawn.debris(17732.3, -550.0, 700, 5); //16 debris per level
+ spawn.debris(18006.4, -2181.3, 700, 5); //16 debris per level
+ spawn.debris(16108.6, -2621.1, 700, 5); //16 debris per level
+ spawn.debris(20823.6, -1332.1, 1300, 5); //16 debris per level
+ spawn.debris(21095.5, -423.4, 700, 5); //16 debris per level
+
+
+
+
+
+
+
+ spawn.randomSmallMob(1300, -70);
+
+
+ // const index = mob.length
+ spawn.shieldingBoss(769.8, -1119.0)
+ // console.log(mob[index].onDeath)
+ // requestAnimationFrame(() => mob[index].onDeath = function() {});
+ // console.log(mob[index].onDeath)
+
+ //second ship base
+ spawn.mapRect(15000, 0, 515, 185); //lower floor 1
+ spawn.mapRect(17015, 0, 5500, 185); //lower floor 2
+ spawn.mapRect(15000, -2972, 185, 2972); //left wall
+ spawn.mapRect(15000, -2972, 7515, 185); //roof
+ spawn.mapRect(22330, -2972, 185, 2972); //right wall
+ spawn.mapRect(17002, -2972, 169, 2564); //left middle wall
+ spawn.mapRect(19089, -2972, 169, 855); //right middle wall upper
+ spawn.mapRect(19089, -1625, 169, 1800); //right middle wall lower
+ spawn.mapRect(20760, -2972, 169, 1350); //medium wall left of portal
+ spawn.mapRect(19720, -1625, 1725, 162); //right room upper floor
+ spawn.mapRect(21440, -2325, 169, 863); //medium wall right of portal
+ spawn.mapRect(19720, -855, 2725, 162); //right room lower floor
+
+ //engines //y -2972 -> 0
+ spawn.mapRect(22330, -2763.75, 400, 800);
+ spawn.mapRect(22330, -1793.5, 400, 800);
+ spawn.mapRect(22330, -804.25, 400, 800);
+
+
+
+ //second ship details
+ spawn.mapRect(19904, -1465, 85, 362); //upper L
+ spawn.mapRect(19542, -1191, 412, 88); //lower L
+ spawn.mapRect(18546, -2199, 600, 82); //2nd room enternce wall
+ spawn.mapRect(18546, -2499, 82, 2300);
+ spawn.mapRect(18108, -326, 500, 82); //walls/floors in middle room
+ spawn.mapRect(17750, -682, 300, 82);
+ spawn.mapRect(17156, -468, 500, 60);
+ spawn.mapRect(18022, -1082, 600, 82);
+ spawn.mapRect(17151, -1196, 500, 82);
+ spawn.mapRect(17453, -2060, 500, 82);
+ spawn.mapRect(18197, -2269, 400, 82);
+ spawn.mapRect(18108, -326, 500, 82);
+ spawn.mapRect(20542, -1191, 612, 88);
+ spawn.mapRect(20238, -1191, 88, 412);
+ spawn.mapRect(21520, -1468, 88, 412);
+ spawn.mapRect(20238, -330.2, 88, 412);
+ spawn.mapRect(20819, -328.3, 412, 88);
+ spawn.mapRect(21532, -708, 88, 412);
+ spawn.mapRect(15483.8, 12.5, 388, 30); //broken floor
+ spawn.mapRect(15487.6, 76.6, 488, 24);
+ spawn.mapRect(15506.5, 134.2, 288, 45);
+ spawn.mapVertex(16758.6, 135.3, "400 -30 -350 -40 -400 30 400 30");
+ spawn.mapVertex(16758.6, 55.3, "423 -30 -408 -20 -400 20 400 20");
+ //tank
+ spawn.mapRect(15310, -960, 600, 135);
+ spawn.mapRect(16290, -960, 800, 135);
+ //in tank
+ spawn.mapRect(16524.8, -2726.8, 40, 400);
+ spawn.mapRect(16524.8, -2130.9, 400, 40);
+ spawn.mapRect(16010.2, -2412.2, 300, 40);
+ spawn.mapRect(15379.2, -2055.1, 400, 40);
+
+
+
+ //add fuel tanks in the last room
+
+
+ spawn.mapRect(21531.9, -707.8, 488, 8);
+
+ //22185.5, -114.8
+ spawn.mapVertex(22207.8, -103, "325 -200 100 -200 325 -300");
+ spawn.mapRect(22056.6, -70, 225, 212);
+
+ spawn.mapVertex(20723.1, -1734, "325 -200 100 -200 325 -300");
+ spawn.mapRect(20571.9, -1701.0, 225, 212);
+
+ spawn.mapVertex(22207.8, -103, "325 -200 100 -200 325 -300");
+ spawn.mapRect(22056.6, -70, 225, 212);
+ //spawn.mapVertex(x,y, "coordinates")
+ //the parts in quotes is "x y x y x y x y x y" x and y need to be the coordinates of points that define the shape in a concave clockwise direction
+
+ //second ship blocks/debris
+ spawn.bodyRect(21525, -113, 50, 50, 9); //first button block
+ spawn.bodyRect(18993, -2283, 50, 50, 9); //second button block
+ spawn.bodyRect(20303, -1736, 50, 50, 9); //third button block
+
+
+
+ let randomBoss = Math.floor(Math.random() * 5); //change the bosses
+ spawn[["blinkBoss", "shooterBoss", "launcherBoss", "pulsarBoss", "beetleBoss", "bladeBoss", "revolutionBoss", "dragonFlyBoss", "spiderBoss"][randomBoss]](17902, -1689, 100, false);
+
+
+
+ // powerUps.spawnStartingPowerUps(1475, -1175);
+ // spawn.debris(750, -2200, 3700, 16); //16 debris per level
+ // spawn.bodyRect(1540, -1110, 300, 25, 0.9);
+ // spawn.randomSmallMob(1300, -70);
+ // spawn.randomMob(2650, -975, 0.8);
+ // spawn.randomGroup(1700, -900, 0.4);
+ // if (simulation.difficulty > 1) spawn.randomLevelBoss(2200, -1300);
+ // spawn.secondaryBossChance(100, -1500)
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ cantilever() { // made by Eclipse#7932 on discord, (TheSpudguy)(@PurpleSunsetGames on github)
+ // simulation.enableConstructMode();
+ simulation.makeTextLog(`
underpass by
Eclipse#7932 `);
+
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 5500;
+ level.exit.y = 950;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit
+ spawn.mapRect(level.exit.x - 50, level.exit.y + 30, 200, 100); // exit platform
+ spawn.mapRect(level.exit.x - 50, level.exit.y - 300, 200, 100); // exit platform roof
+ const endElevator = level.elevator(level.exit.x - 150, level.exit.y - 300, 100, 425, level.exit.y - 300); // end access door
+
+ spawn.randomMob(-200, 350, Infinity); // random mob at the beginning
+
+ spawn.mapRect(-100, 0, 600, 100); // main platform at start
+ spawn.bodyRect(0, 300, 50, 50); // little squares at start (one of these should be taken while crossing the cantilever to complete the level more easily)
+ spawn.bodyRect(100, 200, 50, 50);
+ spawn.bodyRect(50, 250, 50, 50);
+ spawn.mapRect(450, -20, 50, 20); // main platform ledge
+ spawn.mapRect(-200, 500, 2200, 100); // lower platform
+ spawn.mapRect(1850, 380, 100, 50); // cantilever block
+ spawn.bodyRect(80, -1300, 70, 1300, 1, { friction: .03, frictionAir: .001 }); // cantilever
+
+ spawn.mapRect(3400, 500, 300, 100); // lever platform
+ spawn.mapRect(3650, 500, 100, 800); // pit
+ spawn.mapRect(3650, 1300, 2600, 100);
+ spawn.mapRect(6150, 600, 100, 800);
+ spawn.mapRect(5650, 600, 100, 650);
+ spawn.randomMob(4700, 550, Infinity);
+ spawn.randomMob(4700, 450, Infinity);
+ spawn.randomMob(4600, 550, Infinity);
+
+ const toggle = level.toggle(3500, 500, false); // first lever
+ const button = level.button(5900, 1300);
+ const slidingWall = level.elevator(3750, -1200, 100, 1800, -1200); // first sliding wall
+
+ level.defaultZoom = 1500;
+ simulation.zoomTransition(level.defaultZoom);
+ document.body.style.backgroundColor = "#d8badf";
+ // color.map = "#444" //custom map color
+
+ level.custom = () => {
+ level.exit.drawAndCheck();
+
+ level.enter.draw();
+ };
+
+ level.customTopLayer = () => {
+ toggle.query();
+ button.query();
+ button.draw();
+
+ if (toggle.isOn) {
+ slidingWall.force.y -= 400;
+ }
+ if (!button.isUp) {
+ endElevator.force.y -= 100;
+ }
+ slidingWall.move();
+ endElevator.move()
+ };
+ powerUps.addResearchToLevel(); //needs to run after mobs are spawned
+ },
+ dojo() { // By
+ simulation.makeTextLog(`
underpass by
weird_pusheen `);
+
+ const vanishes = [];
+ const smoofes = [];
+ const leftRotor = level.rotor(-550, 900, 950, 25);
+ leftRotor.frictionAir = 0.01;
+ var leftSchwoof = level.boost(-20, -60, -2000);
+ var rightSchwoof = level.button(2550, -50);
+ var rightSchwoofState = false;
+ var rightSchwoofLive = true;
+ spawn.mapRect(2513, -39, 200, 100);
+ var pathPoints = [
+ [0, 0], // Index 0 is owned by M and is set to M's position during play
+ // this means that occasionally the boss will bonk M on the way to somewhere else, which gives it a chance to hurt M and gives the player a chance to hurt it
+ [250, -750], /* Left bases */
+ [250, -2500],
+ [350, -1500], // Left doorway
+ [1150, -1500], // Home base
+ [1150, -2750], // Upper base
+ [1950, -1500], // Right doorway
+ [2050, -750], /* Right bases */
+ [2050, -2500],
+ [-150, -250], // Left porthole
+ ];
+ function isntIn(point, array) {
+ for (var x = 0; x < array.length; x++) {
+ if (point[0] == array[x][0] && point[1] == array[x][1]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ function isObstructed(v1, v2) {
+ var ret = Matter.Query.ray(map,
+ {
+ x: v1[0],
+ y: v1[1],
+ },
+ {
+ x: v2[0],
+ y: v2[1]
+ }).length != 0;
+ return ret; // Kinda-ish stolen from mob.js
+ }
+ function pythag(p1, p2) {
+ var dx = p1[0] - p2[0];
+ var dy = p1[1] - p2[1];
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+ var path = undefined; // This is a stupid way to go about pathfinding code. I might even clean it up!
+ function pathFind(goalPoint, startPoint, curPath = []) {
+ var myPoint = startPoint;
+ if (curPath.length) {
+ myPoint = curPath[curPath.length - 1];
+ }
+ if (path && (curPath.length >= path.length)) { // If we've already found a shorter or equal path, no reason to continue and waste CPU time
+ return; // Minimizes for HOP COUNT, not PATH LENGTH - path length was buggy
+ }
+ if (!isObstructed(myPoint, goalPoint)) { // If the line to the goal point ain't blocked by a map object, we've arrived!
+ path = [...curPath];
+ path.push(goalPoint);
+ return;
+ }
+ pathPoints.forEach(testPoint => {
+ if (isntIn(testPoint, curPath)) { // If it's reusing points, there's clearly something wrong
+ if (!isObstructed(myPoint, testPoint)) { // If the line to the test point ain't blocked by a map object
+ var thing = [...curPath];
+ thing.push(testPoint);
+ pathFind(goalPoint, startPoint, thing); // Branch to a valid test point
+ }
+ }
+ });
+ }
+ level.setPosToSpawn(1200, 500);
+ level.exit.x = 51500;
+ level.exit.y = -1875;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ level.defaultZoom = 1500;
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d8dadf";
+
+ spawn.mapRect(-500, 0, 3300, 300); // Floor
+ spawn.mapRect(-100, -3000, 2500, 100); // Ceiling
+ spawn.mapRect(-200, -3000, 100, 2600); // Left wall
+ spawn.mapRect(2400, -3000, 100, 3000); // Right wall
+
+ spawn.mapRect(500, -1000, 100, 500); /* obstruction blocks */
+ smoofes.push(map[map.length - 1]);
+ spawn.mapRect(500, -2500, 100, 500);
+ smoofes.push(map[map.length - 1]);
+ spawn.mapRect(1700, -1000, 100, 500);
+ smoofes.push(map[map.length - 1]);
+ spawn.mapRect(1700, -2500, 100, 500);
+ smoofes.push(map[map.length - 1]);
+
+ spawn.mapRect(-1000, 550, 200, 50); // Left chonky stepppp low
+ spawn.mapRect(-800, 300, 200, 50); // Left chonky stepppp high
+ spawn.mapVertex(-1000, 1200, "0 0 100 0 700 500 700 700 0 700"); // Left chonky
+ spawn.mapRect(3100, 550, 200, 50); // Right chonky stepppp low
+ spawn.mapRect(2900, 300, 200, 50); // Right chonky stepppp high
+ spawn.mapVertex(3300, 1200, "0 0 -100 0 -700 500 -700 700 0 700"); // Right chonky
+ const leftElevator = level.elevator(-1400 - 300, 1450, 300, 100, 500);
+ const rightElevator = level.elevator(-1400 + 5100, 1450, 300, 100, 500);
+
+ spawn.mapRect(-150, -1700, 200, 50);
+ spawn.mapRect(400, -2050, 200, 50);
+ spawn.mapRect(1600, -1000, 200, 50);
+
+ spawn.randomMob(1200, 700);
+ spawn.randomMob(600, 1000);
+ spawn.randomMob(1800, 1000);
+ spawn.randomMob(3200, 400);
+ spawn.randomMob(3000, 200);
+ spawn.randomMob(-900, 400);
+ spawn.randomMob(-700, 200);
+ spawn.randomMob(1200, 1000);
+ for (var i = 0; i < 4; i++) {
+ spawn.randomSmallMob(Math.random() * 600 - 600, Math.random() * 3000 - 400);
+ }
+ spawn.grenadier(-300, -1000);
+ spawn.grenadier(2600, -1000);
+
+ spawn.mapRect(-1400, 1450, 5100, 100); // The True Floor
+
+ const slime = level.hazard(-1250, 1400, 4800, 50);
+ slime.maxHeight = 600;
+ simulation.draw.body = function () {
+ ctx.beginPath();
+ for (let i = 0, len = body.length; i < len; ++i) {
+ if (!body[i].hidden) {
+ let vertices = body[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ }
+ }
+ ctx.lineWidth = 2;
+ ctx.fillStyle = color.block;
+ ctx.fill();
+ ctx.strokeStyle = color.blockS;
+ ctx.stroke();
+ } // Override the old draw code to allow intelligent hiding of blocks - preferably this becomes official code because it's just a single added if statement and makes a lot of things cleaner and more intelligent
+
+ const vanish = function (x, y, width, height) { // normal vanishes don't work well on my map for some reason, so I rewrote
+ x += width / 2;
+ y += height / 2;
+ const getVertices = function (bX, bY, bW, bH) { return [{ x: bX, y: bY, index: 0, isInternal: false }, { x: bX + bW, y: bY, index: 1, isInternal: false }, { x: bX + bW, y: bY + bH, index: 4, isInternal: false }, { x: bX, y: bY + bH, index: 3, isInternal: false }] };
+ const cMask = cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ const vertices = getVertices(x, y, width, height);
+ const block = body[body.length] = Bodies.fromVertices(x, y, vertices, {
+ collisionFilter: {
+ category: cat.map,
+ mask: cMask
+ },
+ isNoSetCollision: true,
+ inertia: Infinity, //prevents rotation
+ isNotHoldable: true,
+ isNonStick: true, //this keep sporangium from sticking
+ isTouched: false,
+ cWidth: width,
+ hiddenCycle: 0,
+ isStatic: true,
+ query() {
+ if (this.cWidth <= 0) {
+ if (this.cWidth > -100) {
+ this.cWidth = -100;
+ Matter.Body.setVertices(this, vertices);
+ }
+ this.isTouched = false;
+ this.collisionFilter.mask = undefined;
+ this.hidden = true;
+ this.hiddenCycle++;
+ if (this.hiddenCycle > 100) {
+ if (Matter.Query.collides(this, [player]).length) {
+ this.hiddenCycle = 50;
+ }
+ else {
+ this.hiddenCycle = 0;
+ this.cWidth = width;
+ this.collisionFilter.mask = cMask;
+ this.hidden = false;
+ }
+ }
+ }
+ else if (this.isTouched) {
+ Matter.Body.setVertices(this, getVertices(x, y, this.cWidth, height * (this.cWidth / width)));
+ this.cWidth -= 3;
+ }
+ else if (Matter.Query.collides(this, [player]).length) { // Elseif short circuit avoids expensive collision detection
+ this.isTouched = true;
+ }
+ }
+ });
+ return block;
+ };
+
+ vanishes.push(vanish(800, 800, 800, 50));
+ vanishes.push(vanish(400, 1100, 400, 50));
+ vanishes.push(vanish(1600, 1100, 400, 50));
+ spawn.bodyRect(1700, 812, 300, 25, 1, {
+ collisionFilter: {
+ category: cat.body,
+ mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet | cat.map
+ },
+ isNoSetCollision: true,
+ isNotHoldable: true,
+ isNonStick: true, //this keep sporangium from sticking
+ restitution: 1,
+ friction: 0,
+ frictionAir: 0,
+ frictionStatic: 0,
+ query() {
+ Matter.Body.setAngularVelocity(this, 0);
+ Matter.Body.applyForce(this, this.position, {
+ x: 0,
+ y: -(this.position.y - 812) * 0.002
+ });
+ }
+ });
+ const zigzag = body[body.length - 1];
+ Matter.Body.applyForce(zigzag, zigzag.position, {
+ x: 0.1,
+ y: 0
+ });
+ var buttonWasDown = false;
+ level.customTopLayer = () => {
+
+ }
+ level.custom = () => {
+ rightSchwoof.isUp = false;
+ level.exit.drawAndCheck();
+ leftSchwoof.query();
+ level.enter.draw();
+ pathPoints[0][0] = m.pos.x;
+ pathPoints[0][1] = m.pos.y;
+ leftElevator.move();
+ rightElevator.move();
+ slime.query();
+ zigzag.query();
+ slime.levelRise(0.2);
+ for (var i = 0; i < vanishes.length; i++) {
+ vanishes[i].query();
+ }
+ if (!rightSchwoofState) {
+ var math = m.pos.y < leftRotor.position.y;
+ Matter.Body.setAngularVelocity(leftRotor, (math ? 1 : -1) * Math.PI / 45);
+ }
+ if (rightSchwoofLive) {
+ rightSchwoof.query();
+ rightSchwoof.draw();
+ if (rightSchwoofState) {
+ ctx.fillStyle = "lightgreen";
+ }
+ else {
+ ctx.fillStyle = "red";
+ }
+ ctx.beginPath();
+ ctx.arc(2615, -220, 40, 0, Math.PI * 2);
+ ctx.fill();
+ }
+ if (rightSchwoof.isUp) {
+ buttonWasDown = true;
+ }
+ else if (buttonWasDown) {
+ buttonWasDown = false;
+ rightSchwoofState = !rightSchwoofState;
+ }
+ if (Matter.Query.collides(player, smoofes).length) {
+ Matter.Body.applyForce(player, player.position, {
+ x: 0,
+ y: -0.015
+ });
+ }
+ };
+
+ mobs.spawn(500, -500, 10, 100, "yellow"); /* TacticalBoss
+ Modes:
+ Spawn:
+ Pathfinds to a point above M and starts dropping mobs. Learns which mobs to drop to cause the most damage, of course.
+ Occasionally strikes at M.
+ Hide:
+ Pathfinds to the point furthest from M
+ Strike:
+ Pathfind really, really fast to M
+ Recharge:
+ Stop moving for a bit to "recharge" (this is so the player has a chance to hit it)
+
+ It must always Hide or Recharge after Spawning or Striking. Which one it does is based on some factor I'll figure out.
+ Pathfinding is a hypersimplified algorithm with hard-coded "points" that it can travel between. M is one of these.
+ */
+ var boss = mob[mob.length - 1];
+ boss.isBoss = true;
+ boss.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ boss.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y);
+ level.exit.x = 2560;
+ level.exit.y = -90;
+ rightSchwoofLive = false;
+ };
+ var spawnables = {};
+ ["hopper", "stabber", "springer", "striker", "sneaker", "grower"].forEach((m) => { /* Used to be spawn.fullPickList, but some of those mobs don't do collision-only damage and would thus never be properly selected for */
+ if (spawn[m]) {
+ spawnables[m] = {
+ fun: spawn[m],
+ name: m,
+ weight: 1
+ }
+ }
+ });
+ boss.stabCycle = 0;
+ boss.spawnCycle = 0;
+ function spawny() {
+ var totalWeight = 0;
+ Object.keys(spawnables).forEach(key => {
+ totalWeight += spawnables[key].weight;
+ });
+ var cursorWeight = 0;
+ var choice = Math.random();
+ var mC = undefined;
+ Object.values(spawnables).forEach((thing) => {
+ var lower = cursorWeight / totalWeight;
+ cursorWeight += thing.weight;
+ var upper = cursorWeight / totalWeight;
+ if ((choice > lower && choice <= upper) || !mC) {
+ mC = thing;
+ }
+ });
+ mC.fun(boss.position.x, boss.position.y);
+ var sp = mob[mob.length - 1];
+ sp.typeName = mC.name;
+ sp.onHit = () => {
+ spawnables[sp.typeName].weight += 1;
+ };
+ var oldFun = sp.onDeath;
+ sp.onDeath = () => { /* Mobs that die are worth less */
+ oldFun.call(sp);
+ spawnables[sp.typeName].weight -= 0.3; /* But not too much less */
+ };
+ }
+ boss.spawnDelay = 40;
+ boss.mode = "hide";
+ boss.modeSwitch = -1; // Randomize mode immediately
+ boss.damageReduction = 0.1;
+ var oldOnHit = boss.onHit;
+ boss.onHit = () => {
+ boss.modeSwitch = -1; // After striking the player, always switch modes
+ oldOnHit.call(boss);
+ };
+ boss.do = () => {
+ path = undefined;
+ var pfGoal = [0, 0];
+ boss.modeSwitch--;
+ if (boss.modeSwitch < 0) {
+ if (!boss.isShielded) {
+ spawn.shield(boss, boss.position.x, boss.position.y, 0.75); // Every time the mode switches, have a 75% chance to gain a new shield
+ }
+ if (boss.mode == "hide" || boss.mode == "recharge") {
+ if (Math.random() > 0.5) {
+ boss.mode = "spawn";
+ }
+ else {
+ boss.mode = "strike";
+ }
+ boss.modeSwitch = 600;
+ }
+ else {
+ if (boss.mode == "strike") {
+ boss.mode = "hide"; // Always hides after striking
+ }
+ else {
+ if (Math.random() > 0.5) {
+ boss.mode = "hide";
+ }
+ else {
+ boss.mode = "recharge"; // same when it goes into recharge mode
+ spawn.shield(boss, boss.position.x, boss.position.y, 1);
+ }
+ }
+ boss.modeSwitch = 200;
+ }
+ }
+ if (boss.mode == "hide") { /* Find the furthest point from M and get to it */
+ var longest = 0;
+ pathPoints.forEach(item => {
+ if (item[0] == 1150) {
+ return;
+ }
+ var iL = pythag(item, [m.pos.x, m.pos.y]);
+ if (iL > longest) {
+ longest = iL;
+ pfGoal = item;
+ }
+ });
+ }
+ else if (boss.mode == "strike") {
+ pfGoal = pathPoints[0]; // Target M
+ }
+ else if (boss.mode == "spawn") {
+ pfGoal = pathPoints[4]; // Go to Home Base to spawn
+ }
+ if (boss.mode != "recharge") {
+ if (m.pos.x > 2350 || m.pos.x < -150 || m.pos.y > 50) {
+ boss.mode = "hide";
+ }
+ pathFind(pfGoal, [boss.position.x, boss.position.y]);
+ if (!path) {
+ return; // If it couldn't pathfind, just drift
+ }
+ var goalX = path[0][0];
+ var goalY = path[0][1];
+
+ var dX = goalX - boss.position.x;
+ var dY = goalY - boss.position.y;
+ var hyp = Math.sqrt(dX * dX + dY * dY);
+ Matter.Body.applyForce(boss, {
+ x: goalX,
+ y: goalY
+ }, {
+ x: dX / hyp * 0.04 * (boss.mode == "strike" ? 2 : 1),
+ y: dY / hyp * 0.04 * (boss.mode == "strike" ? 2 : 1)// - 0.005
+ });
+ }
+ if (boss.mode == "spawn") {
+ boss.stabCycle++;
+ if (boss.stabCycle > 25) {
+ if (Math.abs(dX) < 200 && dY > 0) {
+ Matter.Body.applyForce(boss, {
+ x: player.position.x,
+ y: player.position.y
+ }, {
+ x: 0,
+ y: 5
+ });
+ }
+ boss.stabCycle = 0;
+ }
+ boss.spawnCycle++;
+ if (boss.spawnCycle > boss.spawnDelay) {
+ spawny();
+ boss.spawnDelay += 4;
+ boss.spawnCycle = 0;
+ }
+ }
+ };
+ boss.showHealthBar = true;
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ tlinat() { // _Destined_ formerly Richard0820#2652
+ simulation.makeTextLog(`
tlinat by
Richard0820 `);
+ simulation.fallHeight = 1 / 0, level.setPosToSpawn(0, -1e3), level.exit.x = 5100, level.exit.y = 3770, spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20), spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20), level.defaultZoom = 3000, simulation.zoomTransition(level.defaultZoom), document.body.style.backgroundColor = "#d8dadf";
+ let e = 0,
+ t = 0;
+ const boidsFlocking = function (mob, otherMobs) {
+ const cohesionFactor = 0.01;
+ const separationFactor = 0.0001;
+ const alignmentFactor = 0.04;
+ let averagePosition = { x: 0, y: 0 };
+ let averageVelocity = { x: 0, y: 0 };
+ let nearbyMobsCount = 0;
+ for (const otherMob of otherMobs) {
+ if (otherMob !== mob) {
+ const distanceSquared = Vector.magnitudeSquared(Vector.sub(mob.position, otherMob.position));
+ const boidRangeSquared = 300 * 300; // Adjust boid range as needed
+ if (distanceSquared < boidRangeSquared) {
+ averagePosition = Vector.add(averagePosition, otherMob.position);
+ averageVelocity = Vector.add(averageVelocity, otherMob.velocity);
+ nearbyMobsCount++;
+ }
+ }
+ }
+ if (nearbyMobsCount > 0) {
+ averagePosition = Vector.div(averagePosition, nearbyMobsCount);
+ averageVelocity = Vector.div(averageVelocity, nearbyMobsCount);
+ const cohesionForce = Vector.mult(Vector.sub(averagePosition, mob.position), cohesionFactor);
+ mob.force = Vector.add(mob.force, cohesionForce);
+ const separationForce = Vector.mult(Vector.sub(mob.position, averagePosition), separationFactor);
+ mob.force = Vector.add(mob.force, separationForce);
+ const alignmentForce = Vector.mult(Vector.sub(averageVelocity, mob.velocity), alignmentFactor);
+ mob.force = Vector.add(mob.force, alignmentForce);
+ }
+ };
+ function ghoster(x, y, radius = 50 + Math.ceil(Math.random() * 90)) {
+ mobs.spawn(x, y, 7, radius, "transparent");
+ let me = mob[mob.length - 1];
+ me.seeAtDistance2 = 300000;
+ me.accelMag = 0.00004 + 0.00015 * simulation.accelScale;
+ if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search
+ // Matter.Body.setDensity(me, 0.0015); //normal is 0.001
+ me.damageReduction = 0.5
+ me.stroke = "transparent"; //used for drawGhost
+ me.alpha = 1; //used in drawGhost
+ me.isNotCloaked = false; //used in drawGhost
+ me.isBadTarget = true;
+ // me.leaveBody = false;
+ me.collisionFilter.mask = cat.bullet //| cat.body
+ me.showHealthBar = false;
+ me.memory = 600;
+ me.do = function () {
+ boidsFlocking(me, mob);//Stack, increase power.
+ if (this.speed > 7) {
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * 0.8,
+ y: this.velocity.y * 0.8
+ });
+ }
+ this.seePlayerCheckByDistance();
+ this.checkStatus();
+ this.attraction();
+ this.search();
+ //draw
+ if (this.distanceToPlayer2() < this.seeAtDistance2) {
+ if (this.alpha < 1) this.alpha += 0.011 * simulation.CDScale; //near player go solid
+ } else {
+ if (this.alpha > 0) this.alpha -= 0.05; ///away from player, hide
+ }
+ if (this.alpha > 0) {
+ if (this.alpha > 0.7 && this.seePlayer.recall) {
+ this.healthBar();
+ if (!this.isNotCloaked) {
+ this.isNotCloaked = true;
+ this.isBadTarget = false;
+ this.collisionFilter.mask = cat.player | cat.bullet
+ }
+ }
+ //draw body
+ ctx.beginPath();
+ const vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ // ctx.lineWidth = 1;
+ ctx.fillStyle = `rgba(255,255,255,${this.alpha * this.alpha})`;
+ ctx.fill();
+ } else if (this.isNotCloaked) {
+ this.isNotCloaked = false;
+ this.isBadTarget = true;
+ this.collisionFilter.mask = cat.bullet; //can't touch player or walls
+ }
+ };
+ }
+ function o(e, t, o) {
+ const l = {
+ J: [" #### ", " # ", " # ", " # ", " # # ", " # # ", " ## "],
+ I: [" # ", " # ", " # ", " # ", " # ", " # ", " # "],
+ N: [" # # ", " ## # ", " ## # ", " # ## ", " # ## ", " # # ", " # # "],
+ " ": [" ", " ", " ", " ", " ", " ", " "],
+ O: [" ## ", " # # ", " # # ", " # # ", " # # ", " # # ", " ## "],
+ U: [" # # ", " # # ", " # # ", " # # ", " # # ", " # # ", " ### "],
+ R: [" #### ", " # #", " #### ", " # # ", " # # ", " # #", " # #"],
+ D: [" ### ", " # ## ", " # # ", " # # ", " # # ", " # ## ", " ### "],
+ S: [" #### ", " # ", " # ", " ### ", " ## ", " # ", " ##### "],
+ C: [" ##### ", " # ", " # ", " # ", " # ", " # ", " ##### "],
+ V: [" # # ", " # # ", " # # ", " # # ", " # # ", " # # ", " # "],
+ E: [" ##### ", " # ", " # ", " ##### ", " # ", " # ", " ##### "],
+ ".": [" ", " ", " ", " ", " ", " ## ", " ## "],
+ "/": [" #", " # ", " # ", " # ", " # ", " # ", "# "],
+ G: [" ###### ", " # ", " # ", " # ### ", " # # ", " # # ", " ###### "],
+ Q: [" ###### ", " # # ", " # # ", " # # ", " # # # ", " # # ", " #### # ", " # "],
+ 8: [" ##### ", " # # ", " # # ", " ##### ", " # # ", " # # ", " ##### "],
+ g: [" ##### ", " # # ", " # # ", " ##### ", " # ", " # ", " ###### "],
+ Y: [" # # ", " # # ", " # # ", " # ", " # ", " # ", " # "],
+ 4: [" # ", " # # ", " # # ", " # # ", " ###### ", " # ", " # "],
+ W: [" # # ", " # # ", " # # ", " # # # ", " # # # # ", " ## ## ", " # # "],
+ e: [" ###### ", " # # ", " # # ", " ####### ", " # ", " # ", " ###### "],
+ c: [" ###### ", "# ", "# ", "# ", "# ", "# ", " ###### ", " "],
+ m: [" # ", " ### ### ", " # # # ", " # # # ", " # # # ", " # # # ", " # # # "]
+ },
+ a = (e, t) => {
+ ctx.fillStyle = "black", ctx.fillRect(e, t, 50, 50)
+ },
+ n = (e, t, o) => {
+ const n = l[e];
+ if (n)
+ for (let e = 0; e < n.length; e++) {
+ const l = n[e];
+ for (let n = 0; n < l.length; n++) {
+ if ("#" === l[n]) {
+ a(t + 20 * n, o + 20 * e)
+ }
+ }
+ }
+ };
+ for (let l = 0; l < o.length; l++) {
+ n(o[l], e + 250 * l - Math.abs(1.5 * e), t)
+ }
+ }
+ simulation.makeTextLog(`
Look up
Walk right to tp to maze Exit is at the bottom left `), Matter.Body.scale(player.parts[3], 2, 2), level.custom = () => {
+ if (level.exit.drawAndCheck(), level.enter.draw(), player.position.y > 1e5 && Matter.Body.setPosition(player, {
+ x: 5100,
+ y: -5925
+ }), player.position.x > 2500 && 0 == e) {
+ Matter.Body.setPosition(player, {
+ x: 5100,
+ y: -5925
+ }), e++;
+ for (let e = 0; e < map.length; e++) Math.random() < .75 && ghoster(map[e].position.x, map[e].position.y);
+ simulation.makeTextLog("Watch out for
ghosters Peace ✌️")
+ }
+ player.position.x > level.exit.x && player.position.x < level.exit.x + 100 && player.position.y > level.exit.y - 150 && player.position.y < level.exit.y - 0 && player.velocity.y < .15 && 0 == t && (t++, Matter.Body.scale(player.parts[3], .5, .5))
+ }, level.customTopLayer = () => {
+ player.position.x > -1200 && player.position.x < 4500 && (o(2e3, -3e3, "JOIN OUR DISCORD SERVER"), o(1500, -2700, "DISCORD.GG/Q8gY4WeUcm"))
+ }, spawn.mapRect(-1e3, -950, 5950, 100), spawn.mapRect(-1325, -3450, 100, 2575), spawn.mapRect(-1325, -950, 350, 100), spawn.mapRect(4850, -3400, 100, 2550), spawn.mapRect(-1325, -3450, 6275, 100),
+ function (e, t, o, l, a) {
+ const n = o / a,
+ s = l / a,
+ i = e - o / 2,
+ p = t - l / 2,
+ r = [];
+ for (let e = 0; e < a; e++) {
+ r[e] = [];
+ for (let t = 0; t < a; t++) r[e][t] = 1
+ }
+ const c = [];
+ (function e(t, o) {
+ r[t][o] = 0;
+ const l = [{
+ dx: 0,
+ dy: -1
+ }, {
+ dx: 1,
+ dy: 0
+ }, {
+ dx: 0,
+ dy: 1
+ }, {
+ dx: -1,
+ dy: 0
+ }];
+ l.sort((() => Math.random() - .5));
+ for (const n of l) {
+ const l = t + 2 * n.dx,
+ s = o + 2 * n.dy;
+ l >= 0 && l < a && s >= 0 && s < a && 1 === r[l][s] && (r[t + n.dx][o + n.dy] = 0, r[l][s] = 0, c.push({
+ x: t + n.dx,
+ y: o + n.dy
+ }), e(l, s))
+ }
+ })(0, 0), r[a - 1][a - 1] = 1;
+ for (let e = -1; e < a + 1; e++) {
+ let t = -1,
+ o = -1;
+ for (let l = -1; l < a + 1; l++)
+ if (e >= 0 && e < a && l >= 0 && l < a && 1 === r[e][l]) - 1 === t && (t = l), o = l;
+ else if (-1 !== t) {
+ const l = i + e * n,
+ a = p + t * s,
+ r = n,
+ c = (o - t + 1) * s;
+ c !== s && spawn.mapRect(l, a, r, c), t = -1, o = -1
+ }
+ }
+ for (let e = -1; e < a + 1; e++) {
+ let t = -1,
+ o = -1;
+ for (let l = -1; l < a + 1; l++)
+ if (l >= 0 && l < a && e >= 0 && e < a && 1 === r[l][e]) - 1 === t && (t = l), o = l;
+ else if (-1 !== t) {
+ const l = i + t * n,
+ a = p + e * s,
+ r = (o - t + 1) * n,
+ c = s;
+ r !== n && spawn.mapRect(l, a, r, c), t = -1, o = -1
+ }
+ }
+ spawn.mapRect(i - n, p - s, n * a, s), spawn.mapRect(i - n, p - s, n, s * a), spawn.mapRect(i + (a - 1) * n, p - s, n, s * (a + 1)), spawn.mapRect(i - n, p + (a - 1) * s, n * (a + 1), s)
+ }(1e4, -1e3, 1e4, 1e4, 50);
+ },
+ ruins() { // by SiddhUPe
+ // simulation.enableConstructMode()
+ simulation.makeTextLog(`
ruins by
SiddhUPe `);
+
+ level.setPosToSpawn(0, -50); //normal spawn
+ level.exit.x = 19531;
+ level.exit.y = 882 + 70;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d8dadf";
+ // color.map = "#444" //custom map color
+
+
+ level.customTopLayer = () => { };
+ spawn.mapRect(875, 0, 1000, 100);
+ spawn.mapRect(1825, -400, 50, 225);
+ spawn.mapRect(1825, -400, 675, 50);
+ spawn.mapRect(1825, 0, 675, 100);
+ spawn.mapRect(2500, -575, 50, 225);
+ spawn.mapRect(2500, -575, 850, 50);
+ spawn.mapRect(2500, -100, 875, 175);
+ spawn.mapRect(2500, 75, 875, 25);
+ spawn.mapRect(3350, -575, 25, 50);
+ spawn.mapRect(2450, -50, 75, 75);
+ spawn.mapRect(2425, -25, 25, 25);
+ spawn.mapRect(2475, -75, 25, 25);
+ spawn.mapRect(3375, -575, 75, 325);
+ spawn.mapRect(3375, -100, 75, 300);
+ spawn.mapRect(3450, -50, 25, 250);
+ spawn.mapRect(3475, -25, 25, 225);
+ spawn.mapRect(3500, 0, 25, 200);
+ spawn.mapRect(3525, 25, 25, 175);
+ spawn.mapRect(3550, 75, 25, 125);
+ spawn.mapRect(3550, 50, 25, 150);
+ spawn.mapRect(3575, 75, 25, 125);
+ spawn.mapRect(3600, 100, 25, 100);
+ spawn.mapRect(3625, 150, 25, 50);
+ spawn.mapRect(2875, -1375, 350, 75);
+ spawn.mapRect(3150, -1375, 75, 350);
+ spawn.mapRect(3100, -1300, 50, 50);
+ spawn.mapRect(3075, -1300, 25, 25);
+ spawn.mapRect(3125, -1250, 25, 25);
+ spawn.mapRect(2825, -1375, 50, 125);
+ spawn.mapRect(3100, -1025, 125, 50);
+ spawn.mapRect(2800, -1350, 25, 75);
+ spawn.mapRect(3125, -975, 75, 25);
+ spawn.mapRect(3225, -1350, 25, 300);
+ spawn.mapRect(2875, -1400, 275, 25);
+ spawn.mapRect(2900, -1425, 225, 25);
+ spawn.mapRect(3250, -1325, 25, 250);
+ spawn.mapRect(2875, -1300, 25, 25);
+ spawn.mapRect(3125, -1050, 50, 25);
+ spawn.mapRect(5325, 800, 50, 225);
+ spawn.mapRect(5325, 975, 300, 50);
+ spawn.mapRect(5375, 925, 50, 50);
+ spawn.mapRect(5375, 900, 25, 25);
+ spawn.mapRect(5425, 950, 25, 25);
+ spawn.mapRect(5325, 775, 100, 25);
+ spawn.mapRect(5625, 925, 25, 100);
+ spawn.mapRect(5350, 800, 50, 25);
+ spawn.mapRect(5600, 950, 25, 50);
+ spawn.mapRect(5300, 800, 25, 175);
+ spawn.mapRect(5400, 1025, 225, 25);
+ spawn.mapRect(5450, 1050, 125, 25);
+ spawn.mapRect(5275, 850, 25, 100);
+ spawn.mapRect(5350, 750, 50, 25);
+ spawn.mapRect(5650, 950, 25, 50);
+ spawn.mapRect(16775, -975, 275, 50);
+ spawn.mapRect(17000, -975, 50, 200);
+ spawn.mapRect(16775, -975, 25, 100);
+ spawn.mapRect(17000, -775, 50, 50);
+ spawn.mapRect(16975, -725, 75, 25);
+ spawn.mapRect(16950, -925, 50, 50);
+ spawn.mapRect(16925, -925, 75, 25);
+ spawn.mapRect(17000, -925, 25, 75);
+ spawn.mapRect(16975, -925, 25, 50);
+ spawn.mapRect(16975, -925, 25, 75);
+ spawn.mapRect(16800, -1000, 200, 25);
+ spawn.mapRect(16850, -1025, 100, 25);
+ spawn.mapRect(17050, -925, 25, 200);
+ spawn.mapRect(17075, -925, 25, 150);
+ spawn.mapRect(16775, -925, 50, 25);
+ spawn.mapRect(17000, -750, 25, 25);
+ spawn.mapRect(16975, -750, 25, 50);
+ spawn.mapRect(16950, -725, 75, 25);
+ spawn.mapRect(9475, -1150, 50, 200);
+ spawn.mapRect(9475, -1150, 25, 25);
+ spawn.mapRect(9475, -1150, 300, 50);
+ spawn.mapRect(9725, -1150, 25, 25);
+ spawn.mapRect(9725, -1150, 50, 200);
+ spawn.mapRect(9500, -975, 25, 25);
+ spawn.mapRect(9500, -975, 75, 25);
+ spawn.mapRect(9700, -975, 25, 25);
+ spawn.mapRect(9675, -975, 75, 25);
+ spawn.mapRect(9525, -1175, 200, 25);
+ spawn.mapRect(9550, -1200, 150, 100);
+ spawn.mapRect(9450, -1125, 50, 150);
+ spawn.mapRect(9750, -1125, 50, 150);
+ spawn.mapRect(9525, -1100, 50, 50);
+ spawn.mapRect(9675, -1100, 50, 50);
+ spawn.mapRect(9575, -1100, 25, 25);
+ spawn.mapRect(9650, -1100, 25, 25);
+ spawn.mapRect(9500, -1050, 50, 25);
+ spawn.mapRect(9700, -1100, 25, 75);
+ spawn.mapRect(11925, -1175, 75, 275);
+ spawn.mapRect(11925, -1175, 475, 75);
+ spawn.mapRect(12325, -1175, 75, 275);
+ spawn.mapRect(11925, -925, 175, 25);
+ spawn.mapRect(12225, -925, 175, 25);
+ spawn.mapRect(11950, -925, 125, 50);
+ spawn.mapRect(12275, -925, 100, 50);
+ spawn.mapRect(11925, -1200, 475, 25);
+ spawn.mapRect(11975, -1225, 375, 25);
+ spawn.mapRect(12000, -1225, 50, 25);
+ spawn.mapRect(12000, -1275, 325, 75);
+ spawn.mapRect(11900, -1175, 50, 250);
+ spawn.mapRect(12375, -1175, 50, 250);
+ spawn.mapRect(11900, -1150, 50, 150);
+ spawn.mapRect(11875, -1150, 50, 200);
+ spawn.mapRect(12375, -1150, 75, 200);
+ spawn.mapRect(11975, -1100, 50, 25);
+ spawn.mapRect(12300, -1100, 75, 25);
+ spawn.mapRect(12300, -950, 25, 50);
+ spawn.mapRect(12000, -950, 25, 75);
+
+ spawn.mapRect(3625, 125, 25, 50);
+ spawn.mapRect(3650, 150, 25, 50);
+ spawn.mapRect(3675, 175, 25, 25);
+ spawn.mapRect(3450, -75, 25, 50);
+ spawn.mapRect(3475, -50, 25, 125);
+ spawn.mapRect(3500, -25, 25, 125);
+ spawn.mapRect(3500, 0, 50, 125);
+ spawn.mapRect(3550, 25, 25, 125);
+ spawn.mapRect(3575, 50, 25, 125);
+ spawn.mapRect(3600, 75, 25, 75);
+ spawn.mapRect(3600, 100, 50, 75);
+ spawn.mapRect(3650, 125, 25, 75);
+ spawn.mapRect(3675, 150, 25, 50);
+ spawn.mapRect(3675, 150, 75, 450);
+ spawn.mapRect(3675, 525, 700, 75);
+ spawn.mapRect(4300, 150, 75, 450);
+ mover = level.mover(3375, -100, 75, 100);
+ pool = level.hazard(3750, 200, 550, 325);
+ spawn.mapRect(-150, -225, 75, 325);
+ spawn.mapRect(-150, -325, 425, 100);
+ spawn.mapRect(-100, -400, 300, 75);
+ spawn.mapRect(-25, -475, 150, 75);
+ spawn.mapRect(200, -350, 25, 50);
+ spawn.mapRect(-50, -425, 25, 100);
+ spawn.mapRect(-125, -350, 25, 100);
+ spawn.mapRect(100, -425, 50, 125);
+ spawn.mapRect(1875, -450, 625, 50);
+ spawn.mapRect(1950, -500, 550, 50);
+ spawn.mapRect(2025, -525, 475, 25);
+ spawn.mapRect(2025, -550, 525, 25);
+ spawn.mapRect(2125, -575, 400, 25);
+ spawn.mapRect(2125, -600, 1325, 50);
+ spawn.mapRect(2475, -550, 950, 200);
+ spawn.mapRect(1825, -350, 100, 175);
+ spawn.mapRect(3350, -375, 25, 125);
+ spawn.mapRect(1850, -425, 50, 25);
+ spawn.mapRect(1925, -475, 125, 25);
+ spawn.mapRect(2000, -525, 125, 25);
+ spawn.mapRect(2100, -575, 200, 25);
+ spawn.mapRect(2400, -650, 725, 75);
+ spawn.mapRect(2500, -675, 475, 75);
+ spawn.mapRect(2625, -725, 225, 100);
+ spawn.mapRect(2675, -750, 125, 25);
+ spawn.mapRect(2600, -700, 25, 50);
+ spawn.mapRect(2850, -700, 25, 75);
+ spawn.mapRect(3075, -625, 75, 50);
+ spawn.mapRect(2375, -625, 50, 75);
+ spawn.mapRect(1900, -350, 100, 75);
+ spawn.mapRect(1925, -300, 50, 50);
+ spawn.mapRect(1975, -350, 75, 50);
+ spawn.mapRect(3325, -350, 50, 25);
+ spawn.mapRect(150, -25, 1425, 50);
+ spawn.mapRect(175, 75, 1200, 50);
+ spawn.mapRect(400, -25, 575, 25);
+ spawn.mapRect(425, -50, 750, 75);
+ spawn.mapRect(1250, -50, 125, 100);
+ spawn.mapRect(1175, -50, 100, 25);
+ spawn.mapRect(725, 100, 500, 50);
+ spawn.mapRect(625, -75, 300, 50);
+ spawn.mapRect(250, -25, 225, 25);
+ spawn.mapRect(1400, 75, 225, 50);
+ spawn.mapRect(950, -75, 200, 25);
+ spawn.mapRect(1200, -75, 125, 25);
+ spawn.mapRect(425, -50, 100, 25);
+ spawn.mapRect(450, -75, 100, 50);
+ spawn.mapRect(250, -50, 125, 50);
+ spawn.mapRect(250, 125, 125, 25);
+ spawn.mapRect(475, 100, 100, 50);
+ spawn.mapRect(650, 125, 25, 25);
+ spawn.mapRect(675, 100, 75, 50);
+ spawn.mapRect(825, 125, 200, 50);
+ spawn.mapRect(-75, 75, 325, 50);
+ spawn.mapRect(0, 100, 175, 50);
+ spawn.mapRect(775, -100, 275, 50);
+ spawn.mapRect(2475, 0, 925, 125);
+ spawn.mapRect(2500, 50, 875, 100);
+ spawn.mapRect(2550, 100, 775, 75);
+ spawn.mapRect(2625, 150, 600, 50);
+ spawn.mapRect(3225, 125, 275, 75);
+ spawn.mapRect(1750, -225, 150, 50);
+ spawn.mapRect(1800, -275, 50, 75);
+ spawn.mapRect(1775, -250, 75, 75);
+ spawn.mapRect(3200, -625, 250, 50);
+ spawn.mapRect(3275, -650, 75, 25);
+ spawn.mapRect(3175, -625, 25, 25);
+ spawn.mapRect(3250, -700, 100, 100);
+ spawn.mapRect(3200, -650, 75, 50);
+ spawn.mapRect(3225, -675, 75, 100);
+ spawn.mapRect(3325, -675, 50, 100);
+ spawn.mapRect(3375, -650, 25, 75);
+ spawn.mapRect(1575, -25, 100, 25);
+ spawn.mapRect(1450, 100, 125, 50);
+ spawn.mapRect(250, -300, 50, 50);
+ spawn.mapRect(275, -275, 50, 25);
+ spawn.mapRect(200, -275, 125, 50);
+ spawn.mapRect(3725, 200, 50, 375);
+ spawn.mapRect(3750, 275, 50, 300);
+ spawn.mapRect(3800, 350, 25, 200);
+ spawn.mapRect(3825, 425, 25, 150);
+ spawn.mapRect(3850, 500, 25, 75);
+ spawn.mapRect(4275, 250, 50, 325);
+ spawn.mapRect(4250, 300, 50, 300);
+ spawn.mapRect(4225, 375, 75, 200);
+ spawn.mapRect(4200, 450, 75, 150);
+ spawn.mapRect(4175, 500, 75, 75);
+ spawn.mapRect(3950, 500, 150, 50);
+ spawn.mapRect(4000, 500, 50, 25);
+ spawn.mapRect(3875, 500, 425, 25);
+ spawn.mapRect(3625, 200, 50, 75);
+ spawn.mapRect(3575, 200, 50, 25);
+ spawn.mapRect(3675, 275, 25, 25);
+ spawn.mapRect(3650, 275, 25, 25);
+ spawn.mapRect(3600, 200, 25, 50);
+ spawn.mapRect(2600, 175, 25, 25);
+ spawn.mapRect(2700, 175, 425, 100);
+ spawn.mapRect(2650, 200, 75, 50);
+ spawn.mapRect(3100, 200, 75, 50);
+ spawn.mapRect(2675, 250, 25, 25);
+ spawn.mapRect(2625, 200, 100, 25);
+ spawn.mapRect(3150, 200, 75, 25);
+ spawn.mapRect(3175, 225, 25, 25);
+ spawn.mapRect(3775, 250, 25, 50);
+ spawn.mapRect(3800, 275, 25, 125);
+ spawn.mapRect(3800, 325, 50, 225);
+ spawn.mapRect(3875, 400, 25, 200);
+ spawn.mapRect(3825, 425, 50, 125);
+ spawn.mapRect(3850, 375, 25, 100);
+ spawn.mapRect(3900, 450, 25, 75);
+ spawn.mapRect(3925, 475, 25, 50);
+ spawn.mapRect(3450, -600, 25, 325);
+ spawn.mapRect(3475, -575, 25, 275);
+ spawn.mapRect(3500, -525, 25, 200);
+ spawn.mapRect(3525, -500, 25, 150);
+ spawn.mapRect(3550, -475, 25, 100);
+ spawn.mapRect(2725, 250, 350, 50);
+ spawn.mapRect(2750, 275, 300, 50);
+ spawn.mapRect(3150, 250, 25, 25);
+ spawn.mapRect(4325, 150, 975, 75);
+ spawn.mapRect(4375, 225, 900, 25);
+ spawn.mapRect(4375, 175, 875, 100);
+ spawn.mapRect(4375, 225, 850, 75);
+ spawn.mapRect(4375, 225, 825, 100);
+ spawn.mapRect(4375, 275, 800, 75);
+ spawn.mapRect(4350, 325, 800, 50);
+ spawn.mapRect(4375, 350, 750, 50);
+ spawn.mapRect(4375, 350, 725, 75);
+ spawn.mapRect(4350, 375, 725, 75);
+ spawn.mapRect(4350, 400, 700, 75);
+ spawn.mapRect(4350, 425, 675, 75);
+ spawn.mapRect(4350, 475, 650, 50);
+ spawn.mapRect(4375, 500, 600, 50);
+ spawn.mapRect(4375, 500, 575, 75);
+ spawn.mapRect(4375, 550, 550, 50);
+ spawn.mapRect(4425, 125, 775, 75);
+ spawn.mapRect(5300, 175, 75, 50);
+ spawn.mapRect(4475, 100, 150, 25);
+ spawn.mapRect(4825, 125, 300, 25);
+ spawn.mapRect(4800, 100, 250, 25);
+ spawn.mapRect(5100, 100, 50, 25);
+ spawn.mapRect(4650, 100, 75, 25);
+ spawn.mapRect(5475, 225, 125, 300);
+ spawn.mapRect(5450, 275, 25, 125);
+ spawn.mapRect(5450, 450, 25, 75);
+ spawn.mapRect(5425, 325, 25, 75);
+ spawn.mapRect(5425, 475, 25, 50);
+ spawn.mapRect(5575, 250, 50, 150);
+ spawn.mapRect(5575, 450, 50, 50);
+ spawn.mapRect(5475, 525, 125, 25);
+ spawn.mapRect(5500, 550, 75, 25);
+ spawn.mapRect(5525, 575, 25, 25);
+ spawn.mapRect(3675, 575, 1050, 50);
+ spawn.mapRect(4175, 600, 250, 50);
+ spawn.mapRect(3850, 625, 100, 25);
+ spawn.mapRect(3700, 625, 75, 25);
+ spawn.mapRect(4050, 625, 50, 25);
+ spawn.mapRect(4500, 625, 225, 25);
+ spawn.mapRect(5725, 150, 75, 225);
+ spawn.mapRect(5700, 175, 25, 150);
+ spawn.mapRect(5775, 250, 50, 100);
+ spawn.mapRect(5950, 325, 75, 75);
+ spawn.mapRect(5925, 375, 25, 25);
+ spawn.mapRect(6000, 350, 50, 50);
+ spawn.mapRect(6125, 425, 1050, 75);
+ spawn.mapRect(6425, 0, 750, 75);
+ spawn.mapRect(6400, 25, 50, 50);
+ spawn.mapRect(6500, -25, 675, 75);
+ spawn.mapRect(6550, -25, 275, 25);
+ spawn.mapRect(6475, -25, 125, 75);
+ spawn.mapRect(6450, -25, 100, 100);
+ spawn.mapRect(6475, -75, 700, 75);
+ spawn.mapRect(6500, -75, 75, 25);
+ spawn.mapRect(6500, -125, 675, 125);
+ spawn.mapRect(6525, -150, 650, 125);
+ spawn.mapRect(6550, -175, 625, 50);
+ spawn.mapRect(6900, -200, 275, 75);
+ spawn.mapRect(6925, -250, 250, 175);
+ spawn.mapRect(6950, -275, 225, 75);
+ spawn.mapRect(6975, -300, 200, 50);
+ spawn.mapRect(7025, -325, 125, 125);
+ spawn.mapRect(6400, 50, 75, 175);
+ spawn.mapRect(6450, 50, 100, 100);
+ spawn.mapRect(6475, 150, 25, 25);
+ spawn.mapRect(6550, 75, 25, 25);
+ spawn.mapRect(6375, 75, 25, 150);
+ spawn.mapRect(6350, 100, 25, 75);
+ spawn.mapRect(6650, 50, 225, 50);
+ spawn.mapRect(6975, 75, 75, 25);
+ spawn.mapRect(6625, -175, 225, 25);
+ spawn.mapRect(6675, -200, 275, 25);
+ spawn.mapRect(6750, -225, 250, 25);
+ spawn.mapRect(6200, 475, 575, 50);
+ spawn.mapRect(6925, 500, 125, 25);
+ spawn.mapRect(6325, 400, 475, 25);
+ spawn.mapRect(6950, 400, 200, 25);
+ spawn.mapRect(7100, 75, 75, 100);
+ spawn.mapRect(7075, 75, 25, 25);
+ spawn.mapRect(7175, -300, 1650, 350);
+ spawn.mapRect(7325, -700, 100, 450);
+ spawn.mapRect(7600, -700, 100, 450);
+ spawn.mapRect(7900, -700, 100, 450);
+ spawn.mapRect(8200, -700, 100, 425);
+ spawn.mapRect(8500, -700, 100, 425);
+ spawn.mapRect(7275, -825, 1375, 125);
+ spawn.mapRect(7400, -700, 50, 25);
+ spawn.mapRect(7575, -700, 50, 25);
+ spawn.mapRect(7875, -700, 150, 25);
+ spawn.mapRect(8175, -700, 150, 25);
+ spawn.mapRect(8475, -700, 150, 25);
+ spawn.mapRect(7300, -325, 150, 75);
+ spawn.mapRect(7575, -325, 150, 75);
+ spawn.mapRect(7875, -325, 150, 75);
+ spawn.mapRect(8175, -325, 150, 75);
+ spawn.mapRect(8475, -325, 150, 75);
+ spawn.mapRect(7700, -700, 25, 25);
+ spawn.mapRect(7300, -700, 75, 25);
+ spawn.mapRect(7150, 50, 75, 50);
+ spawn.mapRect(7175, 100, 25, 25);
+ spawn.mapRect(7225, 50, 25, 25);
+ spawn.mapRect(7300, -850, 1325, 75);
+ spawn.mapRect(7325, -875, 1275, 50);
+ spawn.mapRect(7375, -900, 1200, 25);
+ spawn.mapRect(7350, -900, 25, 25);
+ spawn.mapRect(7375, -900, 200, 25);
+
+ spawn.mapRect(7375, -925, 1175, 25);
+ spawn.mapRect(7400, -950, 1125, 25);
+ spawn.mapRect(7425, -975, 1075, 25);
+ spawn.mapRect(7450, -1000, 1025, 25);
+ spawn.mapRect(7675, -1050, 525, 50);
+ spawn.mapRect(7700, -1050, 100, 25);
+ spawn.mapRect(7700, -1075, 450, 25);
+ spawn.mapRect(7725, -1100, 400, 25);
+ spawn.mapRect(7775, -1125, 300, 25);
+ spawn.mapRect(7650, -1025, 75, 25);
+ spawn.mapRect(8200, -1025, 25, 25);
+ spawn.mapRect(8825, -275, 25, 300);
+ spawn.mapRect(8825, -225, 50, 125);
+ spawn.mapRect(8850, -50, 25, 75);
+ spawn.mapRect(7150, 425, 100, 425);
+ spawn.mapRect(7150, 775, 1600, 100);
+ spawn.mapRect(8750, 400, 75, 475);
+ spawn.mapRect(8825, 400, 25, 475);
+ spawn.mapRect(7225, 450, 50, 325);
+ spawn.mapRect(7250, 500, 50, 275);
+ spawn.mapRect(7300, 550, 25, 225);
+ spawn.mapRect(7325, 600, 25, 175);
+ spawn.mapRect(7350, 650, 25, 125);
+ spawn.mapRect(7375, 675, 25, 100);
+ spawn.mapRect(7400, 700, 25, 75);
+ spawn.mapRect(7425, 725, 25, 50);
+ spawn.mapRect(7450, 750, 25, 25);
+ spawn.mapRect(8725, 425, 50, 375);
+ spawn.mapRect(8700, 450, 75, 375);
+ spawn.mapRect(8675, 475, 100, 375);
+ spawn.mapRect(8650, 500, 125, 375);
+ spawn.mapRect(8600, 525, 100, 350);
+ spawn.mapRect(8575, 550, 100, 275);
+ spawn.mapRect(8550, 575, 150, 250);
+ spawn.mapRect(8525, 625, 100, 225);
+ spawn.mapRect(8500, 675, 100, 125);
+ spawn.mapRect(8625, 825, 25, 25);
+ spawn.mapRect(8475, 700, 75, 75);
+ spawn.mapRect(8450, 725, 50, 50);
+ spawn.mapRect(8425, 750, 100, 25);
+ wastepool = level.hazard(7250, 575, 1450, 200);
+ spawn.mapRect(7375, 0, 250, 75);
+ spawn.mapRect(7700, 0, 725, 75);
+ spawn.mapRect(8575, 50, 150, 25);
+ spawn.mapRect(7750, 50, 475, 50);
+ spawn.mapRect(7425, 50, 175, 50);
+ spawn.mapRect(8600, 50, 50, 50);
+ spawn.mapRect(7200, 850, 875, 50);
+ spawn.mapRect(8225, 850, 125, 50);
+ spawn.mapRect(8475, 850, 275, 50);
+ spawn.mapRect(7300, 875, 375, 50);
+ spawn.mapRect(7925, 875, 100, 50);
+ spawn.mapRect(8525, 875, 125, 50);
+ spawn.mapRect(8250, 875, 75, 50);
+ spawn.mapRect(7800, 900, 50, 25);
+ spawn.mapRect(8125, 875, 50, 50);
+ spawn.mapRect(8075, 875, 50, 50);
+ spawn.mapRect(7125, 500, 25, 325);
+ spawn.mapRect(7100, 475, 25, 300);
+ spawn.mapRect(7075, 600, 50, 125);
+ spawn.mapRect(7075, 500, 50, 25);
+ spawn.mapRect(8850, 425, 75, 450);
+ spawn.mapRect(8925, 475, 75, 400);
+ spawn.mapRect(9000, 550, 75, 325);
+ spawn.mapRect(9075, 650, 75, 25);
+ spawn.mapRect(9075, 625, 75, 250);
+ spawn.mapRect(9150, 675, 75, 200);
+ spawn.mapRect(9225, 750, 75, 125);
+ spawn.mapRect(8925, 450, 25, 25);
+ spawn.mapRect(9000, 500, 25, 75);
+ spawn.mapRect(9000, 525, 25, 100);
+ spawn.mapRect(9000, 525, 50, 100);
+ spawn.mapRect(9050, 575, 50, 100);
+ spawn.mapRect(9075, 600, 50, 75);
+ spawn.mapRect(9150, 650, 25, 100);
+ spawn.mapRect(9225, 725, 50, 100);
+ spawn.mapRect(9225, 700, 25, 100);
+ spawn.mapRect(9300, 800, 1375, 75);
+ spawn.mapRect(9300, 775, 25, 50);
+ spawn.mapRect(9425, 775, 200, 25);
+ spawn.mapRect(9500, 875, 200, 25);
+ spawn.mapRect(9725, 825, 200, 75);
+ spawn.mapRect(10000, 850, 125, 50);
+ spawn.mapRect(10225, 850, 400, 50);
+ spawn.mapRect(9775, 775, 125, 25);
+ spawn.mapRect(10100, 775, 75, 75);
+ spawn.mapRect(10275, 750, 225, 75);
+ spawn.mapRect(9975, 775, 25, 50);
+ spawn.mapRect(10000, 775, 25, 50);
+ spawn.mapRect(10025, 775, 25, 75);
+ spawn.mapRect(10675, 775, 50, 100);
+ spawn.mapRect(10725, 725, 50, 150);
+ spawn.mapRect(10775, 650, 50, 225);
+ spawn.mapRect(10825, 575, 50, 300);
+ spawn.mapRect(10875, 500, 50, 375);
+ spawn.mapRect(10925, 425, 275, 450);
+ spawn.mapRect(11200, 500, 50, 375);
+ spawn.mapRect(11250, 575, 50, 300);
+ spawn.mapRect(11300, 650, 50, 225);
+ spawn.mapRect(11350, 725, 50, 150);
+ spawn.mapRect(11400, 775, 50, 100);
+ spawn.mapRect(10700, 750, 75, 75);
+ spawn.mapRect(10775, 700, 25, 25);
+ spawn.mapRect(10750, 700, 75, 75);
+ spawn.mapRect(10800, 625, 125, 75);
+ spawn.mapRect(10850, 550, 125, 50);
+ spawn.mapRect(10900, 475, 150, 75);
+ spawn.mapRect(11125, 475, 100, 50);
+ spawn.mapRect(11200, 550, 75, 50);
+ spawn.mapRect(11275, 625, 50, 75);
+ spawn.mapRect(11325, 700, 50, 75);
+ spawn.mapRect(11375, 750, 50, 75);
+ spawn.mapRect(11550, 225, 1525, 75);
+ spawn.mapRect(11450, 825, 1625, 50);
+ spawn.mapRect(11450, 800, 1625, 75);
+ spawn.mapRect(11525, -350, 50, 650);
+ spawn.mapRect(11850, -350, 50, 650);
+ spawn.mapRect(12225, -350, 50, 650);
+ spawn.mapRect(12600, -350, 50, 650);
+ spawn.mapRect(13000, -350, 75, 650);
+ spawn.mapRect(11525, -200, 1525, 50);
+ spawn.mapRect(11525, 50, 1550, 50);
+ spawn.mapRect(11525, -400, 1550, 50);
+ spawn.mapRect(11575, -425, 1450, 50);
+ spawn.mapRect(11625, -450, 1325, 75);
+ spawn.mapRect(11700, -475, 1175, 75);
+ spawn.mapRect(11725, -500, 1125, 75);
+ spawn.mapRect(11825, -400, 100, 75);
+ spawn.mapRect(11825, 200, 100, 75);
+ spawn.mapRect(12200, -375, 100, 50);
+ spawn.mapRect(12200, 200, 100, 75);
+ spawn.mapRect(12575, 200, 100, 75);
+ spawn.mapRect(12575, -375, 100, 50);
+ spawn.mapRect(11500, 825, 50, 25);
+ spawn.mapRect(11550, 775, 175, 25);
+ spawn.mapRect(11525, 875, 250, 25);
+ spawn.mapRect(11875, 750, 225, 50);
+ spawn.mapRect(11950, 850, 375, 50);
+ spawn.mapRect(12500, 775, 250, 75);
+ spawn.mapRect(12750, 850, 175, 50);
+
+
+ // books
+ spawn.bodyRect(11575, -300, 25, 100);
+ spawn.bodyRect(11600, -300, 25, 100);
+ spawn.bodyRect(11625, -300, 25, 100);
+ spawn.bodyRect(11650, -300, 25, 100);
+ spawn.bodyRect(11675, -300, 25, 100);
+ spawn.bodyRect(11700, -300, 25, 100);
+ spawn.bodyRect(11725, -300, 25, 100);
+ spawn.bodyRect(11750, -300, 25, 100);
+ spawn.bodyRect(11775, -300, 25, 100);
+ spawn.bodyRect(11800, -300, 25, 100);
+ spawn.bodyRect(11825, -300, 25, 100);
+ spawn.bodyRect(11900, -50, 25, 100);
+ spawn.bodyRect(11925, -50, 25, 100);
+ spawn.bodyRect(11950, -50, 25, 100);
+ spawn.bodyRect(11975, -50, 50, 100);
+ spawn.bodyRect(12025, -50, 50, 100);
+ spawn.bodyRect(12075, -50, 25, 100);
+ spawn.bodyRect(12100, -50, 50, 100);
+ spawn.bodyRect(12150, -50, 25, 100);
+ spawn.bodyRect(12175, -50, 25, 100);
+ spawn.bodyRect(12200, -50, 25, 100);
+ spawn.bodyRect(11900, -300, 25, 100);
+ spawn.bodyRect(11925, -300, 25, 100);
+ spawn.bodyRect(11950, -225, 75, 25);
+ spawn.bodyRect(12650, -50, 25, 100);
+ spawn.bodyRect(12675, -50, 25, 100);
+ spawn.bodyRect(12725, -50, 25, 100);
+ spawn.bodyRect(12750, -50, 50, 100);
+ spawn.bodyRect(12650, -275, 25, 75);
+ spawn.bodyRect(12675, -275, 25, 75);
+ spawn.bodyRect(12700, -275, 50, 75);
+ spawn.bodyRect(12750, -275, 25, 75);
+ spawn.bodyRect(12775, -275, 25, 75);
+ spawn.bodyRect(12800, -275, 25, 75);
+ spawn.bodyRect(12825, -275, 25, 75);
+ spawn.bodyRect(12850, -275, 50, 75);
+ spawn.bodyRect(12900, -275, 50, 75);
+ spawn.bodyRect(12950, -275, 50, 75);
+ spawn.mapRect(12200, 775, 175, 50);
+ spawn.mapRect(11550, 250, 1500, 75);
+ spawn.mapRect(11575, 275, 1450, 75);
+ spawn.mapRect(11600, 325, 1400, 50);
+ spawn.mapRect(11625, 350, 1350, 50);
+ spawn.mapRect(11725, 375, 1150, 50);
+ spawn.mapRect(11900, 400, 800, 50);
+ spawn.mapRect(12100, 425, 425, 50);
+ spawn.mapRect(12125, 475, 375, 25);
+ spawn.mapRect(12200, 475, 225, 50);
+ spawn.mapRect(11475, -400, 50, 700);
+ spawn.mapRect(11450, -375, 50, 625);
+ spawn.mapRect(11425, -350, 100, 600);
+ spawn.mapRect(11400, -300, 75, 525);
+ spawn.mapRect(11375, -250, 100, 400);
+ spawn.mapRect(11350, -150, 50, 200);
+ spawn.mapRect(13075, 825, 25, 50);
+ spawn.mapRect(13100, 850, 25, 25);
+ spawn.mapRect(13200, 700, 100, 225);
+ spawn.mapRect(13300, 775, 25, 100);
+ spawn.mapRect(13325, 825, 25, 50);
+ spawn.mapRect(13175, 775, 25, 125);
+ spawn.mapRect(13225, 675, 50, 25);
+ spawn.mapRect(13225, 925, 50, 25);
+ spawn.mapRect(9250, 75, 1400, 150);
+ spawn.mapRect(9250, -225, 150, 300);
+ spawn.mapRect(9250, -275, 575, 50);
+ spawn.mapRect(9675, -225, 150, 300);
+ spawn.mapRect(9325, -325, 400, 50);
+ spawn.mapRect(9400, -350, 250, 25);
+ spawn.mapRect(9475, -375, 125, 25);
+ spawn.mapRect(9825, -225, 150, 300);
+ spawn.mapRect(10225, -225, 150, 300);
+ spawn.mapRect(9825, -275, 550, 50);
+ spawn.mapRect(9900, -325, 375, 50);
+ spawn.mapRect(9950, -350, 275, 25);
+ spawn.mapRect(10000, -375, 175, 25);
+ spawn.mapRect(10350, -275, 50, 375);
+ spawn.mapRect(10400, -250, 25, 325);
+ spawn.mapRect(10425, -225, 25, 375);
+ spawn.mapRect(10450, -200, 25, 325);
+ spawn.mapRect(10475, -175, 25, 350);
+ spawn.mapRect(10500, -150, 25, 300);
+ spawn.mapRect(10525, -125, 25, 300);
+ spawn.mapRect(10550, -100, 25, 225);
+ spawn.mapRect(10575, -75, 25, 200);
+ spawn.mapRect(10600, -50, 25, 150);
+ spawn.mapRect(10625, -25, 25, 175);
+ spawn.mapRect(9225, -225, 25, 450);
+ spawn.mapRect(9200, -175, 25, 400);
+ spawn.mapRect(9175, -150, 50, 375);
+ spawn.mapRect(9150, -125, 50, 350);
+ spawn.mapRect(9400, -175, 25, 275);
+ spawn.mapRect(9425, -125, 25, 200);
+ spawn.mapRect(9650, -175, 25, 250);
+ spawn.mapRect(9625, -125, 25, 275);
+ spawn.mapRect(9975, -175, 25, 300);
+ spawn.mapRect(10000, -125, 25, 250);
+ spawn.mapRect(10200, -175, 25, 300);
+ spawn.mapRect(10175, -125, 25, 225);
+ spawn.mapRect(9325, 225, 225, 25);
+ spawn.mapRect(9675, 225, 250, 50);
+ spawn.mapRect(10075, 225, 200, 25);
+ spawn.mapRect(10400, 200, 175, 50);
+ spawn.mapRect(13425, 675, 1425, 100);
+ spawn.mapRect(13450, 725, 375, 75);
+ spawn.mapRect(13850, 775, 225, 50);
+ spawn.mapRect(14150, 750, 300, 50);
+ spawn.mapRect(14575, 750, 200, 75);
+ spawn.mapRect(13550, 800, 150, 25);
+ spawn.mapRect(14250, 800, 225, 25);
+ spawn.mapRect(13425, 275, 1425, 100);
+ spawn.mapRect(13475, 250, 1325, 75);
+ spawn.mapRect(13550, 225, 1125, 75);
+ spawn.mapRect(13600, 200, 1025, 25);
+ spawn.mapRect(13650, 150, 925, 50);
+ spawn.mapRect(13725, 100, 775, 100);
+ spawn.mapRect(13825, 50, 525, 100);
+ spawn.mapRect(13900, 0, 350, 75);
+ spawn.mapRect(13975, -25, 175, 75);
+ spawn.mapRect(13875, 25, 50, 50);
+ spawn.mapRect(13800, 75, 75, 50);
+ spawn.mapRect(13700, 125, 75, 50);
+ spawn.mapRect(13625, 200, 50, 25);
+ spawn.mapRect(13650, 175, 25, 25);
+ spawn.mapRect(13625, 175, 125, 75);
+ spawn.mapRect(14350, 75, 25, 50);
+ spawn.mapRect(14250, 0, 25, 75);
+ spawn.mapRect(14275, 50, 25, 50);
+ spawn.mapRect(14275, 25, 25, 75);
+ spawn.mapRect(14500, 125, 25, 75);
+ spawn.mapRect(14575, 175, 25, 75);
+ spawn.mapRect(13475, 650, 400, 50);
+ spawn.mapRect(13975, 675, 75, 25);
+ spawn.mapRect(14000, 650, 50, 50);
+ spawn.mapRect(14150, 625, 675, 100);
+ spawn.mapRect(14325, 625, 100, 25);
+ spawn.mapRect(14300, 600, 325, 25);
+ spawn.mapRect(13525, 325, 375, 100);
+ spawn.mapRect(13975, 375, 400, 25);
+ spawn.mapRect(14500, 325, 100, 75);
+ spawn.mapRect(14850, 675, 50, 200);
+ spawn.mapRect(14875, 700, 50, 175);
+ spawn.mapRect(14925, 725, 50, 150);
+ spawn.mapRect(14975, 750, 50, 125);
+ spawn.mapRect(15025, 775, 50, 100);
+ spawn.mapRect(15075, 750, 1150, 100);
+ spawn.mapRect(15100, 825, 225, 50);
+ spawn.mapRect(15500, 850, 225, 25);
+ spawn.mapRect(15925, 775, 275, 100);
+ spawn.mapRect(15775, 825, 50, 50);
+ spawn.mapRect(15225, 250, 1050, 125);
+ spawn.mapRect(15250, 200, 1000, 50);
+ spawn.mapRect(15275, 175, 950, 50);
+ spawn.mapRect(15300, 150, 900, 50);
+ spawn.mapRect(15325, 125, 850, 25);
+ spawn.mapRect(15350, 100, 800, 25);
+ spawn.mapRect(15375, 75, 750, 25);
+ spawn.mapRect(15400, 50, 700, 100);
+ spawn.mapRect(15425, 25, 650, 75);
+ spawn.mapRect(15450, 0, 600, 50);
+ spawn.mapRect(15475, -25, 550, 75);
+ spawn.mapRect(15500, -50, 500, 75);
+ spawn.mapRect(15525, -75, 450, 75);
+ spawn.mapRect(15550, -100, 400, 75);
+ spawn.mapRect(15575, -125, 350, 75);
+ spawn.mapRect(15600, -150, 300, 50);
+ spawn.mapRect(15625, -175, 250, 50);
+ spawn.mapRect(15650, -200, 200, 25);
+ spawn.mapRect(15675, -225, 150, 75);
+ spawn.mapRect(15700, -250, 100, 75);
+ spawn.mapRect(16275, 250, 25, 125);
+ spawn.mapRect(16250, 225, 25, 25);
+ spawn.mapRect(15200, 250, 25, 125);
+ spawn.mapRect(15225, 225, 25, 25);
+ spawn.mapRect(15275, 350, 175, 50);
+ spawn.mapRect(15550, 350, 425, 75);
+ spawn.mapRect(16100, 375, 175, 25);
+ spawn.mapRect(14700, -375, 50, 325);
+ spawn.mapRect(14700, -425, 375, 50);
+ spawn.mapRect(14750, -375, 125, 100);
+ spawn.mapRect(14750, -275, 75, 75);
+ spawn.mapRect(14850, -375, 100, 50);
+ spawn.mapRect(14825, -275, 25, 25);
+ spawn.mapRect(14950, -375, 25, 25);
+ spawn.mapRect(14875, -325, 25, 25);
+ spawn.mapRect(14725, -200, 50, 25);
+ spawn.mapRect(14700, -75, 100, 25);
+ spawn.mapRect(15050, -425, 25, 100);
+ spawn.mapRect(14725, -450, 325, 25);
+ spawn.mapRect(14775, -475, 225, 25);
+ spawn.mapRect(14825, -500, 125, 25);
+ spawn.mapRect(14675, -350, 25, 100);
+ spawn.mapRect(14675, -175, 25, 75);
+ spawn.mapRect(14850, 325, 25, 50);
+ spawn.mapRect(5700, -725, 375, 50);
+ spawn.mapRect(6025, -725, 50, 325);
+ spawn.mapRect(5775, -675, 250, 25);
+ spawn.mapRect(6000, -675, 25, 225);
+ spawn.mapRect(5950, -650, 50, 75);
+ spawn.mapRect(5900, -650, 75, 25);
+ spawn.mapRect(6000, -575, 25, 25);
+ spawn.mapRect(6050, -700, 50, 275);
+ spawn.mapRect(5925, -625, 75, 25);
+ spawn.mapRect(5775, -750, 100, 25);
+ spawn.mapRect(5950, -750, 100, 25);
+ spawn.mapRect(5675, -725, 25, 150);
+ spawn.mapRect(5975, -400, 100, 25);
+ spawn.mapRect(5650, -700, 25, 75);
+ spawn.mapRect(5700, -675, 25, 50);
+ spawn.mapRect(5700, -600, 25, 25);
+ spawn.mapRect(15275, 750, 225, 25);
+ spawn.mapRect(15225, 725, 250, 25);
+ spawn.mapRect(15675, 725, 275, 100);
+ spawn.mapRect(16075, 725, 125, 50);
+ spawn.pulsar(5775.349354333542, -594.9058498351887)
+ spawn.pulsar(5852.915433009502, -545.5679375496002)
+ spawn.pulsar(5921.99534574469, -480.69487503053097)
+ spawn.mapRect(3725, -975, 1525, 100);
+ spawn.mapRect(3750, -650, 300, 75);
+ spawn.mapRect(4300, -650, 300, 75);
+ spawn.mapRect(4950, -650, 300, 75);
+ spawn.mapRect(5250, -975, 75, 400);
+ spawn.mapRect(3725, -975, 75, 400);
+ spawn.mapRect(4325, -600, 250, 50);
+ spawn.mapRect(4350, -550, 200, 25);
+ spawn.mapRect(3800, -575, 225, 25);
+ spawn.mapRect(3825, -550, 175, 25);
+ spawn.mapRect(4975, -600, 275, 50);
+ spawn.mapRect(5025, -550, 175, 25);
+ spawn.mapRect(3800, -1025, 1450, 50);
+ spawn.mapRect(3875, -1075, 1275, 50);
+ spawn.mapRect(3975, -1125, 1000, 50);
+ spawn.mapRect(3950, -1100, 50, 25);
+ spawn.mapRect(3850, -1050, 150, 25);
+ spawn.mapRect(3775, -1000, 200, 25);
+ spawn.mapRect(5225, -975, 75, 25);
+ spawn.mapRect(4950, -1100, 75, 125);
+ spawn.mapRect(5100, -1050, 75, 75);
+ spawn.mapRect(5225, -1000, 50, 100);
+ spawn.mapRect(4350, -675, 150, 75);
+ spawn.mapRect(4525, -650, 50, 25);
+ spawn.mapRect(4550, -675, 50, 75);
+ spawn.mapRect(3825, -650, 50, 25);
+ spawn.mapRect(3825, -675, 150, 50);
+ spawn.mapRect(4025, -675, 25, 100);
+ spawn.mapRect(4950, -675, 75, 50);
+ spawn.mapRect(5075, -675, 75, 75);
+ spawn.mapRect(5200, -675, 75, 50);
+ spawn.pulsar(4068.196906578167, -653.550201356403)
+ spawn.pulsar(4147.672553167598, -651.0093457935446)
+ spawn.pulsar(4228.863663369247, -653.4768859607283)
+ spawn.pulsar(4619.092688319791, -657.3942377732394)
+ spawn.pulsar(4724.821759138369, -653.4213864043036)
+ spawn.pulsar(4873.583205330713, -657.4103118310311)
+ spawn.pulsar(3871.920598597728, -804.0595760512573)
+ spawn.pulsar(4053.019377134256, -778.0061810623848)
+ spawn.pulsar(4211.732836201937, -780.4633597161928)
+ spawn.pulsar(4380.7768131190005, -776.3400515412312)
+ spawn.pulsar(4533.031170401828, -791.1397513503708)
+ spawn.pulsar(4663.577749297493, -789.0488615794887)
+ spawn.pulsar(4965.48351658387, -809.0025104385204)
+ spawn.pulsar(5122.782442346123, -810.2526936643312)
+ spawn.mapRect(3700, -875, 25, 250);
+ spawn.mapRect(5325, -900, 25, 250);
+ spawn.mapRect(5325, -850, 50, 150);
+ spawn.mapRect(5375, -825, 25, 75);
+ spawn.pulsar(14786.058375868968, -140.5759223979466)
+ spawn.pulsar(14862.320083571307, -177.02507110101413)
+ spawn.pulsar(14888.982047411475, -216.4856450590454)
+ spawn.pulsar(14950.503812885598, -280.9333882582806)
+ spawn.pulsar(15003.202057456116, -316.6767970823471)
+ spawn.spinner(759.4093972764956, -356.0541595435453)
+ spawn.spinner(1467.1412487475097, -617.4326431210314)
+ spawn.mapRect(11850, 775, 50, 50);
+ spawn.mapRect(12075, 775, 50, 50);
+ spawn.mapRect(16225, 750, 75, 325);
+ spawn.mapRect(16300, 775, 50, 325);
+ spawn.mapRect(16350, 800, 50, 275);
+ spawn.mapRect(16375, 825, 50, 200);
+ spawn.mapRect(16450, 875, 25, 150);
+ spawn.mapRect(16450, 875, 25, 225);
+ spawn.mapRect(16400, 875, 50, 150);
+ spawn.mapRect(16225, 1025, 250, 75);
+ spawn.mapRect(16475, 925, 25, 175);
+ spawn.mapRect(16500, 975, 25, 125);
+ spawn.mapRect(16525, 1025, 25, 50);
+ spawn.mapRect(16425, 1075, 150, 25);
+ spawn.mapRect(16225, 1100, 1175, 75);
+ spawn.mapRect(17200, 1050, 25, 50);
+ spawn.mapRect(17225, 950, 25, 200);
+ spawn.mapRect(17250, 800, 25, 300);
+ spawn.mapRect(17275, 725, 25, 400);
+ spawn.mapRect(17300, 750, 75, 400);
+ spawn.mapRect(17300, 725, 100, 450);
+ spawn.mapRect(16300, 250, 1075, 125);
+ spawn.mapRect(16450, -75, 100, 400);
+ spawn.mapRect(17100, -75, 100, 400);
+ spawn.mapRect(16425, 200, 150, 50);
+ spawn.mapRect(17075, 200, 150, 50);
+ spawn.mapRect(16425, -75, 150, 25);
+ spawn.mapRect(17075, -75, 150, 50);
+ spawn.mapRect(16425, -50, 150, 50);
+ spawn.mapRect(16575, -75, 525, 50);
+ spawn.mapRect(17075, -50, 150, 50);
+ spawn.mapRect(16550, -100, 550, 25);
+ spawn.mapRect(16575, -125, 500, 75);
+ spawn.mapRect(16600, -150, 450, 75);
+ spawn.mapRect(16625, -175, 400, 75);
+ spawn.mapRect(16675, -200, 275, 50);
+ spawn.mapRect(16750, -225, 125, 100);
+ spawn.mapRect(19700, 675, 50, 325);
+ spawn.mapRect(19725, 700, 50, 250);
+ spawn.mapRect(19750, 750, 25, 175);
+ spawn.mapRect(16775, -25, 100, 275);
+ spawn.mapRect(16750, -25, 150, 25);
+ spawn.mapRect(16750, 225, 150, 50);
+ spawn.pulsar(3037.797768861211, -1242.9871362505041)
+ spawn.pulsar(3070.307596879197, -1219.5627538123044)
+ spawn.pulsar(3111.2633762820287, -1107.7297980154415)
+ spawn.pulsar(5417.516810698634, 842.824851834252)
+ spawn.pulsar(5484.672534515589, 883.9519420960905)
+ spawn.pulsar(5588.5457723826075, 907.389646857348)
+ spawn.pulsar(16845.139047921595, -885.6942536135854)
+ spawn.pulsar(16892.187197333486, -849.5235136465661)
+ spawn.pulsar(16912.323783455256, -764.5275187038021)
+ powerUps.spawn(2571.591711269197, -145.6717604789277, 'heal')
+ powerUps.spawn(4415.693974666946, -15.077304620299628, 'heal')
+ powerUps.spawn(7505.795753124317, -360.0330849392626, 'heal')
+ powerUps.spawn(7809.5145838152075, -388.5517653996709, 'heal')
+ powerUps.spawn(8049.726318297545, 534.4543327703304, 'heal')
+ powerUps.spawn(8514.444440033667, 551.0268033205841, 'heal')
+ powerUps.spawn(8927.146055851512, 407.25359241772685, 'heal')
+ powerUps.spawn(9730.170170158563, 463.5594890235955, 'ammo')
+ powerUps.spawn(9998.34942087522, 434.9511651200589, 'ammo')
+ powerUps.spawn(10119.083720019844, 437.4195779326937, 'ammo')
+ powerUps.spawn(10346.197135080345, 423.1868836972815, 'ammo')
+ powerUps.spawn(1853.3194789931017, -36.87254038474242, 'ammo')
+ powerUps.spawn(4491.396397908616, 40.2862012621236, 'ammo')
+ powerUps.spawn(4954.207518897743, 50.27790416201856, 'ammo')
+ spawn.mapRect(9125, -50, 75, 275);
+ spawn.mapRect(9100, 0, 50, 225);
+ spawn.mapRect(9075, 75, 75, 150);
+ spawn.mapRect(9050, 150, 125, 50);
+ spawn.mapRect(9050, 200, 225, 25);
+ mover1 = level.mover(4000, -1125, 975, 25);
+ mover2 = level.mover(15675, 725, 275, 25);
+ spawn.mapRect(15025, -375, 25, 25);
+ spawn.mapRect(12200, -150, 100, 25);
+ spawn.mapRect(11825, -150, 100, 25);
+ spawn.mapRect(11825, 75, 100, 50);
+ spawn.mapRect(12200, 75, 100, 50);
+ spawn.mapRect(12575, 100, 75, 25);
+ spawn.mapRect(12625, 50, 50, 75);
+ spawn.mapRect(12600, -175, 75, 50);
+ spawn.mapRect(12575, -175, 75, 50);
+ spawn.mapRect(14125, 650, 75, 25);
+ spawn.mapRect(13875, 375, 50, 25);
+ spawn.mapRect(13300, -525, 325, 50);
+ spawn.mapRect(13575, -525, 50, 250);
+ spawn.mapRect(13550, -300, 75, 25);
+ spawn.mapRect(13300, -525, 25, 75);
+ spawn.mapRect(13525, -475, 50, 50);
+ spawn.mapRect(13500, -475, 100, 25);
+ spawn.mapRect(13550, -475, 25, 100);
+ spawn.mapRect(13325, -550, 275, 25);
+ spawn.mapRect(13350, -575, 200, 25);
+ spawn.mapRect(13625, -500, 25, 175);
+ spawn.mapRect(13650, -450, 25, 75);
+ spawn.mapRect(13500, 375, 75, 25);
+ spawn.mapRect(15550, -950, 50, 225);
+ spawn.mapRect(15575, -750, 75, 25);
+ spawn.mapRect(15550, -950, 375, 50);
+ spawn.mapRect(15925, -950, 50, 225);
+ spawn.mapRect(15875, -750, 100, 25);
+ spawn.mapRect(15575, -1000, 375, 75);
+ spawn.mapRect(15625, -1050, 250, 100);
+ spawn.mapRect(15600, -1025, 75, 50);
+ spawn.mapRect(15875, -1000, 25, 25);
+ spawn.mapRect(15825, -1025, 75, 75);
+ spawn.mapRect(15700, -1100, 125, 50);
+ spawn.mapRect(15650, -1075, 75, 50);
+ spawn.mapRect(15800, -1075, 50, 75);
+ spawn.mapRect(15575, -725, 50, 25);
+ spawn.mapRect(15900, -725, 50, 25);
+ spawn.mapRect(15525, -925, 25, 175);
+ spawn.mapRect(15950, -925, 50, 200);
+ spawn.mapRect(15500, -875, 25, 75);
+ spawn.mapRect(16000, -875, 25, 75);
+ spawn.mapRect(15600, -900, 50, 75);
+ spawn.mapRect(15650, -900, 25, 25);
+ spawn.mapRect(15600, -825, 25, 25);
+ spawn.mapRect(15875, -900, 50, 50);
+ spawn.mapRect(15850, -925, 75, 50);
+ spawn.mapRect(15925, -875, 25, 25);
+ spawn.mapRect(15925, -850, 25, 25);
+ spawn.mapRect(15900, -875, 50, 50);
+ bigpool = level.hazard(9075, 575, 1950, 250);
+ spawn.mapRect(16000, -775, 25, 50);
+ spawn.mapRect(16000, -800, 25, 25);
+ spawn.mapRect(15500, -825, 25, 75);
+ spawn.mapRect(15475, -850, 75, 75);
+ spawn.mapRect(16000, -850, 50, 100);
+ spawn.mapRect(10775, -450, 50, 200);
+ spawn.mapRect(10775, -275, 100, 25);
+ spawn.mapRect(11100, -450, 50, 200);
+ spawn.mapRect(11050, -275, 75, 25);
+ spawn.mapRect(10775, -450, 375, 25);
+ spawn.mapRect(10825, -475, 275, 25);
+ spawn.mapRect(10875, -500, 150, 25);
+ spawn.mapRect(10900, -525, 100, 25);
+ spawn.mapRect(10750, -425, 25, 150);
+ spawn.mapRect(11150, -400, 25, 125);
+ spawn.mapRect(10725, -400, 50, 100);
+ spawn.mapRect(11150, -375, 50, 75);
+ spawn.mapRect(10800, -250, 50, 25);
+ spawn.mapRect(10825, -425, 50, 50);
+ spawn.mapRect(10875, -425, 25, 25);
+ spawn.mapRect(10825, -375, 25, 25);
+ spawn.mapRect(11050, -425, 50, 50);
+ spawn.mapRect(11025, -425, 25, 25);
+ spawn.mapRect(11075, -375, 25, 25);
+ spawn.mapRect(950, -1075, 50, 200);
+ spawn.mapRect(950, -1125, 300, 50);
+ spawn.mapRect(1000, -1075, 50, 50);
+ spawn.mapRect(1050, -1075, 25, 25);
+ spawn.mapRect(975, -1025, 50, 25);
+ spawn.mapRect(975, -1150, 250, 25);
+ spawn.mapRect(1000, -1175, 200, 25);
+ spawn.mapRect(900, -1075, 50, 175);
+ spawn.mapRect(875, -1050, 25, 125);
+ spawn.mapRect(950, -875, 125, 25);
+ spawn.mapRect(1250, -1125, 25, 125);
+ spawn.mapRect(975, -850, 75, 25);
+ spawn.mapRect(1250, -1100, 50, 75);
+ spawn.mapRect(925, -900, 50, 25);
+ spawn.mapRect(1050, -1200, 100, 25);
+ spawn.mapRect(1225, -1000, 50, 25);
+ spawn.mapRect(16375, 350, 900, 50);
+ spawn.mapRect(16400, 375, 850, 50);
+ spawn.mapRect(16425, 400, 800, 50);
+ spawn.mapRect(16475, 425, 675, 50);
+ spawn.mapRect(16625, 475, 375, 25);
+ spawn.mapRect(16650, 500, 325, 25);
+ spawn.mapRect(16675, 500, 275, 50);
+ spawn.mapRect(17400, 775, 25, 325);
+ spawn.mapRect(17425, 825, 25, 225);
+ spawn.mapRect(16200, 900, 25, 225);
+ spawn.mapRect(16175, 925, 25, 125);
+ spawn.mapRect(16150, 975, 25, 25);
+ spawn.mapRect(16400, 1150, 850, 50);
+ spawn.mapRect(16475, 1175, 650, 50);
+ spawn.mapRect(16575, 1225, 450, 25);
+ spawn.sneaker(7895.471733263175, 257.75477496554186)
+ spawn.sneaker(8109.4934675858085, 349.44686618726473)
+ spawn.sneaker(7525.886813944122, 391.9511482895349)
+ spawn.sneaker(8076.43795816953, 441.14947363958373)
+ spawn.pulsar(1064.583377612331, -976.2077284446908)
+ spawn.pulsar(1158.3436115513837, -1054.4975368803214)
+ spawn.pulsar(10966.055009228428, -373.8481911663377)
+ spawn.pulsar(10913.989668763379, -261.59108542627166)
+ spawn.pulsar(13454.158594286884, -402.8270664336466)
+ spawn.pulsar(13360.079608974078, -246.97797933698774)
+ spawn.pulsar(13497.913481830354, -251.68317759640576)
+ spawn.pulsar(15687.09056963911, -850.8426925141155)
+ spawn.pulsar(15829.058084589731, -785.4134546702737)
+ spawn.pulsar(15674.313958480483, -685.0594164868394)
+ spawn.pulsar(15819.881465281747, -686.4370174238113)
+ spawn.sneakBoss(18189.441342796745, 537.6633241821036)
+ thirdpool = level.hazard(16425, 925, 925, 200);
+ spawn.mapRect(17675, -525, 75, 725);
+ spawn.mapRect(17625, -475, 75, 650);
+ spawn.mapRect(17575, -425, 75, 575);
+ spawn.mapRect(17700, -525, 1125, 75);
+ spawn.mapRect(17675, 175, 1125, 75);
+ spawn.mapRect(18775, -525, 75, 775);
+ spawn.mapRect(18825, -475, 75, 675);
+ spawn.mapRect(18900, -450, 50, 625);
+ spawn.mapRect(18950, -400, 50, 500);
+ spawn.mapRect(17750, -575, 1000, 50);
+ spawn.mapRect(17775, -625, 950, 50);
+ spawn.mapRect(17800, -675, 900, 75);
+ spawn.mapRect(17825, -725, 850, 125);
+ spawn.mapRect(17850, -750, 800, 25);
+ spawn.mapRect(17750, 125, 50, 50);
+ spawn.mapRect(17750, 100, 25, 25);
+ spawn.mapRect(17800, 150, 25, 25);
+ spawn.mapRect(17750, -450, 75, 75);
+ spawn.mapRect(17750, -400, 25, 50);
+ spawn.mapRect(17800, -450, 50, 25);
+ spawn.mapRect(18750, -450, 25, 25);
+ spawn.mapRect(18725, -450, 50, 50);
+ spawn.mapRect(18700, -475, 25, 25);
+ spawn.mapRect(18725, -450, 25, 25);
+ spawn.mapRect(18700, -450, 75, 25);
+ spawn.mapRect(18750, -425, 25, 50);
+ spawn.mapRect(18725, 125, 75, 75);
+ spawn.mapRect(18700, 150, 50, 50);
+ spawn.mapRect(18750, 100, 75, 50);
+ spawn.mapRect(17850, 150, 850, 50);
+ spawn.mapRect(17825, 150, 25, 50);
+ spawn.mapRect(17550, -350, 25, 450);
+ spawn.mapRect(19000, -325, 25, 400);
+ spawn.mapRect(18000, -775, 475, 25);
+ spawn.mapRect(18025, -800, 425, 75);
+ spawn.mapRect(18050, -825, 375, 75);
+ spawn.mapRect(18075, -850, 325, 50);
+ spawn.mapRect(18100, -875, 275, 100);
+ spawn.mapRect(18125, -900, 225, 75);
+ spawn.mapRect(18150, -925, 175, 75);
+ spawn.mapRect(17275, 750, 1775, 125);
+ spawn.mapRect(17475, 725, 450, 50);
+ spawn.mapRect(18200, 725, 200, 50);
+ spawn.mapRect(18650, 725, 225, 75);
+ spawn.shieldingBoss(18253.51035871325, -131.1707821125636)
+ // spawn.blockBoss(12604.846253470663, 607.6074958800299)
+ spawn.mapRect(17725, 250, 1025, 25);
+ spawn.mapRect(17775, 275, 925, 25);
+ spawn.mapRect(17800, 300, 875, 25);
+ spawn.mapRect(17850, 325, 775, 25);
+ spawn.mapRect(17375, 275, 25, 75);
+ spawn.mapRect(19050, 750, 25, 275);
+ spawn.mapRect(19075, 775, 25, 250);
+ spawn.mapRect(19100, 800, 25, 225);
+ spawn.mapRect(19125, 850, 25, 175);
+ spawn.mapRect(19150, 875, 25, 150);
+ spawn.mapRect(19175, 925, 25, 100);
+ spawn.mapRect(19200, 950, 25, 75);
+ spawn.mapRect(19000, 850, 100, 175);
+ spawn.mapRect(19050, 975, 650, 50);
+ spawn.mapRect(19425, 650, 275, 50);
+ spawn.mapRect(19675, 650, 50, 375);
+ spawn.mapRect(19050, 1025, 625, 25);
+ spawn.mapRect(19075, 1050, 575, 25);
+ spawn.mapRect(19250, 1100, 200, 25);
+ spawn.mapRect(19175, 1075, 375, 25);
+ spawn.mapRect(19450, 625, 225, 25);
+ spawn.mapRect(19500, 600, 150, 50);
+ spawn.mapRect(19625, 700, 50, 50);
+ spawn.mapRect(19600, 700, 25, 25);
+ spawn.mapRect(19650, 750, 25, 25);
+ spawn.mapRect(19400, 650, 25, 100);
+ spawn.mapRect(19375, 675, 25, 50);
+ spawn.mapRect(17600, 875, 250, 25);
+ spawn.mapRect(18100, 850, 375, 50);
+ spawn.mapRect(18650, 875, 325, 25);
+
+ pooldunker = level.mover(7175, 425, 50, 25);
+ level.custom = () => {
+ level.exit.drawAndCheck();
+ pooldunker.VxGoal = 90;
+ pooldunker.push();
+ mover.VxGoal = 45;
+ mover.push();
+ level.enter.draw();
+ pool.query();
+ wastepool.query();
+ thirdpool.query();
+ mover1.VxGoal = 12;
+ mover1.push();
+ mover2.VxGoal = 24;
+ mover2.push();
+ bigpool.query();
+
+ for (i = 0; i < mob.length; i++) { if (mob[i].isBoss == false) { mob[i].damageReduction = 0.13 } }
+ };
+
+ spawn.mapRect(-100, 0, 1000, 100);
+ powerUps.addResearchToLevel() //needs to run after mobs are spawned
+ },
+ ace() { //join us at discord.gg/Q8gY4WeUcm
+ simulation.makeTextLog(`
ace by
Richard0820 `);
+ let isDestroyed = false;
+ const ace = {
+ spawnOrbitals(who, radius, chance = Math.min(0.25 + simulation.difficulty * 0.005)) {
+ if (Math.random() < chance) {
+ // simulation.difficulty = 50
+ const len = Math.floor(Math.min(15, 3 + Math.sqrt(simulation.difficulty))) // simulation.difficulty = 40 on hard mode level 10
+ const speed = (0.003 + 0.004 * Math.random() + 0.002 * Math.sqrt(simulation.difficulty)) * ((Math.random() < 0.5) ? 1 : -1)
+ const offSet = 6.28 * Math.random()
+ for (let i = 0; i < len; i++) ace.orbital(who, radius, i / len * 2 * Math.PI + offSet, speed)
+ }
+ },
+ orbital(who, radius, phase, speed) {
+ // for (let i = 0, len = 7; i < len; i++) spawn.orbital(me, radius + 250, 2 * Math.PI / len * i)
+ mobs.spawn(who.position.x, who.position.y, 8, 12, "rgb(0,0,0)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ Matter.Body.setDensity(me, 0.01); //normal is 0.001
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isUnstable = true; //dies when blocked
+ me.showHealthBar = false;
+ me.isOrbital = true;
+ // me.isShielded = true
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.bullet; //cat.player | cat.map | cat.body
+ me.do = function () {
+ //if host is gone
+ if (!who || !who.alive) {
+ this.death();
+ return
+ }
+ //set orbit
+ const time = simulation.cycle * speed + phase
+ const orbit = {
+ x: Math.cos(time),
+ y: Math.sin(time)
+ }
+ Matter.Body.setPosition(this, Vector.add(Vector.add(who.position, who.velocity), Vector.mult(orbit, radius)))
+ //damage player
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ const dmg = 0.03 * simulation.dmgScale
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: Math.sqrt(dmg) * 200,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ this.death();
+ }
+ };
+ },
+ shield(target, x, y, chance = Math.min(0.02 + simulation.difficulty * 0.005, 0.2) + tech.duplicationChance(), isExtraShield = false) {
+ if (this.allowShields && Math.random() < chance) {
+ mobs.spawn(x, y, 9, target.radius + 30, "rgba(255,255,255,0.9)");
+ let me = mob[mob.length - 1];
+ me.stroke = "rgb(0,0,0)";
+ Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion
+ me.shield = true;
+ me.damageReduction = 0.05 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.isUnblockable = true
+ me.isExtraShield = isExtraShield //this prevents spamming with tech.isShieldAmmo
+ me.collisionFilter.category = cat.mobShield
+ me.collisionFilter.mask = cat.bullet;
+ consBB[consBB.length] = Constraint.create({
+ bodyA: me,
+ bodyB: target, //attach shield to target
+ stiffness: 0.4,
+ damping: 0.1
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+
+ me.onDamage = function () {
+ //make sure the mob that owns the shield can tell when damage is done
+ this.alertNearByMobs();
+ this.fill = `rgba(255,255,255,${0.3 + 0.6 * this.health})`
+ };
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+
+ me.shieldTargetID = target.id
+ target.isShielded = true;
+ target.shieldID = me.id
+ me.onDeath = function () {
+ //clear isShielded status from target
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].id === this.shieldTargetID) mob[i].isShielded = false;
+ }
+ };
+ me.do = function () {
+ this.checkStatus();
+ };
+
+ mob.unshift(me); //move shield to the front of the array, so that mob is behind shield graphically
+
+ //swap order of shield and mob, so that mob is behind shield graphically
+ // mob[mob.length - 1] = mob[mob.length - 2];
+ // mob[mob.length - 2] = me;
+ }
+ },
+ groupShield(targets, x, y, radius, stiffness = 0.4) {
+ const nodes = targets.length
+ mobs.spawn(x, y, 9, radius, "rgba(255,255,255,0.9)");
+ let me = mob[mob.length - 1];
+ me.stroke = "rgb(0,0,0)";
+ Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion
+ me.frictionAir = 0;
+ me.shield = true;
+ me.damageReduction = 0.075 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.collisionFilter.category = cat.mobShield
+ me.collisionFilter.mask = cat.bullet;
+ for (let i = 0; i < nodes; ++i) {
+ mob[mob.length - i - 2].isShielded = true;
+ //constrain to all mob nodes in group
+ consBB[consBB.length] = Constraint.create({
+ bodyA: me,
+ bodyB: mob[mob.length - i - 2],
+ stiffness: stiffness,
+ damping: 0.1
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ me.onDamage = function () {
+ this.alertNearByMobs(); //makes sure the mob that owns the shield can tell when damage is done
+ this.fill = `rgba(255,255,255,${0.3 + 0.6 * this.health})`
+ };
+ me.onDeath = function () {
+ //clear isShielded status from target
+ for (let j = 0; j < targets.length; j++) {
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].id === targets[j]) mob[i].isShielded = false;
+ }
+ }
+ };
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ mob[mob.length - 1] = mob[mob.length - 1 - nodes];
+ mob[mob.length - 1 - nodes] = me;
+ me.do = function () {
+ this.checkStatus();
+ };
+ },
+ slasher2(x, y, radius = 33 + Math.ceil(Math.random() * 30)) {
+ mobs.spawn(x, y, 6, radius, "rgb(0,0,0)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.accelMag = 0.0009 * simulation.accelScale;
+ me.torqueMagnitude = 0.000012 * me.inertia //* (Math.random() > 0.5 ? -1 : 1);
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.035;
+ me.delay = 140 * simulation.CDScale;
+ me.cd = 0;
+ me.swordRadius = 0;
+ me.swordVertex = 1
+ me.swordRadiusMax = 275 + 3.5 * simulation.difficulty;
+ me.swordRadiusGrowRate = me.swordRadiusMax * (0.011 + 0.0002 * simulation.difficulty)
+ me.isSlashing = false;
+ me.swordDamage = 0.03 * simulation.dmgScale
+ me.laserAngle = 3 * Math.PI / 5
+ const seeDistance2 = 200000
+ ace.shield(me, x, y);
+ me.onDamage = function () { };
+ me.do = function () {
+ this.checkStatus();
+ this.seePlayerByHistory(15);
+ this.attraction();
+ this.sword() //does various things depending on what stage of the sword swing
+ };
+ me.swordWaiting = function () {
+ if (
+ this.seePlayer.recall &&
+ this.cd < simulation.cycle &&
+ this.distanceToPlayer2() < seeDistance2 &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ ) {
+ this.laserAngle = -Math.PI / 6
+ this.sword = this.swordGrow
+ this.accelMag = 0
+ }
+ }
+ me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
+ me.swordGrow = function () {
+ this.laserSword(this.vertices[0], this.angle + this.laserAngle);
+ this.laserSword(this.vertices[1], this.angle + this.laserAngle + (Math.PI / 3));
+ this.laserSword(this.vertices[2], this.angle + this.laserAngle + (Math.PI * 2 / 3));
+ this.laserSword(this.vertices[3], this.angle + this.laserAngle + Math.PI);
+ this.laserSword(this.vertices[4], this.angle + this.laserAngle + (Math.PI * 4 / 3));
+ this.laserSword(this.vertices[5], this.angle + this.laserAngle + (Math.PI * 5 / 3));
+ this.swordRadius += this.swordRadiusGrowRate
+ if (this.swordRadius > this.swordRadiusMax || this.isStunned) {
+ this.sword = this.swordSlash
+ this.spinCount = 0
+ }
+ }
+ me.swordSlash = function () {
+ this.laserSword(this.vertices[0], this.angle + this.laserAngle);
+ this.laserSword(this.vertices[1], this.angle + this.laserAngle + (Math.PI / 3));
+ this.laserSword(this.vertices[2], this.angle + this.laserAngle + (Math.PI * 2 / 3));
+ this.laserSword(this.vertices[3], this.angle + this.laserAngle + Math.PI);
+ this.laserSword(this.vertices[4], this.angle + this.laserAngle + (Math.PI * 4 / 3));
+ this.laserSword(this.vertices[5], this.angle + this.laserAngle + (Math.PI * 5 / 3));
+
+ this.torque += this.torqueMagnitude;
+ this.spinCount++
+ if (this.spinCount > 100 || this.isStunned) {
+ this.sword = this.swordWaiting
+ this.swordRadius = 0
+ this.accelMag = 0.001 * simulation.accelScale;
+ this.cd = simulation.cycle + this.delay;
+ }
+ }
+ me.laserSword = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let v = domain[i].vertices;
+ const len = v.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
+ vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(0,0,0,0.1)"; // 0 path
+ ctx.lineWidth = 15;
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(0,0,0,0.5)"; // 0 path
+ ctx.lineWidth = 4;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ },
+ slasher3(x, y, radius = 33 + Math.ceil(Math.random() * 30)) {
+ const sides = 6
+ mobs.spawn(x, y, sides, radius, "rgb(0,0,0)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.accelMag = 0.0005 * simulation.accelScale;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.02;
+ me.delay = 150 * simulation.CDScale;
+ me.cd = 0;
+ me.cycle = 0;
+ me.swordVertex = 1
+ me.swordRadiusInitial = radius / 2;
+ me.swordRadius = me.swordRadiusInitial;
+ me.swordRadiusMax = 750 + 6 * simulation.difficulty;
+ me.swordRadiusGrowRateInitial = 1.08
+ me.swordRadiusGrowRate = me.swordRadiusGrowRateInitial//me.swordRadiusMax * (0.009 + 0.0002 * simulation.difficulty)
+ me.isSlashing = false;
+ me.swordDamage = 0.04 * simulation.dmgScale
+ me.laserAngle = 3 * Math.PI / 5
+ const seeDistance2 = me.swordRadiusMax * me.swordRadiusMax
+ ace.shield(me, x, y);
+ me.onDamage = function () { };
+ me.do = function () {
+ this.checkStatus();
+ this.seePlayerByHistory(15);
+ this.sword() //does various things depending on what stage of the sword swing
+ };
+ me.swordWaiting = function () {
+ this.attraction();
+ if (
+ this.seePlayer.recall &&
+ this.cd < simulation.cycle &&
+ this.distanceToPlayer2() < seeDistance2 &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ ) {
+ //find vertex closest to the player
+ let dist = Infinity
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ const D = Vector.magnitudeSquared(Vector.sub({ x: this.vertices[i].x, y: this.vertices[i].y }, m.pos))
+ if (D < dist) {
+ dist = D
+ this.swordVertex = i
+ }
+ }
+ this.laserAngle = this.swordVertex / sides * 2 * Math.PI + Math.PI / sides
+ this.sword = this.swordGrow
+ this.cycle = 0
+ this.swordRadius = this.swordRadiusInitial
+ //slow velocity but don't stop
+ Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.5))
+ //set angular velocity to 50%
+ // Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.5)
+ //gently rotate towards the player with a torque, use cross product to decided clockwise or counterclockwise
+ const laserStartVector = Vector.sub(this.position, this.vertices[this.swordVertex])
+ const playerVector = Vector.sub(this.position, m.pos)
+ const cross = Matter.Vector.cross(laserStartVector, playerVector)
+ this.torque = 0.00002 * this.inertia * (cross > 0 ? 1 : -1)
+ }
+ }
+ me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
+ me.swordGrow = function () {
+ const angle = this.angle + this.laserAngle;
+ const end = {
+ x: this.vertices[this.swordVertex].x + this.swordRadiusMax * Math.cos(angle),
+ y: this.vertices[this.swordVertex].y + this.swordRadiusMax * Math.sin(angle)
+ };
+
+ const dx = end.x - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].x;
+ const dy = end.y - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].y;
+ const angle1 = Math.atan2(dy, dx) * (180 / Math.PI);
+
+ const dx1 = end.x - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].x;
+ const dy1 = end.y - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].y;
+ const angle2 = Math.atan2(dy1, dx1) * (180 / Math.PI);
+
+ this.laserSpear(this.vertices[this.swordVertex], this.angle + this.laserAngle);
+ this.laserSpear(this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1], angle1 * (Math.PI / 180))
+ this.laserSpear(this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1], angle2 * (Math.PI / 180))
+
+ Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.9))
+ // this.swordRadius += this.swordRadiusGrowRate
+ this.cycle++
+ // this.swordRadius = this.swordRadiusMax * Math.sin(this.cycle * 0.03)
+ this.swordRadius *= this.swordRadiusGrowRate
+
+ if (this.swordRadius > this.swordRadiusMax) this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial
+ // if (this.swordRadius > this.swordRadiusMax) this.swordRadiusGrowRate = -Math.abs(this.swordRadiusGrowRate)
+ if (this.swordRadius < this.swordRadiusInitial || this.isStunned) {
+ // this.swordRadiusGrowRate = Math.abs(this.swordRadiusGrowRate)
+ this.swordRadiusGrowRate = this.swordRadiusGrowRateInitial
+ this.sword = this.swordWaiting
+ this.swordRadius = 0
+ this.cd = simulation.cycle + this.delay;
+ }
+ }
+ me.laserSpear = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let v = domain[i].vertices;
+ const len = v.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
+ vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead)) {
+ this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial //!!!! this retracts the sword if it hits the player
+
+ if (m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(0,0,0,0.1)"; // 0 path
+ ctx.lineWidth = 15;
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(0,0,0,0.5)"; // 0 path
+ ctx.lineWidth = 4;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ },
+ stabber(x, y, radius = 25 + Math.ceil(Math.random() * 12), spikeMax = 7) {
+ if (radius > 80) radius = 65;
+ mobs.spawn(x, y, 6, radius, "rgb(0,0,0)"); //can't have sides above 6 or collision events don't work (probably because of a convex problem)
+ let me = mob[mob.length - 1];
+ me.isVerticesChange = true
+ me.accelMag = 0.0006 * simulation.accelScale;
+ // me.g = 0.0002; //required if using this.gravity
+ me.isInvulnerable = false
+ me.delay = 360 * simulation.CDScale;
+ me.spikeVertex = 0;
+ me.spikeLength = 0;
+ me.isSpikeGrowing = false;
+ me.spikeGrowth = 0;
+ me.isSpikeReset = true;
+ me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.player //can't touch other mobs
+ Matter.Body.rotate(me, Math.PI * 0.1);
+ ace.shield(me, x, y);
+ // me.onDamage = function () {};
+ // me.onHit = function() { //run this function on hitting player
+ // };
+ me.onDeath = function () {
+ if (this.spikeLength > 4) {
+ this.spikeLength = 4
+ const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.spikeVertex], this.position)), this.radius * this.spikeLength)
+ this.vertices[this.spikeVertex].x = this.position.x + spike.x
+ this.vertices[this.spikeVertex].y = this.position.y + spike.y
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
+ }
+ };
+ me.do = function () {
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ this.attraction();
+ if (this.isSpikeReset) {
+ if (this.seePlayer.recall) {
+ const dist = Vector.sub(this.seePlayer.position, this.position);
+ const distMag = Vector.magnitude(dist);
+ if (distMag < radius * spikeMax) {
+ //find nearest vertex
+ let nearestDistance = Infinity
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ //find distance to player for each vertex
+ const dist = Vector.sub(this.seePlayer.position, this.vertices[i]);
+ const distMag = Vector.magnitude(dist);
+ //save the closest distance
+ if (distMag < nearestDistance) {
+ this.spikeVertex = i
+ nearestDistance = distMag
+ }
+ }
+ this.spikeLength = 1
+ this.isSpikeGrowing = true;
+ this.isSpikeReset = false;
+ Matter.Body.setAngularVelocity(this, 0)
+ }
+ me.isInvulnerable = false
+ }
+ } else {
+ if (this.isSpikeGrowing) {
+ this.spikeLength += Math.pow(this.spikeGrowth += 0.02, 8)
+ // if (this.spikeLength < 2) {
+ // this.spikeLength += 0.035
+ // } else {
+ // this.spikeLength += 1
+ // }
+ if (this.spikeLength > spikeMax) {
+ this.isSpikeGrowing = false;
+ this.spikeGrowth = 0
+ }
+ } else {
+ Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.8) //reduce rotation
+ this.spikeLength -= 0.3
+ if (this.spikeLength < 1) {
+ this.spikeLength = 1
+ this.isSpikeReset = true
+ this.radius = radius
+ }
+ }
+ const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.spikeVertex], this.position)), radius * this.spikeLength)
+ this.vertices[this.spikeVertex].x = this.position.x + spike.x
+ this.vertices[this.spikeVertex].y = this.position.y + spike.y
+ me.isInvulnerable = true
+ // this.radius = radius * this.spikeLength;
+ }
+ if (this.isInvulnerable) {
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ me.damageReduction = 0;
+ } else {
+ me.damageReduction = 1;
+ }
+ };
+ },
+ slash(x, y, radius = 80) {
+ let targets = []
+ const sides = 6;
+ mobs.spawn(x, y, 6, radius, "#000000");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ targets.push(me.id) //add to shield protection
+ const nodeBalance = Math.random()
+ const nodes2 = Math.min(15, Math.floor(2 + 4 * nodeBalance + 0.75 * Math.sqrt(simulation.difficulty)))
+ me.isBoss = true;
+ me.isSlashBoss = true;
+ me.showHealthBar = false;
+ me.damageReduction = 0.1 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.startingDamageReduction = me.damageReduction
+ me.isInvulnerable = false
+ me.frictionAir = 0.02
+ me.seeAtDistance2 = 1000000;
+ me.accelMag = 0.0004 + 0.00015 * simulation.accelScale;
+ Matter.Body.setDensity(me, 0.0005); //normal is 0.001
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map
+ me.memory = Infinity;
+ me.seePlayerFreq = 20
+ me.lockedOn = null;
+ me.laserRange = 500;
+ me.torqueMagnitude = 0.00024 * me.inertia * (Math.random() > 0.5 ? -1 : 1);
+ me.delay = 70 + 70 * simulation.CDScale;
+ me.cd = 0;
+ me.swordRadius = 0;
+ me.swordVertex = 1
+ me.swordRadiusMax = 1100 + 20 * simulation.difficulty;
+ me.swordRadiusGrowRate = me.swordRadiusMax * (0.005 + 0.0003 * simulation.difficulty)
+ me.isSlashing = false;
+ me.swordDamage = 0.07 * simulation.dmgScale
+ me.laserAngle = 3 * Math.PI / 5
+ me.eventHorizon = 550;
+ const seeDistance2 = 200000
+ ace.shield(me, x, y);
+ const rangeInnerVsOuter = Math.random()
+ let speed = (0.006 + 0.001 * Math.sqrt(simulation.difficulty)) * ((Math.random() < 0.5) ? 1 : -1)
+ let range = radius + 350 + 200 * rangeInnerVsOuter + nodes2 * 7
+ for (let i = 0; i < nodes2; i++) ace.orbital(me, range, i / nodes2 * 2 * Math.PI, speed)
+ const orbitalIndexes = [] //find indexes for all the current nodes2
+ for (let i = 0; i < nodes2; i++) orbitalIndexes.push(mob.length - 1 - i)
+ // add orbitals for each orbital
+ range = Math.max(60, 100 + 100 * Math.random() - nodes2 * 3 - rangeInnerVsOuter * 80)
+ speed = speed * (1.25 + 2 * Math.random())
+ const subNodes = Math.max(2, Math.floor(6 - 5 * nodeBalance + 0.5 * Math.sqrt(simulation.difficulty)))
+ for (let j = 0; j < nodes2; j++) {
+ for (let i = 0, len = subNodes; i < len; i++) ace.orbital(mob[orbitalIndexes[j]], range, i / len * 2 * Math.PI, speed)
+ }
+ for (let i = 0, len = 3 + 0.5 * Math.sqrt(simulation.difficulty); i < len; i++) ace.spawnOrbitals(me, radius + 40 + 10 * i, 1);
+
+ const springStiffness = 0.00014;
+ const springDampening = 0.0005;
+
+ me.springTarget = {
+ x: me.position.x,
+ y: me.position.y
+ };
+ const len = cons.length;
+ cons[len] = Constraint.create({
+ pointA: me.springTarget,
+ bodyB: me,
+ stiffness: springStiffness,
+ damping: springDampening
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ cons[len].length = 100 + 1.5 * radius;
+ me.cons = cons[len];
+
+ me.springTarget2 = {
+ x: me.position.x,
+ y: me.position.y
+ };
+ const len2 = cons.length;
+ cons[len2] = Constraint.create({
+ pointA: me.springTarget2,
+ bodyB: me,
+ stiffness: springStiffness,
+ damping: springDampening,
+ length: 0
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ cons[len2].length = 100 + 1.5 * radius;
+ me.cons2 = cons[len2];
+ me.onDamage = function () { };
+ me.onDeath = function () {
+ isDestroyed = true;
+ this.removeCons();
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y);
+ };
+ me.do = function () {
+ for (let i = 0; i < this.vertices.length; i++) {
+ this.harmField(this.vertices[i].x, this.vertices[i].y);
+ }
+ this.seePlayerByHistory(40);
+ this.springAttack();
+ this.checkStatus();
+ this.sword() //does various things depending on what stage of the sword swing
+ const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008))
+ me.laserRange = eventHorizon;
+ };
+ me.swordWaiting = function () {
+ if (
+ this.seePlayer.recall &&
+ this.cd < simulation.cycle &&
+ this.distanceToPlayer2() < seeDistance2 &&
+ !m.isCloak &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ ) {
+ //find vertex farthest away from player
+ let dist = 0
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ const D = Vector.magnitudeSquared(Vector.sub({ x: this.vertices[i].x, y: this.vertices[i].y }, m.pos))
+ if (D > dist) {
+ dist = D
+ this.swordVertex = i
+ }
+ }
+ this.laserAngle = this.swordVertex / 6 * 2 * Math.PI + 0.6283
+ this.sword = this.swordGrow
+ Matter.Body.setAngularVelocity(this, 0)
+ this.accelMag = 0.0004 + 0.00015 * simulation.accelScale;
+ this.damageReduction = 0
+ this.isInvulnerable = true
+ this.frictionAir = 1
+ }
+ }
+ me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
+ me.swordGrow = function () {
+ const angle = this.angle + this.laserAngle;
+ const end = {
+ x: this.vertices[this.swordVertex].x + this.swordRadiusMax * Math.cos(angle),
+ y: this.vertices[this.swordVertex].y + this.swordRadiusMax * Math.sin(angle)
+ };
+
+ const dx = end.x - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].x;
+ const dy = end.y - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].y;
+ const angle1 = Math.atan2(dy, dx) * (180 / Math.PI);
+
+ const dx1 = end.x - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].x;
+ const dy1 = end.y - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].y;
+ const angle2 = Math.atan2(dy1, dx1) * (180 / Math.PI);
+
+ this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
+ this.laserSword(this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1], angle1 * (Math.PI / 180))
+ this.laserSword(this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1], angle2 * (Math.PI / 180))
+ this.swordRadius += this.swordRadiusGrowRate
+ if (this.swordRadius > this.swordRadiusMax) {
+ this.sword = this.swordSlash
+ this.spinCount = 0
+ }
+
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ }
+ me.swordSlash = function () {
+ const angle = this.angle + this.laserAngle;
+ const end = {
+ x: this.vertices[this.swordVertex].x + this.swordRadiusMax * Math.cos(angle),
+ y: this.vertices[this.swordVertex].y + this.swordRadiusMax * Math.sin(angle)
+ };
+
+ const dx = end.x - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].x;
+ const dy = end.y - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].y;
+ const angle1 = Math.atan2(dy, dx) * (180 / Math.PI);
+
+ const dx1 = end.x - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].x;
+ const dy1 = end.y - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].y;
+ const angle2 = Math.atan2(dy1, dx1) * (180 / Math.PI);
+
+ this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
+ this.laserSword(this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1], angle1 * (Math.PI / 180))
+ this.laserSword(this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1], angle2 * (Math.PI / 180))
+ this.torque += this.torqueMagnitude;
+ this.spinCount++
+ if (this.spinCount > 80) {
+ this.sword = this.swordWaiting
+ this.swordRadius = 0
+ this.accelMag = 0.0004 + 0.00015 * simulation.accelScale;
+ this.cd = simulation.cycle + this.delay;
+ this.damageReduction = this.startingDamageReduction
+ this.isInvulnerable = false
+ this.frictionAir = 0.01
+ }
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ }
+ me.laserSword = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let v = domain[i].vertices;
+ const len = v.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
+ vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(0,0,0,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(0,0,0,0.1)"; // Black path
+ ctx.lineWidth = 25;
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(0,0,0,0.5)"; // Black path
+ ctx.lineWidth = 5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ me.harmField = function (x, y) {
+ ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
+ // ctx.lineDashOffset = 6*(simulation.cycle % 215);
+ if (this.distanceToPlayer3(x, y) < this.laserRange) {
+ if (m.immuneCycle < m.cycle) {
+ m.damage(0.0003 * simulation.dmgScale);
+ if (m.energy > 0.1) m.energy -= 0.003
+ }
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(m.pos.x, m.pos.y);
+ ctx.lineTo(m.pos.x + (Math.random() - 0.5) * 3000, m.pos.y + (Math.random() - 0.5) * 3000);
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "rgb(0,0,0)";
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.15)";
+ ctx.fill();
+ }
+ ctx.beginPath();
+ ctx.arc(x, y, this.laserRange * 0.9, 0, 2 * Math.PI);
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ ctx.lineWidth = 1;
+ ctx.stroke();
+ ctx.setLineDash([]);
+ ctx.fillStyle = "rgba(0,0,0,0.03)";
+ ctx.fill();
+ }
+ me.distanceToPlayer3 = function (x, y) {
+ const dx = x - player.position.x;
+ const dy = y - player.position.y;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+ radius = 22 // radius of each node mob
+ const sideLength = 100 // distance between each node mob
+ const nodes = 6
+ const angle = 2 * Math.PI / nodes
+
+ spawn.allowShields = false; //don't want shields on individual mobs
+
+ for (let i = 0; i < nodes; ++i) {
+ ace.stabber(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius, 12);
+ Matter.Body.setDensity(mob[mob.length - 1], 0.003); //extra dense //normal is 0.001 //makes effective life much larger
+ mob[mob.length - 1].damageReduction = 0.12
+ mob[mob.length - 1].showHealthBar = false;
+ mob[mob.length - 1].isBoss = true;
+ targets.push(mob[mob.length - 1].id) //track who is in the node boss, for shields
+ }
+
+ const attachmentStiffness = 0.02
+ spawn.constrain2AdjacentMobs(nodes, attachmentStiffness, true); //loop mobs together
+
+ for (let i = 0; i < nodes; ++i) { //attach to center mob
+ consBB[consBB.length] = Constraint.create({
+ bodyA: me,
+ bodyB: mob[mob.length - i - 1],
+ stiffness: attachmentStiffness,
+ damping: 0.03
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ //spawn shield around all nodes
+ ace.groupShield(targets, x, y, sideLength + 1 * radius + nodes * 5 - 25);
+ spawn.allowShields = true;
+ },
+ }
+ level.setPosToSpawn(-625, -100); //normal spawn
+ level.exit.x = -23650;
+ level.exit.y = 11100;
+ simulation.fallHeight = 20000;
+ const door = level.door(350, -200, 25, 225, 225, 10)
+ const door2 = level.door(6325, -200, 25, 225, 225, 10);
+ // spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d8dadf";
+ ace.stabber(425, -100);
+ ace.stabber(725, -100);
+ ace.stabber(1000, -100);
+ ace.stabber(1300, -100);
+ ace.stabber(1550, -100);
+ ace.stabber(1850, -100);
+ ace.stabber(2125, -100);
+ ace.stabber(2400, -100);
+ ace.stabber(2675, -100);
+ ace.stabber(2975, -100);
+ ace.stabber(3225, -100);
+ ace.stabber(3525, -100);
+ ace.stabber(3800, -100);
+ ace.stabber(4100, -100);
+ ace.stabber(4375, -100);
+ ace.stabber(4650, -100);
+ ace.stabber(4925, -100);
+ ace.stabber(5200, -100);
+ ace.stabber(5500, -100);
+ ace.stabber(5775, -100);
+ spawn.mapRect(-200, -450, 2825, 75);
+ spawn.mapRect(-200, 0, 2825, 75);
+ spawn.mapRect(-300, -400, 150, 50);
+ spawn.mapRect(-575, -375, 325, 50);
+ spawn.mapRect(-1175, 0, 700, 75);
+ spawn.mapRect(-1100, 50, 675, 75);
+ spawn.mapRect(-1100, -50, 225, 75);
+ spawn.mapRect(-1025, -75, 200, 50);
+ spawn.mapRect(-875, -50, 150, 75);
+ spawn.mapRect(-700, -350, 325, 50);
+ spawn.mapRect(-950, -100, 150, 50);
+ spawn.mapRect(-675, -50, 125, 25);
+ spawn.mapRect(-575, -150, 25, 125);
+ spawn.mapRect(-650, -50, 25, 75);
+ spawn.mapRect(-600, -50, 25, 75);
+ spawn.mapRect(-800, -325, 250, 50);
+ spawn.mapRect(-1450, 50, 500, 75);
+ spawn.mapRect(-1550, 100, 475, 100);
+ spawn.mapRect(-1650, 175, 525, 375);
+ spawn.mapRect(-1700, 275, 200, 175);
+ spawn.mapRect(-1550, 525, 475, 100);
+ spawn.mapRect(-1475, 600, 4125, 100);
+ spawn.mapRect(-50, 50, 75, 75);
+ level.chain(-450, 75, 0, false, 13)
+ level.chain(7475, 600, -0.5498531827, false, 200)
+ spawn.mapRect(325, -425, 75, 275);
+ spawn.mapRect(-850, -300, 100, 50);
+ spawn.mapRect(-900, -125, 75, 50);
+ spawn.mapRect(-875, -275, 50, 50);
+ spawn.mapRect(425, -400, 125, 100);
+ spawn.mapRect(600, -400, 125, 100);
+ spawn.mapRect(775, -400, 125, 100);
+ spawn.mapRect(950, -400, 125, 100);
+ spawn.mapRect(375, -350, 2250, 25);
+ spawn.mapRect(1125, -400, 125, 100);
+ spawn.mapRect(1300, -400, 125, 100);
+ spawn.mapRect(1475, -400, 125, 100);
+ spawn.mapRect(1650, -400, 125, 100);
+ spawn.mapRect(1825, -400, 125, 100);
+ spawn.mapRect(2000, -400, 125, 100);
+ spawn.mapRect(2175, -400, 125, 100);
+ spawn.mapRect(2350, -400, 125, 100);
+ spawn.mapRect(2525, -400, 125, 100);
+ spawn.mapRect(-1350, 650, 4000, 150);
+ spawn.mapRect(-1400, 675, 125, 75);
+ spawn.mapRect(-1325, 25, 200, 50);
+ spawn.mapRect(2600, 600, 4350, 200);
+ spawn.mapRect(2550, 0, 4400, 75);
+ spawn.mapRect(6875, 0, 875, 75);
+ spawn.mapRect(2500, -450, 5300, 50);
+ spawn.mapRect(7575, -425, 575, 475);
+ spawn.mapRect(6825, 600, 650, 125);
+ spawn.mapRect(6875, 675, 475, 100);
+ spawn.mapRect(7050, -525, 1175, 175);
+ spawn.mapRect(7650, -25, 575, 150);
+ spawn.mapRect(6075, -500, 1125, 75);
+ spawn.mapRect(2550, -350, 3450, 25);
+ spawn.mapRect(2700, -400, 125, 100);
+ spawn.mapRect(2875, -400, 125, 100);
+ spawn.mapRect(3050, -400, 125, 100);
+ spawn.mapRect(3225, -400, 125, 100);
+ spawn.mapRect(3400, -400, 125, 100);
+ spawn.mapRect(3575, -400, 125, 100);
+ spawn.mapRect(3750, -400, 125, 100);
+ spawn.mapRect(3925, -400, 125, 100);
+ spawn.mapRect(4100, -400, 125, 100);
+ spawn.mapRect(4275, -400, 125, 100);
+ spawn.mapRect(4450, -400, 125, 100);
+ spawn.mapRect(4625, -400, 125, 100);
+ spawn.mapRect(4800, -400, 125, 100);
+ spawn.mapRect(4975, -400, 125, 100);
+ spawn.mapRect(5150, -400, 125, 100);
+ spawn.mapRect(5325, -400, 125, 100);
+ spawn.mapRect(5500, -400, 125, 100);
+ spawn.mapRect(5675, -400, 125, 100);
+ spawn.mapRect(5850, -400, 125, 100);
+ spawn.mapRect(6000, -400, 125, 100);
+ spawn.mapRect(6100, -425, 125, 100);
+ spawn.mapRect(6150, -450, 200, 75);
+ spawn.mapRect(2575, -400, 3575, 25);
+ spawn.mapRect(6300, -425, 75, 250);
+ spawn.mapRect(-200, -175, 50, 50);
+ spawn.bodyRect(-950, 475, 150, 125);
+ spawn.bodyRect(-650, 475, 150, 125);
+ spawn.bodyRect(-1000, 350, 550, 125);
+ spawn.bodyRect(-650, 150, 225, 200);
+ spawn.bodyRect(-1050, 150, 400, 200);
+ spawn.bodyRect(-1125, 225, 25, 275);
+ spawn.bodyRect(-1100, 350, 125, 200);
+ spawn.bodyRect(-800, 475, 150, 125);
+ spawn.bodyRect(-500, 475, 125, 125);
+ spawn.mapRect(-3325, -50, 600, 75);
+ spawn.mapRect(-3250, 0, 450, 75);
+ spawn.mapRect(-2950, -100, 350, 75);
+ spawn.mapRect(-2975, -150, 325, 75);
+ spawn.mapRect(-3150, -250, 125, 25);
+ spawn.mapRect(-3050, -225, 100, 25);
+ spawn.mapRect(-3000, -200, 125, 25);
+ spawn.mapRect(-3425, -75, 325, 50);
+ spawn.mapRect(-3250, -225, 125, 25);
+ spawn.mapRect(-3325, -200, 100, 25);
+ spawn.mapRect(-3100, -300, 25, 50);
+ spawn.mapRect(-3725, -325, 1300, 25);
+ spawn.mapRect(-2925, -175, 125, 25);
+ spawn.mapRect(-3375, -175, 100, 25);
+ spawn.mapRect(-3550, -150, 250, 75);
+ spawn.mapRect(-3725, -150, 250, 50);
+ spawn.mapRect(-3725, -200, 125, 75);
+ spawn.mapRect(-3625, -175, 50, 25);
+ spawn.mapRect(-3750, -125, 50, 25);
+ spawn.mapRect(-3750, -50, 125, 50);
+ spawn.mapRect(-3650, -125, 75, 100);
+ spawn.mapRect(-2750, 0, 100, 75);
+ spawn.mapRect(-2675, 25, 175, 25);
+ spawn.mapRect(-2850, 0, 150, 50);
+ spawn.mapRect(-3150, 50, 25, 75);
+ spawn.mapRect(-2900, 50, 25, 75);
+ spawn.mapRect(-3300, 100, 575, 25);
+ spawn.mapRect(-24300, 11125, 51525, 6250);
+ spawn.mapVertex(7900, -675, "0 0 500 -200 500 300 -450 300")
+ spawn.mapRect(-24300, 9575, 475, 1750);
+ spawn.mapRect(26800, 9575, 425, 1750);
+ spawn.hopper(-3100, -150);
+ spawn.mapRect(11625, 8375, 11200, 225);
+ spawn.mapRect(22600, 8375, 225, 3225);
+ spawn.mapRect(11625, 8375, 225, 1800);
+ spawn.mapRect(12425, 9825, 225, 875);
+ spawn.mapRect(13150, 10725, 225, 575);
+ spawn.mapRect(14125, 10450, 5025, 200);
+ spawn.mapRect(21775, 10625, 1050, 225);
+ spawn.mapRect(20325, 10925, 1300, 200);
+ spawn.mapRect(20825, 10250, 750, 225);
+ spawn.mapRect(19500, 10000, 1000, 225);
+
+
+ ace.slasher2(-22725, 10325);
+ ace.slasher3(-23425, 10250);
+ ace.slasher2(-23350, 10700);
+ ace.slasher3(-21725, 11075);
+ ace.slasher2(-21525, 10025);
+ ace.slasher3(-20950, 9750);
+ ace.slasher2(-19975, 9700);
+ ace.slasher3(-18850, 9650);
+ ace.slasher2(-18675, 9700);
+ ace.slasher3(-18250, 9125);
+ ace.slasher2(-17775, 8925);
+ ace.slasher3(-16975, 8875);
+ ace.slasher2(-16475, 9125);
+ ace.slasher3(-16125, 9275);
+ ace.slasher2(-15650, 9225);
+ ace.slasher3(-15200, 9175);
+ ace.slasher2(-16800, 9325);
+ ace.slasher3(-17450, 9525);
+ ace.slasher2(-18375, 9625);
+ ace.slasher3(-19650, 9375);
+ ace.slasher2(-20600, 9225);
+ ace.slasher3(-21625, 9400);
+ ace.slasher2(-22450, 9775);
+ ace.slasher3(-22900, 10000);
+ ace.slasher2(-23275, 9300);
+ ace.slasher3(-23125, 9150);
+ ace.slasher2(2800, 9350);
+ ace.slasher3(4925, 9825);
+ ace.slasher2(3725, 10525);
+ ace.slasher3(1850, 10450);
+ ace.slash(16850, 10075);
+ spawn.mapVertex(-14325, 11000, "0 0 4000 -2000 10000 -3000 16000 -2000 20000 0");
+
+ let q = Matter.Bodies.rectangle(7525 + (1100 / 2), 10675 + (150 / 2), 1100, 150, {
+ density: 0.05,
+ isNotHoldable: false,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let qq = Matter.Bodies.rectangle(7375 + (150 / 2), 10550 + (200 / 2), 150, 200, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let qqq = Matter.Bodies.rectangle(7450 + (1250 / 2), 10500 + (100 / 2), 1250, 100, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let qqqq = Matter.Bodies.rectangle(8625 + (150 / 2), 10550 + (200 / 2), 150, 200, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let qqqqq = Matter.Bodies.rectangle(7600 + (100 / 2), 10350 + (200 / 2), 100, 200, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let qqqqqq = Matter.Bodies.rectangle(8475 + (100 / 2), 10350 + (200 / 2), 100, 200, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let qqqqqqq = Matter.Bodies.rectangle(7650 + (725 / 2), 10325 + (75 / 2), 725, 75, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let qqqqqqqq = Matter.Bodies.rectangle(8000 + 100, 10200 + (150 / 2), 200, 150, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let qqqqqqqqq = Matter.Bodies.rectangle(6975 + (1125 / 2), 10250 + 25, 1125, 50, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let qqqqqqqqqq = Matter.Bodies.rectangle(7600 + 50, 10575 + (125 / 2), 100, 125, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let qqqqqqqqqqq = Matter.Bodies.rectangle(8475 + 50, 10575 + (125 / 2), 100, 125, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+ let qqqqqqqqqqqq = Matter.Bodies.rectangle(8025 + 50, 10575 + (125 / 2), 100, 125, {
+ density: 0.05,
+ isNotHoldable: true,
+ restitution: 1.05,
+ isStatic: false
+ }, true, [true], 0);
+
+
+ wasd = Matter.Body.create({
+ parts: [q, qq, qqq, qqqq, qqqqq, qqqqqq, qqqqqqq, qqqqqqqq, qqqqqqqqq, qqqqqqqqqq, qqqqqqqqqqq, qqqqqqqqqqqq]
+ });
+
+ body[body.length] = q;
+ body[body.length] = qq;
+ body[body.length] = qqq;
+ body[body.length] = qqqq;
+ body[body.length] = qqqqq;
+ body[body.length] = qqqqqq;
+ body[body.length] = qqqqqqq;
+ body[body.length] = qqqqqqqq;
+ body[body.length] = qqqqqqqqq;
+ body[body.length] = qqqqqqqqqq;
+ body[body.length] = qqqqqqqqqqq;
+ body[body.length] = qqqqqqqqqqqq;
+ // body[body.length] = wasd;
+
+ Matter.Composite.add(engine.world, wasd)
+ composite[composite.length] = wasd;
+ // wasd.friction -= 0.5
+ setTimeout(function () {
+ wasd.collisionFilter.category = cat.map;
+ wasd.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mobBullet | cat.mob | cat.map
+ }, 100);
+ let Vx = 0;
+ var gradient = ctx.createLinearGradient(0, 0, 10975 / 2, 0);
+ gradient.addColorStop(0, "#00000000");
+ gradient.addColorStop(1, "#686868");
+ level.custom = () => {
+ wasd.force.y += simulation.g * wasd.mass;
+ if (Matter.Query.collides(wasd, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && input.down && isDestroyed) {
+ wasd.force.x += Math.cos(m.angle) * 75;
+ Matter.Body.setVelocity(player, wasd.velocity)
+ m.Vx = player.velocity.x - wasd.velocity.x;
+ }
+ for (let i = 0; i < mob.length; i++) {
+ if (Matter.Query.collides(wasd, [mob[i]]).length > 0 && !mob[i].isBoss && isDestroyed) {
+ const dmg = 1;
+ mob[i].damage(dmg, true);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: mob[i].position.x,
+ y: mob[i].position.y,
+ radius: Math.sqrt(dmg) * 50,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ break
+ }
+ }
+ Vx = wasd.velocity.x / 5;
+ level.exit.drawAndCheck();
+ drawSeats(475, -50, 5600, 125, 20, "darkgray");
+ door.openClose()
+ door2.openClose()
+ if (player.position.y < 25) {
+ door.isClosing = false;
+ door2.isClosing = false;
+ } else {
+ door.isClosing = true;
+ door2.isClosing = true;
+ }
+ ctx.fillStyle = "red";
+ ctx.fillRect(-825, -75, 50, 50);
+
+ b.pulse(30, 0, { x: -2500, y: (25 + (25 / 2)) });
+ ctx.save()
+ ctx.translate(11750, 8475)
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, 0, 10975, 2800);
+ ctx.restore()
+ drawHead(7400, 0, Math.PI * 0.1);
+ drawHead(7460, 0, Math.PI * 0.5);
+ drawHead(7520, 0, Math.PI * 0.3);
+ drawHead(22400, 11125, Math.PI * 0.3);
+ drawHead(21925, 10625, Math.PI * 0.5);
+ drawHead(21175, 10250, Math.PI * 0.1);
+ drawHead(22525, 10625, Math.PI * 0.7);
+ drawHead(22525, 11125, Math.PI * 0.9);
+ drawHead(22225, 11125, Math.PI * 1.5);
+ };
+ level.customTopLayer = () => {
+ drawSeats(500, -50, 5600, 125);
+
+ ctx.strokeStyle = 'red';
+ ctx.lineWidth = 20;
+ ctx.beginPath();
+ ctx.setLineDash([40, 40]);
+ ctx.lineDashOffset = (-simulation.cycle * Vx) % 80;
+
+ ctx.moveTo(q.vertices[0].x, q.vertices[0].y);
+ for (let i = 1; i < q.vertices.length; i++) {
+ ctx.lineTo(q.vertices[i].x, q.vertices[i].y);
+ }
+ ctx.lineTo(q.vertices[0].x, q.vertices[0].y);
+ ctx.closePath();
+ ctx.stroke();
+ ctx.setLineDash([0, 0]);
+ };
+ function drawSeats(x, y, w, h, num = 20, c = "gray") {
+ const seatWidth = w / num;
+ const seatHeight = h / num;
+
+ for (let i = 0; i < num; i++) {
+ const seatX = x + i * seatWidth;
+ const seatY = y;
+
+ // Draw the seat parts
+ ctx.fillStyle = c;
+ ctx.fillRect(seatX - 100, seatY, 125, 25);
+ ctx.fillRect(seatX, seatY - 125, 25, 150);
+ ctx.fillRect(seatX - 75, seatY, 25, 75);
+ ctx.fillRect(seatX - 25, seatY, 25, 75);
+ }
+ }
+ function drawHead(x, y, angle) {
+ ctx.save();
+ ctx.translate(x, y - 30);
+ ctx.rotate(angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.restore();
+ }
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isSlashBoss) {
+ simulation.ephemera.push({
+ name: "bossBar",
+ do() {
+ if (level.levels[level.onLevel] == "ace" && !isDestroyed) {
+ ctx.save();
+ ctx.setTransform(1, 0, -0.5, 1, 0, 0); //slanted
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(canvas.width2 / 2, canvas.height2 / 10, canvas.width2, 30);
+ ctx.fillStyle = "rgba(0,0,0,0.7)";
+ ctx.fillRect(canvas.width2 / 2, canvas.height2 / 10, canvas.width2 * mob[i].health, 30);
+ ctx.restore();
+ }
+ },
+ })
+ }
+ }
+ },
+ crimsonTowers() {
+ simulation.makeTextLog(`crimsonTowers by Richard0820. Thank you desboot for the video:
Source `)
+ const ace = {
+ spawnOrbitals(who, radius, chance = Math.min(0.25 + simulation.difficulty * 0.005)) {
+ if (Math.random() < chance) {
+ // simulation.difficulty = 50
+ const len = Math.floor(Math.min(15, 3 + Math.sqrt(simulation.difficulty))) // simulation.difficulty = 40 on hard mode level 10
+ const speed = (0.003 + 0.004 * Math.random() + 0.002 * Math.sqrt(simulation.difficulty)) * ((Math.random() < 0.5) ? 1 : -1)
+ const offSet = 6.28 * Math.random()
+ for (let i = 0; i < len; i++) ace.orbital(who, radius, i / len * 2 * Math.PI + offSet, speed)
+ }
+ },
+ orbital(who, radius, phase, speed) {
+ // for (let i = 0, len = 7; i < len; i++) spawn.orbital(me, radius + 250, 2 * Math.PI / len * i)
+ mobs.spawn(who.position.x, who.position.y, 8, 12, "rgb(0,0,0)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ Matter.Body.setDensity(me, 0.01); //normal is 0.001
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isUnstable = true; //dies when blocked
+ me.showHealthBar = false;
+ me.isOrbital = true;
+ // me.isShielded = true
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.bullet; //cat.player | cat.map | cat.body
+ me.do = function () {
+ //if host is gone
+ if (!who || !who.alive) {
+ this.death();
+ return
+ }
+ //set orbit
+ const time = simulation.cycle * speed + phase
+ const orbit = {
+ x: Math.cos(time),
+ y: Math.sin(time)
+ }
+ Matter.Body.setPosition(this, Vector.add(Vector.add(who.position, who.velocity), Vector.mult(orbit, radius)))
+ //damage player
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ const dmg = 0.03 * simulation.dmgScale
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: Math.sqrt(dmg) * 200,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ this.death();
+ }
+ };
+ },
+ shield(target, x, y, chance = Math.min(0.02 + simulation.difficulty * 0.005, 0.2) + tech.duplicationChance(), isExtraShield = false) {
+ if (this.allowShields && Math.random() < chance) {
+ mobs.spawn(x, y, 9, target.radius + 30, "rgba(255,255,255,0.9)");
+ let me = mob[mob.length - 1];
+ me.stroke = "rgb(0,0,0)";
+ Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion
+ me.shield = true;
+ me.damageReduction = 0.05 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.isUnblockable = true
+ me.isExtraShield = isExtraShield //this prevents spamming with tech.isShieldAmmo
+ me.collisionFilter.category = cat.mobShield
+ me.collisionFilter.mask = cat.bullet;
+ consBB[consBB.length] = Constraint.create({
+ bodyA: me,
+ bodyB: target, //attach shield to target
+ stiffness: 0.4,
+ damping: 0.1
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+
+ me.onDamage = function () {
+ //make sure the mob that owns the shield can tell when damage is done
+ this.alertNearByMobs();
+ this.fill = `rgba(255,255,255,${0.3 + 0.6 * this.health})`
+ };
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+
+ me.shieldTargetID = target.id
+ target.isShielded = true;
+ target.shieldID = me.id
+ me.onDeath = function () {
+ //clear isShielded status from target
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].id === this.shieldTargetID) mob[i].isShielded = false;
+ }
+ };
+ me.do = function () {
+ this.checkStatus();
+ };
+
+ mob.unshift(me); //move shield to the front of the array, so that mob is behind shield graphically
+
+ //swap order of shield and mob, so that mob is behind shield graphically
+ // mob[mob.length - 1] = mob[mob.length - 2];
+ // mob[mob.length - 2] = me;
+ }
+ },
+ groupShield(targets, x, y, radius, stiffness = 0.4) {
+ const nodes = targets.length
+ mobs.spawn(x, y, 9, radius, "rgba(255,255,255,0.9)");
+ let me = mob[mob.length - 1];
+ me.stroke = "rgb(0,0,0)";
+ Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion
+ me.frictionAir = 0;
+ me.shield = true;
+ me.damageReduction = 0.075 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.collisionFilter.category = cat.mobShield
+ me.collisionFilter.mask = cat.bullet;
+ for (let i = 0; i < nodes; ++i) {
+ mob[mob.length - i - 2].isShielded = true;
+ //constrain to all mob nodes in group
+ consBB[consBB.length] = Constraint.create({
+ bodyA: me,
+ bodyB: mob[mob.length - i - 2],
+ stiffness: stiffness,
+ damping: 0.1
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ me.onDamage = function () {
+ this.alertNearByMobs(); //makes sure the mob that owns the shield can tell when damage is done
+ this.fill = `rgba(255,255,255,${0.3 + 0.6 * this.health})`
+ };
+ me.onDeath = function () {
+ //clear isShielded status from target
+ for (let j = 0; j < targets.length; j++) {
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].id === targets[j]) mob[i].isShielded = false;
+ }
+ }
+ };
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ mob[mob.length - 1] = mob[mob.length - 1 - nodes];
+ mob[mob.length - 1 - nodes] = me;
+ me.do = function () {
+ this.checkStatus();
+ };
+ },
+ slasher2(x, y, radius = 33 + Math.ceil(Math.random() * 30)) {
+ mobs.spawn(x, y, 6, radius, "rgb(0,0,0)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.accelMag = 0.0009 * simulation.accelScale;
+ me.torqueMagnitude = 0.000012 * me.inertia //* (Math.random() > 0.5 ? -1 : 1);
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.035;
+ me.delay = 140 * simulation.CDScale;
+ me.cd = 0;
+ me.swordRadius = 0;
+ me.swordVertex = 1
+ me.swordRadiusMax = 275 + 3.5 * simulation.difficulty;
+ me.swordRadiusGrowRate = me.swordRadiusMax * (0.011 + 0.0002 * simulation.difficulty)
+ me.isSlashing = false;
+ me.swordDamage = 0.03 * simulation.dmgScale
+ me.laserAngle = 3 * Math.PI / 5
+ const seeDistance2 = 200000
+ ace.shield(me, x, y);
+ me.onDamage = function () { };
+ me.do = function () {
+ this.checkStatus();
+ this.seePlayerByHistory(15);
+ this.attraction();
+ this.sword() //does various things depending on what stage of the sword swing
+ };
+ me.swordWaiting = function () {
+ if (
+ this.seePlayer.recall &&
+ this.cd < simulation.cycle &&
+ this.distanceToPlayer2() < seeDistance2 &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ ) {
+ this.laserAngle = -Math.PI / 6
+ this.sword = this.swordGrow
+ this.accelMag = 0
+ }
+ }
+ me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
+ me.swordGrow = function () {
+ this.laserSword(this.vertices[0], this.angle + this.laserAngle);
+ this.laserSword(this.vertices[1], this.angle + this.laserAngle + (Math.PI / 3));
+ this.laserSword(this.vertices[2], this.angle + this.laserAngle + (Math.PI * 2 / 3));
+ this.laserSword(this.vertices[3], this.angle + this.laserAngle + Math.PI);
+ this.laserSword(this.vertices[4], this.angle + this.laserAngle + (Math.PI * 4 / 3));
+ this.laserSword(this.vertices[5], this.angle + this.laserAngle + (Math.PI * 5 / 3));
+ this.swordRadius += this.swordRadiusGrowRate
+ if (this.swordRadius > this.swordRadiusMax || this.isStunned) {
+ this.sword = this.swordSlash
+ this.spinCount = 0
+ }
+ }
+ me.swordSlash = function () {
+ this.laserSword(this.vertices[0], this.angle + this.laserAngle);
+ this.laserSword(this.vertices[1], this.angle + this.laserAngle + (Math.PI / 3));
+ this.laserSword(this.vertices[2], this.angle + this.laserAngle + (Math.PI * 2 / 3));
+ this.laserSword(this.vertices[3], this.angle + this.laserAngle + Math.PI);
+ this.laserSword(this.vertices[4], this.angle + this.laserAngle + (Math.PI * 4 / 3));
+ this.laserSword(this.vertices[5], this.angle + this.laserAngle + (Math.PI * 5 / 3));
+
+ this.torque += this.torqueMagnitude;
+ this.spinCount++
+ if (this.spinCount > 100 || this.isStunned) {
+ this.sword = this.swordWaiting
+ this.swordRadius = 0
+ this.accelMag = 0.001 * simulation.accelScale;
+ this.cd = simulation.cycle + this.delay;
+ }
+ }
+ me.laserSword = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let v = domain[i].vertices;
+ const len = v.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
+ vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(0,0,0,0.1)"; // 0 path
+ ctx.lineWidth = 15;
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(0,0,0,0.5)"; // 0 path
+ ctx.lineWidth = 4;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ },
+ slasher3(x, y, radius = 33 + Math.ceil(Math.random() * 30)) {
+ const sides = 6
+ mobs.spawn(x, y, sides, radius, "rgb(0,0,0)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.accelMag = 0.0005 * simulation.accelScale;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.02;
+ me.delay = 150 * simulation.CDScale;
+ me.cd = 0;
+ me.cycle = 0;
+ me.swordVertex = 1
+ me.swordRadiusInitial = radius / 2;
+ me.swordRadius = me.swordRadiusInitial;
+ me.swordRadiusMax = 750 + 6 * simulation.difficulty;
+ me.swordRadiusGrowRateInitial = 1.08
+ me.swordRadiusGrowRate = me.swordRadiusGrowRateInitial//me.swordRadiusMax * (0.009 + 0.0002 * simulation.difficulty)
+ me.isSlashing = false;
+ me.swordDamage = 0.04 * simulation.dmgScale
+ me.laserAngle = 3 * Math.PI / 5
+ const seeDistance2 = me.swordRadiusMax * me.swordRadiusMax
+ ace.shield(me, x, y);
+ me.onDamage = function () { };
+ me.do = function () {
+ this.checkStatus();
+ this.seePlayerByHistory(15);
+ this.sword() //does various things depending on what stage of the sword swing
+ };
+ me.swordWaiting = function () {
+ this.attraction();
+ if (
+ this.seePlayer.recall &&
+ this.cd < simulation.cycle &&
+ this.distanceToPlayer2() < seeDistance2 &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ ) {
+ //find vertex closest to the player
+ let dist = Infinity
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ const D = Vector.magnitudeSquared(Vector.sub({ x: this.vertices[i].x, y: this.vertices[i].y }, m.pos))
+ if (D < dist) {
+ dist = D
+ this.swordVertex = i
+ }
+ }
+ this.laserAngle = this.swordVertex / sides * 2 * Math.PI + Math.PI / sides
+ this.sword = this.swordGrow
+ this.cycle = 0
+ this.swordRadius = this.swordRadiusInitial
+ //slow velocity but don't stop
+ Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.5))
+ //set angular velocity to 50%
+ // Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.5)
+ //gently rotate towards the player with a torque, use cross product to decided clockwise or counterclockwise
+ const laserStartVector = Vector.sub(this.position, this.vertices[this.swordVertex])
+ const playerVector = Vector.sub(this.position, m.pos)
+ const cross = Matter.Vector.cross(laserStartVector, playerVector)
+ this.torque = 0.00002 * this.inertia * (cross > 0 ? 1 : -1)
+ }
+ }
+ me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
+ me.swordGrow = function () {
+ const angle = this.angle + this.laserAngle;
+ const end = {
+ x: this.vertices[this.swordVertex].x + this.swordRadiusMax * Math.cos(angle),
+ y: this.vertices[this.swordVertex].y + this.swordRadiusMax * Math.sin(angle)
+ };
+
+ const dx = end.x - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].x;
+ const dy = end.y - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].y;
+ const angle1 = Math.atan2(dy, dx) * (180 / Math.PI);
+
+ const dx1 = end.x - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].x;
+ const dy1 = end.y - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].y;
+ const angle2 = Math.atan2(dy1, dx1) * (180 / Math.PI);
+
+ this.laserSpear(this.vertices[this.swordVertex], this.angle + this.laserAngle);
+ this.laserSpear(this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1], angle1 * (Math.PI / 180))
+ this.laserSpear(this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1], angle2 * (Math.PI / 180))
+
+ Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.9))
+ // this.swordRadius += this.swordRadiusGrowRate
+ this.cycle++
+ // this.swordRadius = this.swordRadiusMax * Math.sin(this.cycle * 0.03)
+ this.swordRadius *= this.swordRadiusGrowRate
+
+ if (this.swordRadius > this.swordRadiusMax) this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial
+ // if (this.swordRadius > this.swordRadiusMax) this.swordRadiusGrowRate = -Math.abs(this.swordRadiusGrowRate)
+ if (this.swordRadius < this.swordRadiusInitial || this.isStunned) {
+ // this.swordRadiusGrowRate = Math.abs(this.swordRadiusGrowRate)
+ this.swordRadiusGrowRate = this.swordRadiusGrowRateInitial
+ this.sword = this.swordWaiting
+ this.swordRadius = 0
+ this.cd = simulation.cycle + this.delay;
+ }
+ }
+ me.laserSpear = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let v = domain[i].vertices;
+ const len = v.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
+ vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead)) {
+ this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial //!!!! this retracts the sword if it hits the player
+
+ if (m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(0,0,0,0.1)"; // 0 path
+ ctx.lineWidth = 15;
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(0,0,0,0.5)"; // 0 path
+ ctx.lineWidth = 4;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ },
+ stabber(x, y, radius = 25 + Math.ceil(Math.random() * 12), spikeMax = 7) {
+ if (radius > 80) radius = 65;
+ mobs.spawn(x, y, 6, radius, "rgb(0,0,0)"); //can't have sides above 6 or collision events don't work (probably because of a convex problem)
+ let me = mob[mob.length - 1];
+ me.isVerticesChange = true
+ me.accelMag = 0.0006 * simulation.accelScale;
+ // me.g = 0.0002; //required if using this.gravity
+ me.isInvulnerable = false
+ me.delay = 360 * simulation.CDScale;
+ me.spikeVertex = 0;
+ me.spikeLength = 0;
+ me.isSpikeGrowing = false;
+ me.spikeGrowth = 0;
+ me.isSpikeReset = true;
+ me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.player //can't touch other mobs
+ Matter.Body.rotate(me, Math.PI * 0.1);
+ ace.shield(me, x, y);
+ // me.onDamage = function () {};
+ // me.onHit = function() { //run this function on hitting player
+ // };
+ me.onDeath = function () {
+ if (this.spikeLength > 4) {
+ this.spikeLength = 4
+ const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.spikeVertex], this.position)), this.radius * this.spikeLength)
+ this.vertices[this.spikeVertex].x = this.position.x + spike.x
+ this.vertices[this.spikeVertex].y = this.position.y + spike.y
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
+ }
+ };
+ me.do = function () {
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ this.attraction();
+ if (this.isSpikeReset) {
+ if (this.seePlayer.recall) {
+ const dist = Vector.sub(this.seePlayer.position, this.position);
+ const distMag = Vector.magnitude(dist);
+ if (distMag < radius * spikeMax) {
+ //find nearest vertex
+ let nearestDistance = Infinity
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ //find distance to player for each vertex
+ const dist = Vector.sub(this.seePlayer.position, this.vertices[i]);
+ const distMag = Vector.magnitude(dist);
+ //save the closest distance
+ if (distMag < nearestDistance) {
+ this.spikeVertex = i
+ nearestDistance = distMag
+ }
+ }
+ this.spikeLength = 1
+ this.isSpikeGrowing = true;
+ this.isSpikeReset = false;
+ Matter.Body.setAngularVelocity(this, 0)
+ }
+ me.isInvulnerable = false
+ }
+ } else {
+ if (this.isSpikeGrowing) {
+ this.spikeLength += Math.pow(this.spikeGrowth += 0.02, 8)
+ // if (this.spikeLength < 2) {
+ // this.spikeLength += 0.035
+ // } else {
+ // this.spikeLength += 1
+ // }
+ if (this.spikeLength > spikeMax) {
+ this.isSpikeGrowing = false;
+ this.spikeGrowth = 0
+ }
+ } else {
+ Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.8) //reduce rotation
+ this.spikeLength -= 0.3
+ if (this.spikeLength < 1) {
+ this.spikeLength = 1
+ this.isSpikeReset = true
+ this.radius = radius
+ }
+ }
+ const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.spikeVertex], this.position)), radius * this.spikeLength)
+ this.vertices[this.spikeVertex].x = this.position.x + spike.x
+ this.vertices[this.spikeVertex].y = this.position.y + spike.y
+ me.isInvulnerable = true
+ // this.radius = radius * this.spikeLength;
+ }
+ if (this.isInvulnerable) {
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ me.damageReduction = 0;
+ } else {
+ me.damageReduction = 1;
+ }
+ };
+ },
+ slash(x, y, radius = 80) {
+ let targets = []
+ const sides = 6;
+ mobs.spawn(x, y, 6, radius, "#000000");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ targets.push(me.id) //add to shield protection
+ const nodeBalance = Math.random()
+ const nodes2 = Math.min(15, Math.floor(2 + 4 * nodeBalance + 0.75 * Math.sqrt(simulation.difficulty)))
+ me.isBoss = true;
+ me.isSlashBoss = true;
+ me.showHealthBar = false;
+ me.damageReduction = 0.1 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.startingDamageReduction = me.damageReduction
+ me.isInvulnerable = false
+ me.frictionAir = 0.02
+ me.seeAtDistance2 = 1000000;
+ me.accelMag = 0.0004 + 0.00015 * simulation.accelScale;
+ Matter.Body.setDensity(me, 0.0005); //normal is 0.001
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map
+ me.memory = Infinity;
+ me.seePlayerFreq = 20
+ me.lockedOn = null;
+ me.laserRange = 500;
+ me.torqueMagnitude = 0.00024 * me.inertia * (Math.random() > 0.5 ? -1 : 1);
+ me.delay = 70 + 70 * simulation.CDScale;
+ me.cd = 0;
+ me.swordRadius = 0;
+ me.swordVertex = 1
+ me.swordRadiusMax = 1100 + 20 * simulation.difficulty;
+ me.swordRadiusGrowRate = me.swordRadiusMax * (0.005 + 0.0003 * simulation.difficulty)
+ me.isSlashing = false;
+ me.swordDamage = 0.07 * simulation.dmgScale
+ me.laserAngle = 3 * Math.PI / 5
+ me.eventHorizon = 550;
+ const seeDistance2 = 200000
+ ace.shield(me, x, y);
+ const rangeInnerVsOuter = Math.random()
+ let speed = (0.006 + 0.001 * Math.sqrt(simulation.difficulty)) * ((Math.random() < 0.5) ? 1 : -1)
+ let range = radius + 350 + 200 * rangeInnerVsOuter + nodes2 * 7
+ for (let i = 0; i < nodes2; i++) ace.orbital(me, range, i / nodes2 * 2 * Math.PI, speed)
+ const orbitalIndexes = [] //find indexes for all the current nodes2
+ for (let i = 0; i < nodes2; i++) orbitalIndexes.push(mob.length - 1 - i)
+ // add orbitals for each orbital
+ range = Math.max(60, 100 + 100 * Math.random() - nodes2 * 3 - rangeInnerVsOuter * 80)
+ speed = speed * (1.25 + 2 * Math.random())
+ const subNodes = Math.max(2, Math.floor(6 - 5 * nodeBalance + 0.5 * Math.sqrt(simulation.difficulty)))
+ for (let j = 0; j < nodes2; j++) {
+ for (let i = 0, len = subNodes; i < len; i++) ace.orbital(mob[orbitalIndexes[j]], range, i / len * 2 * Math.PI, speed)
+ }
+ for (let i = 0, len = 3 + 0.5 * Math.sqrt(simulation.difficulty); i < len; i++) ace.spawnOrbitals(me, radius + 40 + 10 * i, 1);
+
+ const springStiffness = 0.00014;
+ const springDampening = 0.0005;
+
+ me.springTarget = {
+ x: me.position.x,
+ y: me.position.y
+ };
+ const len = cons.length;
+ cons[len] = Constraint.create({
+ pointA: me.springTarget,
+ bodyB: me,
+ stiffness: springStiffness,
+ damping: springDampening
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ cons[len].length = 100 + 1.5 * radius;
+ me.cons = cons[len];
+
+ me.springTarget2 = {
+ x: me.position.x,
+ y: me.position.y
+ };
+ const len2 = cons.length;
+ cons[len2] = Constraint.create({
+ pointA: me.springTarget2,
+ bodyB: me,
+ stiffness: springStiffness,
+ damping: springDampening,
+ length: 0
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ cons[len2].length = 100 + 1.5 * radius;
+ me.cons2 = cons[len2];
+ me.onDamage = function () { };
+ me.onDeath = function () {
+ isDestroyed = true;
+ this.removeCons();
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y);
+ };
+ me.do = function () {
+ for (let i = 0; i < this.vertices.length; i++) {
+ this.harmField(this.vertices[i].x, this.vertices[i].y);
+ }
+ this.seePlayerByHistory(40);
+ this.springAttack();
+ this.checkStatus();
+ this.sword() //does various things depending on what stage of the sword swing
+ const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008))
+ me.laserRange = eventHorizon;
+ };
+ me.swordWaiting = function () {
+ if (
+ this.seePlayer.recall &&
+ this.cd < simulation.cycle &&
+ this.distanceToPlayer2() < seeDistance2 &&
+ !m.isCloak &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ ) {
+ //find vertex farthest away from player
+ let dist = 0
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ const D = Vector.magnitudeSquared(Vector.sub({ x: this.vertices[i].x, y: this.vertices[i].y }, m.pos))
+ if (D > dist) {
+ dist = D
+ this.swordVertex = i
+ }
+ }
+ this.laserAngle = this.swordVertex / 6 * 2 * Math.PI + 0.6283
+ this.sword = this.swordGrow
+ Matter.Body.setAngularVelocity(this, 0)
+ this.accelMag = 0.0004 + 0.00015 * simulation.accelScale;
+ this.damageReduction = 0
+ this.isInvulnerable = true
+ this.frictionAir = 1
+ }
+ }
+ me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
+ me.swordGrow = function () {
+ const angle = this.angle + this.laserAngle;
+ const end = {
+ x: this.vertices[this.swordVertex].x + this.swordRadiusMax * Math.cos(angle),
+ y: this.vertices[this.swordVertex].y + this.swordRadiusMax * Math.sin(angle)
+ };
+
+ const dx = end.x - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].x;
+ const dy = end.y - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].y;
+ const angle1 = Math.atan2(dy, dx) * (180 / Math.PI);
+
+ const dx1 = end.x - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].x;
+ const dy1 = end.y - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].y;
+ const angle2 = Math.atan2(dy1, dx1) * (180 / Math.PI);
+
+ this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
+ this.laserSword(this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1], angle1 * (Math.PI / 180))
+ this.laserSword(this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1], angle2 * (Math.PI / 180))
+ this.swordRadius += this.swordRadiusGrowRate
+ if (this.swordRadius > this.swordRadiusMax) {
+ this.sword = this.swordSlash
+ this.spinCount = 0
+ }
+
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ }
+ me.swordSlash = function () {
+ const angle = this.angle + this.laserAngle;
+ const end = {
+ x: this.vertices[this.swordVertex].x + this.swordRadiusMax * Math.cos(angle),
+ y: this.vertices[this.swordVertex].y + this.swordRadiusMax * Math.sin(angle)
+ };
+
+ const dx = end.x - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].x;
+ const dy = end.y - this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1].y;
+ const angle1 = Math.atan2(dy, dx) * (180 / Math.PI);
+
+ const dx1 = end.x - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].x;
+ const dy1 = end.y - this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1].y;
+ const angle2 = Math.atan2(dy1, dx1) * (180 / Math.PI);
+
+ this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
+ this.laserSword(this.vertices[this.swordVertex + 1 > (sides - 1) ? 0 : this.swordVertex + 1], angle1 * (Math.PI / 180))
+ this.laserSword(this.vertices[this.swordVertex - 1 < 0 ? (sides - 1) : this.swordVertex - 1], angle2 * (Math.PI / 180))
+ this.torque += this.torqueMagnitude;
+ this.spinCount++
+ if (this.spinCount > 80) {
+ this.sword = this.swordWaiting
+ this.swordRadius = 0
+ this.accelMag = 0.0004 + 0.00015 * simulation.accelScale;
+ this.cd = simulation.cycle + this.delay;
+ this.damageReduction = this.startingDamageReduction
+ this.isInvulnerable = false
+ this.frictionAir = 0.01
+ }
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ }
+ me.laserSword = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let v = domain[i].vertices;
+ const len = v.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
+ vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(0,0,0,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(0,0,0,0.1)"; // Black path
+ ctx.lineWidth = 25;
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(0,0,0,0.5)"; // Black path
+ ctx.lineWidth = 5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ me.harmField = function (x, y) {
+ ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
+ // ctx.lineDashOffset = 6*(simulation.cycle % 215);
+ if (this.distanceToPlayer3(x, y) < this.laserRange) {
+ if (m.immuneCycle < m.cycle) {
+ m.damage(0.0003 * simulation.dmgScale);
+ if (m.energy > 0.1) m.energy -= 0.003
+ }
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(m.pos.x, m.pos.y);
+ ctx.lineTo(m.pos.x + (Math.random() - 0.5) * 3000, m.pos.y + (Math.random() - 0.5) * 3000);
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "rgb(0,0,0)";
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.15)";
+ ctx.fill();
+ }
+ ctx.beginPath();
+ ctx.arc(x, y, this.laserRange * 0.9, 0, 2 * Math.PI);
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ ctx.lineWidth = 1;
+ ctx.stroke();
+ ctx.setLineDash([]);
+ ctx.fillStyle = "rgba(0,0,0,0.03)";
+ ctx.fill();
+ }
+ me.distanceToPlayer3 = function (x, y) {
+ const dx = x - player.position.x;
+ const dy = y - player.position.y;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+ radius = 22 // radius of each node mob
+ const sideLength = 100 // distance between each node mob
+ const nodes = 6
+ const angle = 2 * Math.PI / nodes
+
+ spawn.allowShields = false; //don't want shields on individual mobs
+
+ for (let i = 0; i < nodes; ++i) {
+ ace.stabber(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius, 12);
+ Matter.Body.setDensity(mob[mob.length - 1], 0.003); //extra dense //normal is 0.001 //makes effective life much larger
+ mob[mob.length - 1].damageReduction = 0.12
+ mob[mob.length - 1].showHealthBar = false;
+ mob[mob.length - 1].isBoss = true;
+ targets.push(mob[mob.length - 1].id) //track who is in the node boss, for shields
+ }
+
+ const attachmentStiffness = 0.02
+ spawn.constrain2AdjacentMobs(nodes, attachmentStiffness, true); //loop mobs together
+
+ for (let i = 0; i < nodes; ++i) { //attach to center mob
+ consBB[consBB.length] = Constraint.create({
+ bodyA: me,
+ bodyB: mob[mob.length - i - 1],
+ stiffness: attachmentStiffness,
+ damping: 0.03
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ //spawn shield around all nodes
+ ace.groupShield(targets, x, y, sideLength + 1 * radius + nodes * 5 - 25);
+ spawn.allowShields = true;
+ },
+ }
+ level.setPosToSpawn(0, -50);
+ color.map = "crimson";
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
+ spawn.mapRect(0, 0, 1, 1);
+ level.defaultZoom = 1800;
+ simulation.zoomTransition(level.defaultZoom);
+ document.body.style.backgroundColor = "#d8dadf";
+ const isSus = Math.random() < 0.001; //A very lucky person gets rickrolled
+ const mediaSource = isSus ? "https://ia801509.us.archive.org/10/items/Rick_Astley_Never_Gonna_Give_You_Up/Rick_Astley_Never_Gonna_Give_You_Up.ogv" : "https://cdn.glitch.me/b559a783-c0cb-4369-92e3-0c0a5556ba01/n-gon%20evangelion%20-%20Made%20with%20Clipchamp%20(8).mp4?v=1692134040246"
+ let videoContainer;
+ let video = document.createElement("video");
+ video.src = mediaSource;
+ video.autoPlay = true;
+ video.loop = true;
+ video.muted = true;
+ videoContainer = {
+ video: video,
+ ready: true,
+ };
+ video.play();
+ const boost1 = level.boost(8835, -3675, 7500);
+ const boost2 = level.boost(-8935, -3675, 7500);
+ ace.slash(0, -15000 + 1800);
+ function Raindrop(minX, minY, maxX, maxY) {
+ this.x = minX + Math.random() * (maxX - minX);
+ this.y = minY + Math.random() * (maxY - minY);
+ this.speed = Math.random() * 5 + 25;
+ this.length = Math.random() * 20 + 30;
+ }
+ function forceField(x, y, width, height) {
+ return {
+ min: { x: x, y: y },
+ max: { x: x + width, y: y + height },
+ width: width,
+ height: height,
+ maxHeight: height,
+ raindrops: [],
+ drawRaindrop(drop) {
+ if (Math.sqrt(Math.pow(player.position.x - drop.x, 2) + Math.pow(player.position.y - drop.y, 2)) + Math.PI < 5000) {
+ ctx.beginPath();
+ ctx.moveTo(drop.x, drop.y);
+ ctx.lineTo(drop.x, drop.y + drop.length);
+ ctx.strokeStyle = '#00FFFF';
+ ctx.lineWidth = 10;
+ ctx.lineCap = 'butt';
+ ctx.stroke();
+ }
+ },
+ updateRaindrop(drop) {
+ drop.y += drop.speed;
+ if ((Matter.Query.ray(map, { x: drop.x, y: drop.y }, { x: drop.x, y: drop.y - drop.length }).length === 0) == false) {
+ simulation.drawList.push({
+ x: drop.x,
+ y: drop.y - drop.length,
+ radius: 10,
+ color: "rgb(0,100,250,0.3)",
+ time: 8
+ });
+ do {
+ drop.y = this.min.y + this.height * Math.random();
+ drop.x = this.min.x + this.width * Math.random();
+ } while (drop.x > this.min.x && drop.x < this.max.x && drop.y > this.min.y && drop.y < this.max.y)
+ }
+ },
+ isOn: true,
+ query() {
+ if (this.isOn) {
+ ctx.fillStyle = `rgba(200, 20, 10, 0.55)`
+ ctx.fillRect(this.min.x, this.min.y, this.width, this.height)
+ if (this.height > 0 && Matter.Query.region([player], this).length) {
+ player.force.y -= 0.015;
+ m.energy = m.maxEnergy;
+ }
+ // if(this.raindrops.length < 300) { // too many (like 900) can cause a little bit of lag minus 5 ~ 10 fps, but it really just depends on your computer
+ // this.raindrops.push(new Raindrop());
+ // }
+ // for (let i = 0; i < this.raindrops.length; i++) {
+ // const drop = this.raindrops[i];
+ // this.drawRaindrop(drop);
+ // this.updateRaindrop(drop);
+ // }
+ }
+ },
+ }
+ }
+ const forceField1 = forceField(-750, -30000, 1500, 20000);
+ level.custom = () => {
+ if (player.position.y < -20000) {
+ level.nextLevel();
+ }
+ forceField1.query();
+ boost1.query();
+ boost2.query();
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ ctx.beginPath();
+ ctx.strokeStyle = "rgba(220, 20, 10, 0.55)";
+ ctx.lineWidth = 1500;
+ ctx.lineJoin = "miter"
+ ctx.miterLimit = 100;
+ ctx.moveTo(map[272].vertices[0].x, map[272].vertices[0].y);
+ for (let i = 0; i < map[272].vertices.length; i++) {
+ ctx.lineTo(map[272].vertices[i].x, map[272].vertices[i].y);
+ }
+ ctx.closePath();
+ ctx.stroke();
+ };
+ let checkVid = () => {
+ if (simulation.paused && !videoContainer.paused) {
+ videoContainer.paused = true;
+ video.pause();
+ } else if (!simulation.paused && videoContainer.paused) {
+ videoContainer.paused = false;
+ video.play();
+ }
+ requestAnimationFrame(checkVid);
+ }
+ checkVid();
+ simulation.ephemera.push({
+ name: "vid",
+ do() {
+ if (level.levels[level.onLevel] !== "crimsonTowers") simulation.removeEphemera(this.name);
+ if (mediaSource && !isSus) {
+ ctx.drawImage(videoContainer.video, -1600, -15000, 3200, 1800);
+ } else if (mediaSource) {
+ ctx.drawImage(videoContainer.video, -1920 / 2, -15000, 1920, 1080);
+ }
+ }
+ });
+ level.customTopLayer = () => {
+ ctx.fillStyle = "rgba(220, 20, 10, 0.1)";
+ ctx.fillRect(-6725, -3500, 475, 2925);
+ ctx.fillRect(-8725, -3700, 450, 2925);
+ ctx.fillRect(-4725, -3300, 450, 2925);
+ ctx.fillRect(-2725, -3100, 450, 2925);
+ ctx.fillRect(-725, -2900, 450, 2925);
+ ctx.fillRect(275, -2900, 450, 2925);
+ ctx.fillRect(2275, -3100, 450, 2925);
+ ctx.fillRect(4275, -3300, 450, 2925);
+ ctx.fillRect(6275, -3500, 450, 2925);
+ ctx.fillRect(8275, -3700, 450, 2925);
+ };
+ spawn.mapRect(-10000, 0, 20000, 2000);
+ spawn.mapRect(-9050, -3650, 350, 50);
+ spawn.mapRect(8700, -3650, 350, 50);
+ spawn.mapRect(-275, -2825, 550, 50);
+ spawn.mapRect(-225, -500, 450, 50);
+ spawn.mapRect(-250, -1575, 500, 50);
+ function spawnTower(index, y = 0) {
+ const x = index - 1325;
+ spawn.mapRect(x + 1025, y + -950, 125, 750);
+ spawn.mapRect(x + 1125, y + -225, 50, 50);
+ spawn.mapRect(x + 1500, y + -950, 125, 750);
+ spawn.mapRect(x + 1475, y + -225, 50, 50);
+ spawn.mapRect(x + 1600, y + -225, 50, 50);
+ spawn.mapRect(x + 1000, y + -225, 50, 50);
+ spawn.mapRect(x + 1475, y + -475, 50, 50);
+ spawn.mapRect(x + 1125, y + -750, 50, 50);
+ spawn.mapRect(x + 1050, y + -2025, 100, 1125);
+ spawn.mapRect(x + 1500, y + -2025, 100, 1125);
+ spawn.mapRect(x + 1475, y + -1050, 50, 50);
+ spawn.mapRect(x + 1125, y + -1325, 50, 50);
+ spawn.mapRect(x + 1475, y + -1550, 50, 50);
+ spawn.mapRect(x + 1125, y + -1875, 50, 50);
+ spawn.mapRect(x + 1075, y + -2900, 75, 925);
+ spawn.mapRect(x + 1500, y + -2900, 75, 925);
+ spawn.mapRect(x + 1475, y + -2150, 50, 50);
+ spawn.mapRect(x + 1125, y + -2475, 50, 50);
+ spawn.mapRect(x + 1475, y + -2800, 50, 50);
+ spawn.mapRect(x + 1000, y + -975, 50, 50);
+ spawn.mapRect(x + 1025, y + -2050, 50, 50);
+ spawn.mapRect(x + 1050, y + -2925, 50, 50);
+ spawn.mapRect(x + 1550, y + -2925, 50, 50);
+ spawn.mapRect(x + 1600, y + -975, 50, 50);
+ spawn.mapRect(x + 1575, y + -2050, 50, 50);
+ for (let i = 0; i < 5; i++) {
+ if (Math.random() > 0.5) { ace.slasher2(index, y - (i * 500) - 500) } else { ace.slasher3(index, y - (i * 500) - 500) };
+ }
+ }
+ // ace.slash(0, -5000);
+ function spawnChain(x, y, x1, y1, length = 39) {
+ const angle = Math.atan2(y1 - y, x1 - x);
+ chain(x, y, angle, true, length);
+ }
+ function chain(x, y, angle = 0, isAttached = true, len = 15, radius = 20, stiffness = 1, damping = 1) {
+ const gap = 2 * radius
+ const unit = {
+ x: Math.cos(angle),
+ y: Math.sin(angle)
+ }
+ for (let i = 0; i < len; i++) {
+ bullet[bullet.length] = Bodies.polygon(x + gap * unit.x * i, y + gap * unit.y * i, 12, radius, {
+ inertia: Infinity,
+ isNotHoldable: true
+ });
+ const who = bullet[bullet.length - 1];
+ who.do = () => { };
+ who.collisionFilter.category = cat.body;
+ who.collisionFilter.mask = cat.player | cat.bullet | cat.body | cat.bullet | cat.bullet | cat.bulletBullet
+ Composite.add(engine.world, who); //add to world
+ who.classType = "bullet"
+ }
+ for (let i = 1; i < len; i++) {
+ consBB[consBB.length] = Constraint.create({
+ bodyA: bullet[bullet.length - i],
+ bodyB: bullet[bullet.length - i - 1],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: x,
+ y: y
+ },
+ bodyB: bullet[bullet.length - len],
+ stiffness: 1,
+ damping: damping
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ if (isAttached) {
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: x + gap * unit.x * (len - 1),
+ y: y + gap * unit.y * (len - 1)
+ },
+ bodyB: bullet[bullet.length - 1],
+ stiffness: 1,
+ damping: damping
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ }
+ }
+ spawnChain(-2250, -3100, -750, -2900);
+ spawnChain(-4250, -3300, -2750, -3100);
+ spawnChain(-6250, -3500, -4750, -3300);
+ spawnChain(-8250, -3700, -6750, -3500);
+ spawnChain(750, -2900, 2250, -3100);
+ spawnChain(2750, -3100, 4250, -3300);
+ spawnChain(4750, -3300, 6250, -3500);
+ spawnChain(6750, -3500, 8250, -3700);
+ // spawnChain(-3000, -30000, -9500, -20400, 291);
+ // spawnChain(3000, -30000, 9500, -20400, 291);
+ spawnTower(500);
+ spawnTower(2500, -200);
+ spawn.mapRect(2000, -200, 7000, 300);
+ spawnTower(4500, -400);
+ spawn.mapRect(4000, -400, 5000, 300);
+ spawnTower(6500, -600);
+ spawn.mapRect(6000, -600, 5000, 300);
+ spawnTower(8500, -800);
+ spawn.mapRect(8000, -800, 3000, 300);
+ spawnTower(-500);
+ spawnTower(-2500, -200);
+ spawn.mapRect(-10000, -200, 8000, 300);
+ spawnTower(-4500, -400);
+ spawn.mapRect(-10000, -400, 6000, 300);
+ spawnTower(-6500, -600);
+ spawn.mapRect(-10000, -600, 4000, 300);
+ spawnTower(-8500, -800);
+ spawn.mapRect(-10000, -800, 2000, 300);
+ spawn.mapVertex(10000, -9450, "-1000 0 1000 0 1000 -10000 500 -20000 -500 -20000 -1000 -10000");
+ spawn.mapVertex(-10000, -9450, "-1000 0 1000 0 1000 -10000 500 -20000 -500 -20000 -1000 -10000");
+ spawn.mapRect(-11000, -675, 2000, 2675);
+ spawn.mapRect(9000, -675, 2000, 2675);
+ spawn.mapVertex(0, -30000, "0 0 3000 -10000 6000 0 3000 10000");
+ spawn.mapRect(-8750, -10000, 8000, 100);
+ spawn.mapRect(750, -10000, 8000, 100);
+ spawn.mapVertex(0, -10020, "-1000 0 -5000 300 5000 300 1000 0");
+ spawn.mapRect(-800, -10250, 100, 350);
+ spawn.mapRect(700, -10250, 100, 350);
+ const a = 200;
+ const maxTheta = 10 * Math.PI;
+ const spiralX = (theta) => a * theta * Math.cos(theta);
+ const spiralY = (theta) => a * theta * Math.sin(theta);
+ for (let i = 1; i <= maxTheta; i += 0.2) {
+ const x = spiralX(i);
+ const y = spiralY(i) + (-15000 + 1800 / 2);
+ spawn.mapRect(x, y, 100, 100);
+ }
+ level.exit.y = map[272].position.y;
+ level.exit.x = map[272].position.x;
+ },
+ // ********************************************************************************************************
+ // ********************************************************************************************************
+ // ***************************************** training levels **********************************************
+ // ********************************************************************************************************
+ // ********************************************************************************************************
+ walk() { //learn to walk
+ if (localSettings.isHideHUD) localSettings.isHideHUD = false
+ m.addHealth(Infinity)
+ document.getElementById("health").style.display = "none" //hide your health bar
+ document.getElementById("health-bg").style.display = "none"
+ document.getElementById("defense-bar").style.display = "none"
+ document.getElementById("damage-bar").style.display = "none"
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+
+ simulation.lastLogTime = 0; //clear previous messages
+ let instruction = 0
+ level.trainingText(`move
↔ with
${input.key.left.replace('Key', '').replace('Digit', '')} and
${input.key.right.replace('Key', '').replace('Digit', '')} `)
+
+ level.custom = () => {
+ if (instruction === 0 && input.right) {
+ instruction++
+ level.trainingText(`
move ↔ with ${input.key.left.replace('Key', '').replace('Digit', '')} and ${input.key.right.replace('Key', '').replace('Digit', '')}
+
exit through the blue door`)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ };
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 0, 3500, 1800); //floor
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+ spawn.mapRect(700, -8, 50, 25);
+ spawn.mapRect(725, -16, 75, 25);
+ spawn.mapRect(1375, -16, 50, 50);
+ spawn.mapRect(1400, -8, 50, 25);
+ spawn.mapRect(750, -24, 650, 100);
+ spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
+ crouch() { //learn to crouch
+ if (localSettings.isTrainingNotAttempted) { //after making it to the second training level
+ localSettings.isTrainingNotAttempted = false // this makes the training button less obvious at the start screen
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ }
+
+ m.addHealth(Infinity)
+ level.setPosToSpawn(75, -100); //normal spawn
+ spawn.mapRect(25, -60, 100, 20); //small platform for player
+ spawn.mapRect(0, -50, 150, 25); //stairs
+ spawn.mapRect(-25, -40, 200, 25);
+ spawn.mapRect(-50, -30, 250, 25);
+ spawn.mapRect(-75, -20, 300, 25);
+ spawn.mapRect(-100, -10, 350, 25);
+ spawn.mapRect(-150, -50, 175, 75);
+
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+
+ let instruction = 0
+ level.trainingText(`press
${input.key.down.replace('Key', '').replace('Digit', '')} to crouch`)
+ level.custom = () => {
+ if (instruction === 0 && input.down) {
+ instruction++
+ level.trainingText(`
press ${input.key.down.replace('Key', '').replace('Digit', '')} to crouch `)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1625, -350, 375, 350)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1625, -350, 375, 350)
+ //dark
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+ ctx.fillRect(500, -100, 1125, 175);
+ };
+
+ // spawn.mapRect(1025, -675, 300, 623); //crouch wall
+ // spawn.mapRect(625, -650, 1025, 550);
+ spawn.mapRect(500, -650, 1125, 550);
+ spawn.mapRect(-200, -650, 875, 300);
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ },
+ jump() { //learn to jump
+ m.addHealth(Infinity)
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+
+ let instruction = 0
+ level.trainingText(`hold down
${input.key.up.replace('Key', '').replace('Digit', '')} longer to jump higher`)
+
+ level.custom = () => {
+ if (instruction === 0 && m.pos.x > 300) {
+ instruction++
+ level.trainingText(`
hold down ${input.key.up.replace('Key', '').replace('Digit', '')} longer to jump higher `)
+ }
+ m.health = 1 //can't die
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ //dark
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+ ctx.fillRect(1000, 0, 450, 1800)
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(275, -350, 200, 375);
+ spawn.mapRect(-250, 0, 1250, 1800); //floor
+ spawn.mapRect(1450, 0, 1075, 1800); //floor
+ spawn.mapRect(-250, -2800, 1250, 2200); //roof
+ spawn.mapRect(1450, -2800, 1075, 2200); //roof
+ spawn.mapVertex(375, 0, "150 0 -150 0 -100 -50 100 -50"); //base
+
+ spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+
+ //roof steps
+ spawn.mapRect(1000, -650, 25, 25);
+ spawn.mapRect(1000, -675, 50, 25);
+ spawn.mapRect(1000, -700, 75, 25);
+ spawn.mapRect(1000, -725, 100, 25);
+ spawn.mapRect(1425, -650, 25, 25);
+ spawn.mapRect(1400, -675, 50, 25);
+ spawn.mapRect(1375, -700, 75, 25);
+ spawn.mapRect(1350, -725, 100, 25);
+ spawn.mapRect(1325, -750, 150, 25);
+ spawn.mapRect(1300, -775, 150, 25);
+ spawn.mapRect(1000, -750, 125, 25);
+ spawn.mapRect(1275, -2800, 200, 2025);
+ spawn.mapRect(975, -2800, 200, 2025);
+ spawn.mapRect(1000, -775, 150, 25);
+ },
+ hold() { //put block on button to open door
+ m.addHealth(Infinity)
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+
+ spawn.bodyRect(1025, -75, 50, 50); //block to go on button
+ const buttonDoor = level.button(500, 0)
+ const door = level.door(1612.5, -175, 25, 190, 185, 3)
+
+ let instruction = 0
+ level.trainingText(`activate your
field with
${input.key.field.replace('Key', '').replace('Digit', '')} or
right mouse `)
+
+ level.custom = () => {
+ if (instruction === 0 && input.field) {
+ instruction++
+ level.trainingText(`
activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse release your
field on a
block to pick it up`)
+ } else if (instruction === 1 && m.isHolding) {
+ instruction++
+ level.trainingText(`
activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse release your field on a block to pick it up drop the
block on the red button to open the door`)
+ } else if (instruction === 2 && !buttonDoor.isUp && Vector.magnitudeSquared(Vector.sub(body[0].position, buttonDoor.min)) < 10000) {
+ instruction++
+ level.trainingText(`
activate your field with ${input.key.field.replace('Key', '').replace('Digit', '')} or right mouse release your field on a block to pick it up drop the block on the red button to open the door `)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ buttonDoor.query();
+ buttonDoor.draw();
+ if (buttonDoor.isUp) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ door.draw();
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
+ throw() { //throw a block on button to open door
+ m.addHealth(Infinity)
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+
+ spawn.bodyRect(1025, -75, 50, 50); //block to go on button
+ const buttonDoor = level.button(1635, -400)
+ const door = level.door(1612.5, -175, 25, 190, 185, 3)
+
+ // activate your
field with
${input.key.field.replace('Key', '').replace('Digit', '')} or
right mouse
+ let instruction = 0
+ level.trainingText(`pick up the
block with your
field `)
+
+ level.custom = () => {
+ if (instruction === 0 && m.isHolding) {
+ instruction++
+ level.trainingText(`
pick up the block with your field
+
hold your
field down to charge up then release to throw a
block `)
+ } else if (instruction === 1 && m.throwCharge > 2) {
+ instruction++
+ level.trainingText(`
pick up the block with your field
+ hold your field down to charge up then release to throw a block
+
throw the
block onto the button`)
+ // the
block at the button
+ } else if (instruction === 2 && !buttonDoor.isUp && Vector.magnitudeSquared(Vector.sub(body[0].position, buttonDoor.min)) < 10000) {
+ instruction++
+ level.trainingText(`
pick up the block with your field
+ hold your field down to charge up then release to throw a block
+ throw the block onto the button `)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ buttonDoor.query();
+ buttonDoor.draw();
+ if (buttonDoor.isUp) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ door.draw();
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ // spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1790, -600, 250, 225); //button left wall
+ spawn.mapRect(1625, -400, 400, 50);
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
+ throwAt() { //throw a block at mob to open door
+ m.addHealth(Infinity)
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+
+ const door = level.door(1612.5, -175, 25, 190, 185, 3)
+
+ let instruction = 0
+ level.trainingText(`throw the
block at the
mobs to open the door`)
+
+ level.custom = () => {
+ if (instruction === 0 && !mob.length) {
+ instruction++
+ level.trainingText(`
throw the block at the mobs to open the door `)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ if (mob.length > 0) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ door.draw();
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ // spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ // spawn.mapRect(1790, -600, 250, 225); //button left wall
+ // spawn.mapRect(1625, -400, 400, 50);
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ spawn.mapRect(1600, -600, 425, 250);
+
+ spawn.bodyRect(1025, -75, 50, 50); //block to go on button
+ spawn.starter(425, -350, 35)
+ spawn.starter(800, -350, 44)
+ },
+ fire() { //throw a block at mob to open door
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = 15;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+
+ const door = level.door(1612.5, -125, 25, 190, 185, 3)
+ const buttonDoor = level.button(400, 0)
+
+ let instruction = 0
+ level.trainingText(`use your
field to pick up the gun power up`)
+
+ level.custom = () => {
+ if (instruction === 0 && simulation.isChoosing) {
+ instruction++
+ level.trainingText(`
use your field to pick up the gun power up
+
choose a
gun `)
+ } else if (instruction === 1 && !simulation.isChoosing) {
+ instruction++
+ level.trainingText(`
use your field to pick up the gun power up
+ choose a gun
+
use the
left mouse button to shoot the
mobs `)
+ } else if (instruction === 2 && mob.length === 0) {
+ instruction++
+ level.trainingText(`
use your field to pick up the gun power up
+ choose a gun
+ use the left mouse button to shoot the mobs
+
drop a
block on the red button to open the door`)
+ } else if (instruction === 3 && !door.isClosing) {
+ instruction++
+ level.trainingText(`
use your field to pick up the gun power up
+ choose a gun
+ use the left mouse button to shoot the mobs
+ put a block on the red button to open the door `)
+ }
+ if (!powerUp.length) {
+ //spawn ammo if you run out
+ if (b.inventory.length && b.guns[b.activeGun].ammo === 0) powerUps.directSpawn(1300, -2000, "ammo", false);
+ //spawn a gun power up if don't have one or a gun
+ if (!b.inventory.length && !simulation.isChoosing) powerUps.directSpawn(1300, -2000, "gun", false);
+
+ }
+
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -350, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ buttonDoor.query();
+ buttonDoor.draw();
+ if (buttonDoor.isUp) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ door.draw();
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -350, 400, 400)
+ //ammo tunnel shadow
+ ctx.fillStyle = "rgba(0,0,0,0.4)"
+ ctx.fillRect(1250, -2800, 100, 2200)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(-150, -2800, 1400, 2200); //roof with tunnel for ammo
+ spawn.mapRect(1350, -2800, 675, 2200);
+
+ //ceiling steps
+ spawn.mapRect(725, -588, 50, 25);
+ spawn.mapRect(725, -600, 75, 25);
+ spawn.mapRect(750, -612, 75, 25);
+ spawn.mapRect(-275, -650, 1025, 87);
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+
+ spawn.mapRect(1600, -600, 425, 300);
+ spawn.mapRect(1600, -400, 50, 275);
+
+ powerUps.directSpawn(1300, -1500, "gun", false);
+ spawn.starter(900, -300, 35)
+ spawn.starter(1400, -400, 44)
+ },
+ deflect() { //learn to jump
+ m.addHealth(Infinity)
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+
+ let instruction = 0
+ // activate your
field with
${input.key.field.replace('Key', '').replace('Digit', '')} or
right mouse
+ level.trainingText(`use your
field to
deflect the
mobs `)
+
+ level.custom = () => {
+ if (instruction === 0 && m.pos.x > 1350) {
+ instruction++
+ level.trainingText(`
use your field to deflect the mobs `)
+ }
+ //teleport to start if hit
+ if (m.immuneCycle > m.cycle) {
+ m.energy = m.maxEnergy
+ Matter.Body.setPosition(player, {
+ x: 60,
+ y: -50
+ })
+ }
+ //spawn bullets
+ if (!(simulation.cycle % 5)) {
+ spawn.sniperBullet(660 + 580 * Math.random(), -2000, 10, 4);
+ const who = mob[mob.length - 1]
+ Matter.Body.setVelocity(who, {
+ x: 0,
+ y: 8
+ });
+ who.timeLeft = 300
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ //dark
+ ctx.fillStyle = "rgba(0,0,0,0.05)"
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ //center falling bullets
+ ctx.fillStyle = "rgba(255,0,255,0.013)" //pink?
+ ctx.fillRect(650, -2800, 600, 2800)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+
+ spawn.mapRect(-250, 0, 3000, 1800); //floor
+ spawn.mapRect(-250, -2800, 900, 2200); //roof
+ spawn.mapRect(1250, -2800, 1275, 2200); //roof
+ spawn.mapVertex(950, 0, "400 0 -400 0 -300 -50 300 -50"); //base
+
+ spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+
+ //spawn bullets on load to avoid rush
+ for (let i = 0; i < 32; i++) {
+ spawn.sniperBullet(660 + 580 * Math.random(), -2000 + 40 * i, 10, 4);
+ const who = mob[mob.length - 1]
+ Matter.Body.setVelocity(who, {
+ x: 0,
+ y: 8
+ });
+ who.timeLeft = 300
+ }
+ },
+ heal() { //learn to heal
+ m.addHealth(Infinity)
+ m.health = 0;
+ m.addHealth(0.25)
+ document.getElementById("health").style.display = "inline" //show your health bar
+ document.getElementById("health-bg").style.display = "inline"
+ if (!localSettings.isHideHUD) {
+ document.getElementById("defense-bar").style.display = "inline"
+ document.getElementById("damage-bar").style.display = "inline"
+ }
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+
+ let instruction = 0
+ level.trainingText(`your
health is displayed in the top left corner
+
use your
field to pick up
until your
health is full`)
+
+ level.custom = () => {
+ if (instruction === 0 && m.health === 1) {
+ instruction++
+ level.trainingText(`
use your field to pick up
until your health is full`)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ if (m.health !== 1) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ door.draw();
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 0, 3500, 1800); //floor
+
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+
+ spawn.mapRect(700, -8, 50, 25);
+ spawn.mapRect(725, -16, 75, 25);
+ spawn.mapRect(1375, -16, 50, 50);
+ spawn.mapRect(1400, -8, 50, 25);
+ spawn.mapRect(750, -24, 650, 100);
+ powerUps.directSpawn(875, -40, "heal", false, null, 15);
+ powerUps.directSpawn(1075, -50, "heal", false, null, 25);
+ powerUps.directSpawn(1275, -65, "heal", false, null, 35);
+
+ const door = level.door(1612.5, -175, 25, 190, 185, 3)
+ spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
+ nailGun() {
+ level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+ b.removeAllGuns();
+ b.giveGuns("nail gun")
+ b.guns[b.activeGun].ammo = 0
+ simulation.updateGunHUD();
+
+ const door = level.door(1612.5, -175, 25, 190, 185, 3)
+ let instruction = 0
+ level.trainingText(`use your
field to pick up
for your
nail gun `)
+
+ level.custom = () => {
+ if (instruction === 0 && b.inventory.length && b.guns[b.activeGun].ammo > 0) {
+ instruction++
+ level.trainingText(`
use your field to pick up
for your nail gun
+
use the
left mouse button to shoot the
mobs `)
+ } else if (instruction === 1 && mob.length === 0) {
+ instruction++
+ level.trainingText(`
use your field to pick up
for your nail gun
+ use the left mouse button to shoot the mobs `)
+ }
+ //spawn ammo if you run out
+ let isAmmo = false
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === 'ammo') isAmmo = true
+ }
+ if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) {
+ powerUps.directSpawn(1300, -2000, "ammo", false);
+ powerUps.directSpawn(1301, -2200, "ammo", false);
+ }
+
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ if (mob.length > 0) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ door.draw();
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ //ammo tunnel shadow
+ ctx.fillStyle = "rgba(0,0,0,0.4)"
+ ctx.fillRect(1250, -2800, 100, 2200)
+ };
+
+ if (m.health < 1) {
+ powerUps.directSpawn(1298, -3500, "heal", false, 23);
+ powerUps.directSpawn(1305, -3000, "heal", false, 35);
+ }
+ for (let i = 0; i < 2; i++) {
+ spawn.spinner(1300 + i, -3000 - 200 * i, 25 + 5 * i)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: 0,
+ y: 62
+ });
+ }
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-150, -2800, 1400, 2200); //roof with tunnel for ammo
+ spawn.mapRect(1350, -2800, 675, 2200);
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ // spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ // spawn.mapRect(1790, -600, 250, 225); //button left wall
+ // spawn.mapRect(1625, -400, 400, 50);
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ spawn.mapRect(1600, -600, 425, 250);
+ },
+ shotGun() {
+ level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+ b.removeAllGuns();
+ b.giveGuns("shotgun")
+ // b.guns[b.activeGun].ammo = 0
+ // simulation.updateGunHUD();
+ const door = level.door(1612.5, -175, 25, 190, 185, 3)
+ let instruction = 0
+ level.trainingText(`use your
shotgun to clear the room of mobs`)
+
+ level.custom = () => {
+ if (instruction === 0 && mob.length === 0) {
+ instruction++
+ level.trainingText(`
use your shotgun to clear the room of mobs `)
+ }
+ //spawn ammo if you run out
+ let isAmmo = false
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === 'ammo') isAmmo = true
+ }
+ if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) {
+ powerUps.directSpawn(1300, -2000, "ammo", false);
+ powerUps.directSpawn(1301, -2200, "ammo", false);
+ }
+
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ if (mob.length > 0) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ door.draw();
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ //ammo tunnel shadow
+ ctx.fillStyle = "rgba(0,0,0,0.4)"
+ ctx.fillRect(1250, -2800, 100, 2200)
+ };
+
+ if (m.health < 1) {
+ powerUps.directSpawn(1298, -3500, "heal", false, 23);
+ powerUps.directSpawn(1305, -3000, "heal", false, 35);
+ }
+ for (let i = 0; i < 3; i++) {
+ spawn.hopper(1300 + i, -3000 - 2000 * i, 25 + 5 * i)
+ // Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 });
+ }
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-150, -2800, 1400, 2200); //roof with tunnel for ammo
+ spawn.mapRect(1350, -2800, 675, 2200);
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ spawn.mapRect(1600, -600, 425, 250);
+ },
+ superBall() {
+ level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+ b.removeAllGuns();
+ b.giveGuns("super balls")
+ // b.guns[b.activeGun].ammo = 0
+ // simulation.updateGunHUD();
+ const door = level.door(1612.5, -175, 25, 190, 185, 3)
+ let instruction = 0
+ level.trainingText(`use
super balls to clear the room of mobs`)
+
+ level.custom = () => {
+ if (instruction === 0 && mob.length === 0) {
+ instruction++
+ level.trainingText(`
use super balls to clear the room of mobs `)
+ }
+ //spawn ammo if you run out
+ let isAmmo = false
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === 'ammo') isAmmo = true
+ }
+ if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) {
+ powerUps.directSpawn(1300, -2000, "ammo", false);
+ powerUps.directSpawn(1301, -2200, "ammo", false);
+ }
+
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ if (mob.length > 0) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ door.draw();
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ //ammo tunnel shadow
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+ // ctx.fillRect(1225, -2800, 125, 2450)
+ ctx.fillRect(-150, -2800, 1500, 2450);
+ };
+
+ if (m.health < 1) {
+ powerUps.directSpawn(1298, -3500, "heal", false, 23);
+ powerUps.directSpawn(1305, -3000, "heal", false, 35);
+ }
+ for (let i = 0; i < 6; i++) {
+ spawn.spawner(i * 230, -800)
+ // Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 });
+ }
+ spawn.mapVertex(510, -430, "725 0 725 80 -650 80 -650 -80 650 -80"); //upper room with mobs
+ spawn.mapRect(-225, -2800, 1450, 2000);
+ spawn.mapRect(1350, -2800, 675, 2450);
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
+ matterWave() { //fire wave through the map to kill mosb
+ level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+ b.removeAllGuns();
+ b.giveGuns("wave")
+ // b.guns[b.activeGun].ammo = 0
+ // simulation.updateGunHUD();
+ const door = level.door(1612.5, -175, 25, 190, 185, 3)
+ let instruction = 0
+ level.trainingText(`use
wave to clear the room of mobs`)
+
+ level.custom = () => {
+ if (instruction === 0 && mob.length === 0) {
+ instruction++
+ level.trainingText(`
use wave to clear the room of mobs `)
+ }
+ //spawn ammo if you run out
+ let isAmmo = false
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === 'ammo') isAmmo = true
+ }
+ if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) {
+ powerUps.directSpawn(1300, -2000, "ammo", false);
+ powerUps.directSpawn(1301, -2200, "ammo", false);
+ }
+
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ if (mob.length > 0) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ door.draw();
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ //ammo tunnel shadow
+ ctx.fillStyle = "rgba(0,0,0,0.2)"
+ // ctx.fillRect(1225, -2800, 125, 2450)
+ ctx.fillRect(-150, -2800, 1500, 2450);
+ };
+
+ if (m.health < 1) {
+ powerUps.directSpawn(1298, -3500, "heal", false, 23);
+ powerUps.directSpawn(1305, -3000, "heal", false, 35);
+ }
+ for (let i = 0; i < 6; i++) {
+ spawn.springer(i * 200, -800)
+ // Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 });
+ }
+ spawn.springer(1825, -330, 20);
+
+ spawn.mapRect(1175, -850, 50, 500); //upper room with mobs
+ spawn.mapRect(-225, -400, 1450, 50);
+ spawn.mapRect(-225, -2800, 1450, 2000);
+ spawn.mapRect(1350, -2800, 675, 2450);
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
+ missile() { //fire a missile to kill mobs and trigger button
+ level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 30); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+ b.removeAllGuns();
+ b.giveGuns("missiles")
+ // b.guns[b.activeGun].ammo = 0
+ // simulation.updateGunHUD();
+ const buttonDoor = level.button(2500, 50)
+ const door = level.door(1612.5, -175, 25, 190, 185, 3)
+ let instruction = 0
+ level.trainingText(`use
missiles to drop a
block on the button`)
+
+ level.custom = () => {
+ if (instruction === 0 && mob.length === 0) {
+ instruction++
+ level.trainingText(`
use missiles to drop a block on the button `)
+ }
+ //spawn ammo if you run out
+ let isAmmo = false
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === 'ammo') isAmmo = true
+ }
+ if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) {
+ powerUps.directSpawn(1300, -2000, "ammo", false);
+ powerUps.directSpawn(1301, -2200, "ammo", false);
+ }
+
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ buttonDoor.query();
+ buttonDoor.draw();
+ if (buttonDoor.isUp) {
+ door.isClosing = true
+ } else {
+ door.isClosing = false
+ }
+ door.openClose();
+ door.draw();
+
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ //tunnel shadow
+ ctx.fillStyle = "rgba(0,0,0,0.4)"
+ ctx.fillRect(1250, -2800, 100, 2200)
+ ctx.fillRect(1550, 25, 475, 25);
+ };
+ if (m.health < 1) {
+ powerUps.directSpawn(1298, -3500, "heal", false, 23);
+ powerUps.directSpawn(1305, -3000, "heal", false, 35);
+ }
+ for (let i = 0; i < 10; i++) {
+ spawn.springer(2100 + i * 100, -250)
+ // Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 });
+ }
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ // spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(3050, -2800, 1550, 4600);
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(-150, -2800, 1400, 2200); //roof with tunnel for ammo
+ spawn.mapRect(1350, -2800, 675, 2200);
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ // spawn.mapRect(1350, 0, 675, 30);
+ spawn.mapRect(1550, 0, 475, 35);
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ spawn.mapRect(1600, -600, 425, 250);
+
+ spawn.mapRect(1975, -600, 50, 625);
+ spawn.mapRect(2025, -2800, 1075, 2450);
+ },
+ stack() { //stack blocks to get to exit
+ level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -685;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+ b.removeAllGuns();
+ let instruction = 0
+ level.trainingText(`use your
field to stack the
blocks `)
+
+ level.custom = () => {
+ if (instruction === 0 && m.pos.x > 1635) {
+ instruction++
+ level.trainingText(`
use your field to stack the blocks `)
+ }
+
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -1050, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -1050, 400, 400)
+ //ammo tunnel shadow
+ ctx.fillStyle = "rgba(0,0,0,0.4)"
+ ctx.fillRect(250, -2800, 200, 1800)
+ };
+
+ if (m.health < 1) {
+ powerUps.directSpawn(298, -3500, "heal", false, 23);
+ powerUps.directSpawn(305, -3000, "heal", false, 35);
+ }
+ for (let i = 0; i < 15; i++) {
+ spawn.bodyRect(280, -2000 - 500 * i, 30 + 80 * Math.random(), 30 + 80 * Math.random());
+ }
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 0, 3500, 1800); //floor
+ spawn.mapRect(1600, -650, 450, 775);
+ spawn.mapRect(-150, -2800, 400, 1800); //roof with tunnel for ammo
+ spawn.mapRect(450, -2800, 1675, 1800);
+ spawn.mapVertex(1300, 0, "400 0 -500 0 -300 -125 400 -125"); //base
+ },
+ mine() { //kill mobs and tack their bodies
+ level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level
+ level.setPosToSpawn(300, -50); //normal spawn
+ spawn.mapRect(250, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -685;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+ b.removeAllGuns();
+ b.giveGuns("mine")
+
+ let instruction = 0
+ level.trainingText(`press the red
button to spawn a
mob `)
+ const button = level.button(-100, -200)
+ button.isUp = true
+ spawn.mapRect(-150, -200, 240, 425);
+
+ level.custom = () => {
+ if (instruction === 0 && !button.isUp) {
+ instruction++
+ level.trainingText(`
press the red button to spawn a mob turn the
mobs into
blocks `)
+ } else if (instruction === 1 && body.length > 2) {
+ instruction++
+ level.trainingText(`
press the red button to spawn a mob turn the mobs into blocks use your
field to stack the
blocks `)
+ } else if (instruction === 2 && m.pos.x > 1635) {
+ instruction++
+ level.trainingText(`
press the red button to spawn a mob turn the mobs into blocks use your field to stack the blocks `)
+ }
+ //spawn ammo if you run out
+ let isAmmo = false
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === 'ammo') isAmmo = true
+ }
+ if (!isAmmo && b.inventory.length && b.guns[b.activeGun].ammo === 0) {
+ powerUps.directSpawn(1300, -2000, "ammo", false);
+ powerUps.directSpawn(1301, -2200, "ammo", false);
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -1050, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ button.query();
+ button.draw();
+ if (!button.isUp) {
+ if (button.isReady) {
+ button.isReady = false
+ spawn.exploder(335, -1700)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: 0,
+ y: 20
+ });
+ ctx.fillStyle = "rgba(255,0,0,0.9)"
+ ctx.fillRect(550, -2800, 200, 1800)
+ }
+ } else {
+ button.isReady = true
+ }
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -1050, 400, 400)
+ //ammo tunnel shadow
+ ctx.fillStyle = "rgba(0,0,0,0.4)"
+ ctx.fillRect(550, -2800, 200, 1800)
+ };
+
+ if (m.health < 1) {
+ powerUps.directSpawn(298, -3500, "heal", false, 23);
+ powerUps.directSpawn(305, -3000, "heal", false, 35);
+ }
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 0, 3500, 1800); //floor
+ spawn.mapRect(1600, -650, 450, 775);
+ spawn.mapRect(-150, -2800, 700, 1800); //roof with tunnel for ammo
+ spawn.mapRect(750, -2800, 1675, 1800);
+ spawn.mapVertex(1300, 0, "400 0 -600 0 -300 -125 400 -125"); //base
+ },
+ grenades() { //jump at the top of the elevator's path to go extra high
+ level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level
+ level.setPosToSpawn(0, -50); //normal spawn
+ spawn.mapRect(-50, -10, 100, 20); //small platform for player
+ level.exit.x = 1900;
+ level.exit.y = -2835;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+ b.removeAllGuns();
+ b.giveGuns("grenades")
+
+ const elevator1 = level.elevator(550, -100, 180, 25, -840, 0.003, {
+ up: 0.05,
+ down: 0.2
+ }) // x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
+ elevator1.addConstraint();
+ const toggle1 = level.toggle(275, 0) //(x,y,isOn,isLockOn = true/false)
+
+ const elevator2 = level.elevator(1400, -950, 180, 25, -2400, 0.0025) // x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) {
+ elevator2.addConstraint();
+ const button2 = level.button(1000, -850)
+
+ let instruction = 0
+ level.trainingText(`flip the
switch to turn on the
elevator `)
+ level.custom = () => {
+ if (instruction === 0 && elevator1.isOn) {
+ instruction++
+ level.trainingText(`
flip the switch to turn on the elevator
+
put a
block on the
button to active the
elevator `)
+ } else if (instruction === 1 && elevator2.isOn) {
+ instruction++
+ level.trainingText(`
flip the switch to turn on the elevator put a block on the button to active the elevator
+
hold
jump before the
elevator's apex to reach the
exit `)
+ } else if (instruction === 2 && m.pos.x > 1635) {
+ instruction++
+ level.trainingText(`
flip the switch to turn on the elevator put a block on the button to active the elevator hold jump before the elevator's apex to reach the exit `)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1725, -3100, 375, 300);
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ toggle1.query();
+ if (!toggle1.isOn) {
+ if (elevator1.isOn) {
+ elevator1.isOn = false
+ elevator1.frictionAir = 0.2
+ elevator1.addConstraint();
+ }
+ } else if (!elevator1.isOn) {
+ elevator1.isOn = true
+ elevator1.isUp = false
+ elevator1.removeConstraint();
+ elevator1.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2
+ }
+ if (elevator1.isOn) {
+ elevator1.move();
+ ctx.fillStyle = "#444"
+ } else {
+ ctx.fillStyle = "#aaa"
+ }
+ ctx.fillRect(640, -825, 1, 745)
+
+ button2.query();
+ button2.draw();
+ if (button2.isUp) {
+ if (elevator2.isOn) {
+ elevator2.isOn = false
+ elevator2.frictionAir = 0.2
+ elevator2.addConstraint();
+ }
+ } else if (!elevator2.isOn) {
+ elevator2.isOn = true
+ elevator2.isUp = false
+ elevator2.removeConstraint();
+ elevator2.frictionAir = 0.2 //elevator.isUp ? 0.01 : 0.2
+ }
+ if (elevator2.isOn) {
+ elevator2.move();
+ ctx.fillStyle = "#444"
+ } else {
+ ctx.fillStyle = "#aaa"
+ }
+ ctx.fillRect(1490, -2300, 1, 1375)
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1725, -3100, 375, 300);
+ //shadows
+ ctx.fillStyle = "rgba(0,0,0,0.05)"
+ ctx.fillRect(-150, -250, 300, 250);
+ let grd = ctx.createLinearGradient(0, -150, 0, -2300);
+ grd.addColorStop(0, "rgba(0,0,0,0.35)");
+ grd.addColorStop(1, "rgba(0,0,0,0)");
+ ctx.fillStyle = grd //"rgba(0,0,100,0.01)"
+ ctx.fillRect(-200, -2300, 1825, 2300);
+ };
+
+ if (m.health < 1) {
+ powerUps.directSpawn(298, -3500, "heal", false, 23);
+ powerUps.directSpawn(305, -3000, "heal", false, 35);
+ }
+ spawn.mapRect(-2750, -4800, 2600, 6600); //left wall
+ spawn.mapRect(1600, -2800, 3000, 4600); //right wall
+ spawn.mapRect(-150, -4800, 300, 4550);
+ spawn.mapRect(2125, -4775, 2475, 2050);
+ spawn.mapRect(-250, 0, 3500, 1800); //floor
+ spawn.mapRect(750, -850, 950, 950);
+ spawn.mapRect(125, -275, 25, 100);
+ spawn.mapRect(2100, -3150, 50, 350);
+ spawn.mapRect(1725, -3150, 50, 175);
+ spawn.mapRect(1725, -3150, 425, 50);
+
+ spawn.nodeGroup(1200, -1500, "grenadier", 7);
+ },
+ harpoon() { //jump at the top of the elevator's path to go extra high
+ level.difficultyIncrease(1) //difficulty on training mode resets to zero with each new level
+ level.setPosToSpawn(0, -50); //normal spawn
+ spawn.mapRect(-50, -10, 100, 20); //small platform for player
+ level.exit.x = 1900;
+ level.exit.y = -2835;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+ b.removeAllGuns();
+ b.giveGuns("harpoon")
+
+ let instruction = 0
+ level.trainingText(`climb up to the exit`)
+ level.custom = () => {
+ if (instruction === 0 && m.pos.x > 1635) {
+ instruction++
+ level.trainingText(`
climb up to the exit `)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1725, -3100, 375, 300);
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1725, -3100, 375, 300);
+ //shadows
+ ctx.fillStyle = "rgba(0,90,100,0.05)"
+ ctx.fillRect(-150, -250, 300, 250);
+ let grd = ctx.createLinearGradient(0, -150, 0, -2300);
+ grd.addColorStop(0, "rgba(0,90,100,0.35)");
+ grd.addColorStop(1, "rgba(0,90,100,0)");
+ ctx.fillStyle = grd //"rgba(0,0,100,0.01)"
+ ctx.fillRect(-200, -2300, 1825, 2300);
+ vanish1.query();
+ vanish2.query();
+ vanish3.query();
+ vanish4.query();
+ vanish5.query();
+ vanish6.query();
+ vanish7.query();
+ vanish8.query();
+ vanish9.query();
+ vanish10.query();
+ vanish11.query();
+ vanish12.query();
+ };
+ const vanish1 = level.vanish(175, -325, 175, 25); //x, y, width, height, hide = { x: 0, y: 100 } //hide should just be somewhere behind the map so the player can't see it
+ const vanish2 = level.vanish(525, -625, 175, 25);
+ const vanish3 = level.vanish(1125, -1125, 175, 25);
+ const vanish4 = level.vanish(1500, -1450, 100, 25);
+ const vanish5 = level.vanish(1125, -1675, 175, 25);
+ const vanish6 = level.vanish(750, -1950, 175, 25);
+ const vanish7 = level.vanish(550, -1950, 175, 25);
+ const vanish8 = level.vanish(350, -1950, 175, 25);
+ const vanish9 = level.vanish(150, -1950, 175, 25);
+ const vanish10 = level.vanish(325, -2300, 200, 25);
+ const vanish11 = level.vanish(725, -2550, 100, 25);
+ const vanish12 = level.vanish(1125, -2700, 150, 25);
+
+ if (m.health < 1) {
+ powerUps.directSpawn(298, -3500, "heal", false, 23);
+ powerUps.directSpawn(305, -3000, "heal", false, 35);
+ }
+ spawn.mapRect(-2750, -4800, 2600, 6600); //left wall
+ spawn.mapRect(1600, -2800, 3000, 4600); //right wall
+ spawn.mapRect(-150, -4800, 300, 4550);
+ spawn.mapRect(2125, -4775, 2475, 2050);
+ spawn.mapRect(-250, 0, 3500, 1800); //floor
+ spawn.mapRect(750, -850, 950, 950);
+ spawn.mapRect(125, -275, 25, 100);
+ spawn.mapRect(2100, -3150, 50, 350);
+ spawn.mapRect(1725, -3150, 50, 175);
+ spawn.mapRect(1725, -3150, 425, 50);
+
+ spawn.grower(250, -375);
+ spawn.grower(1000, -900)
+ spawn.grower(1475, -925);
+ spawn.grower(275, -2000);
+ spawn.grower(650, -2000);
+ spawn.grower(1475, -975);
+ spawn.grower(1575, -1525);
+ spawn.grower(1700, -2850);
+ },
+ diamagnetism() {
+ if (localSettings.isHideHUD) localSettings.isHideHUD = false
+ m.addHealth(Infinity)
+ document.getElementById("health").style.display = "none" //hide your health bar
+ document.getElementById("health-bg").style.display = "none"
+ document.getElementById("defense-bar").style.display = "none"
+ document.getElementById("damage-bar").style.display = "none"
+ const futureGuns = ["harpoon", "shotgun", "nail gun", "super balls", "wave", "foam", "laser"];
+ const futureGun = Math.floor(Math.random() * futureGuns.length)
+ b.giveGuns(futureGuns[futureGun], Infinity)
+ m.setField(2)
+ m.fieldRegen = 0;
+ level.trainingText(`
diamagnetism by
Richard0820 Don't get hit. Find the portal to the exit.`)
+ const dodge = [];
+ const button = level.button(350 - 63, -300)
+ const door = level.door(750, -275, 50, 125, 125)
+ const door2 = level.door(750, -525, 50, 125, 125);
+ const forceOne = forceField(4425, -3925, 525, 3975);
+ const forceTwo = forceField(1550, -9950, 275, 3300);
+ const forceThree = forceField(4200, -8725, 750, 4450);
+ const respawnX = [];
+ respawnX.push(setRespawn(-50, -625, 825, 375));
+ respawnX.push(setRespawn(3225, -3675, 1200, 1000));
+ respawnX.push(setRespawn(3575, -5675, 625, 800));
+ respawnX.push(setRespawn(775, -4250, 400, 375));
+ respawnX.push(setRespawn(2825, -2975, 250, 300));
+ respawnX.push(setRespawn(3675, -1125, 325, 250));
+ let respawnPoints = {
+ x: 125,
+ y: -9575,
+ }
+ door2.isClosing = true;
+ button.isUp = true
+ level.setPosToSpawn(125, -9575); //normal spawn
+ level.exit.x = -1825;
+ level.exit.y = 50;
+ spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); //bump for level entrance
+ spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20); //bump for level exit
+ level.defaultZoom = 1800
+ simulation.zoomTransition(level.defaultZoom)
+ document.body.style.backgroundColor = "#d8dadf";
+ alternate(-50, -9050, 425, 100);
+ const image = new Image()
+ image.src = "https://raw.githubusercontent.com/Whyisthisnotavalable/image-yy/main/Hotpot-removed.png";
+ level.chain(-675, 400, -0.4366271598, true, 20)
+ level.chain(-1600, 125, 0.5144513131, true, 19)
+ const portal = portall({
+ x: 3825,
+ y: -1000,
+ },
+ 3 * Math.PI, {
+ x: 550,
+ y: -100,
+ },
+ 3 * Math.PI
+ );
+ level.custom = () => {
+ portal[2].query();
+ portal[3].query();
+ portal[0].draw();
+ portal[1].draw();
+ portal[2].draw();
+ portal[3].draw();
+ forceOne.query()
+ forceTwo.query()
+ forceThree.query()
+ if (input.field && player.position.x < 775 && player.position.x > -50) {
+ if (m.energy > 0.02) {
+ m.energy -= 0.01
+ } else {
+ input.field = false
+ }
+ }
+ level.exit.drawAndCheck();
+ level.enter.draw();
+ button.query()
+ button.draw()
+ if (!button.isUp) {
+ door.isClosing = true;
+ door2.isClosing = false;
+ } else if (button.isUp) {
+ door.isClosing = false;
+ door2.isClosing = true;
+ }
+ door.draw()
+ door.openClose()
+ door2.draw()
+ door2.openClose()
+ for (let i = 0; i < dodge.length; i++) dodge[i].query();
+ for (let i = 0; i < respawnX.length; i++) respawnX[i].query();
+ ctx.fillStyle = "gray";
+ ctx.fillRect(1175, -6650, 2400, 2375);
+ ctx.drawImage(image, 1175 + 1200 - 250, -6650 + (2375 / 2) - 250, 500, 500)
+ if (m.immuneCycle > m.cycle) {
+ m.energy = m.maxEnergy
+ Matter.Body.setPosition(player, {
+ x: respawnPoints.x,
+ y: respawnPoints.y
+ })
+ }
+ };
+ level.customTopLayer = () => { };
+ spawn.mapRect(-100, 0, 5100, 100);
+ spawn.mapRect(-100, -10000, 5100, 100);
+ spawn.mapRect(4900, -10000, 100, 10100);
+ spawn.mapRect(-100, -10000, 100, 9800);
+ spawn.mapRect(-100, -9525, 450, 100);
+ spawn.mapRect(725, -300, 100, 400);
+ spawn.mapRect(725, -10000, 100, 9500);
+ spawn.mapRect(-100, -300, 925, 100);
+ spawn.mapRect(800, -675, 3675, 100);
+ spawn.mapRect(4375, -1425, 100, 850);
+ spawn.mapRect(1350, -1425, 3125, 100);
+ spawn.mapRect(1350, -1425, 100, 600);
+ spawn.mapRect(1350, -925, 2700, 100);
+ spawn.mapRect(1575, -1175, 2475, 100);
+ spawn.mapRect(3950, -1175, 100, 350);
+ spawn.mapRect(4375, -2725, 100, 1400);
+ spawn.mapRect(775, -2725, 2325, 100);
+ spawn.mapRect(3200, -2725, 1275, 100);
+ spawn.mapRect(3200, -3975, 100, 1350);
+ spawn.mapRect(4375, -3950, 100, 1125);
+ spawn.mapRect(4375, -3975, 625, 100);
+ spawn.mapRect(3200, -4325, 100, 450);
+ spawn.mapRect(3200, -4325, 1600, 100);
+ spawn.mapRect(4450, -2725, 50, 25);
+ spawn.mapRect(1125, -3025, 2175, 100);
+ spawn.mapRect(725, -3925, 2175, 100);
+ spawn.mapRect(3525, -6700, 100, 2475);
+ spawn.mapRect(4150, -6700, 100, 2475);
+ spawn.mapRect(1125, -6700, 2500, 105);
+ spawn.mapRect(1125, -6700, 100, 2625);
+ spawn.mapRect(1500, -8775, 100, 2175);
+ spawn.mapRect(4150, -8775, 100, 1900);
+ spawn.mapRect(1775, -8775, 2475, 100);
+ spawn.mapRect(4225, -6700, 50, 25);
+ spawn.mapRect(4150, -8775, 850, 100);
+ spawn.mapRect(3600, -2825, 125, 125);
+ spawn.mapRect(3275, -3050, 125, 125);
+ spawn.mapRect(3600, -3275, 125, 125);
+ spawn.mapRect(3300, -3525, 125, 125);
+ spawn.mapRect(3575, -3725, 900, 125);
+ spawn.mapRect(4075, -3775, 75, 75);
+ spawn.mapRect(4225, -3875, 75, 175);
+ spawn.mapRect(3600, -6625, 100, 100);
+ spawn.mapRect(4075, -6475, 100, 100);
+ spawn.mapRect(3600, -6300, 100, 100);
+ spawn.mapRect(4075, -6175, 100, 100);
+ spawn.mapRect(3600, -6000, 100, 100);
+ spawn.mapRect(4075, -5875, 100, 100);
+ spawn.mapRect(3600, -5700, 100, 100);
+ spawn.mapRect(4075, -5550, 100, 100);
+ spawn.mapRect(3600, -5400, 100, 1125);
+ spawn.mapRect(3675, -5300, 100, 1025);
+ spawn.mapRect(3750, -5225, 100, 950);
+ spawn.mapRect(3825, -5150, 100, 875);
+ spawn.mapRect(3900, -5075, 100, 800);
+ spawn.mapRect(3975, -5000, 100, 725);
+ spawn.mapRect(4050, -4925, 125, 650);
+ spawn.mapRect(4150, -6925, 75, 125);
+ spawn.mapRect(1775, -8775, 100, 1900);
+ spawn.mapRect(1775, -9950, 100, 975);
+ spawn.mapRect(1500, -9950, 100, 975);
+ spawn.mapRect(1275, -8775, 325, 100);
+ spawn.mapRect(1200, -7775, 25, 1175);
+ spawn.mapRect(1250, -7950, 25, 1350);
+ spawn.mapRect(1300, -8175, 25, 1575);
+ spawn.mapRect(1350, -8500, 25, 1900);
+ spawn.mapRect(1400, -8625, 25, 2025);
+ spawn.mapRect(1450, -8700, 25, 2100);
+ spawn.mapRect(1150, -7625, 25, 1025);
+ spawn.mapRect(1125, -4325, 2175, 100);
+ spawn.mapRect(4250, -925, 150, 100);
+ spawn.mapRect(575, -225, 175, 50);
+ spawn.mapRect(575, -50, 175, 75);
+ spawn.mapRect(-25, 50, 125, 100);
+ spawn.mapRect(75, 75, 50, 50);
+ spawn.sniper(3600, -7300);
+ spawn.sniper(3325, -7475);
+ spawn.sniper(2825, -7500);
+ spawn.sniper(2250, -7450);
+ spawn.sniper(4125, -5150);
+ spawn.sniper(4100, -5675);
+ spawn.sniper(4100, -5950);
+ spawn.sniper(4125, -6325);
+ spawn.sniper(3875, -6975);
+ spawn.stabber(4075, -4075);
+ spawn.stabber(3775, -3950);
+ spawn.stabber(3500, -3850);
+ spawn.stabber(4000, -3500);
+ spawn.stabber(3850, -3125);
+ spawn.stabber(3450, -3125);
+ spawn.stabber(4225, -2900);
+ spawn.hopper(4125, -250);
+ spawn.hopper(3525, -250);
+ spawn.hopper(2925, -325);
+ spawn.hopper(2175, -150);
+ spawn.hopper(1175, -400);
+ spawn.mantisBoss(3425, -9350);
+ spawn.pulsarBoss(1725, -6050, 1);
+ spawn.pulsarBoss(1800, -4850, 1);
+ spawn.pulsarBoss(3000, -4825, 1);
+ spawn.pulsarBoss(2975, -6175, 1);
+ spawn.spinner(2025, -4050);
+ spawn.spinner(2125, -2825);
+ spawn.pulsar(2450, -3775);
+ spawn.pulsar(2200, -3750);
+ spawn.pulsar(1900, -3775);
+ spawn.pulsar(1600, -3725);
+ spawn.pulsar(1300, -3750);
+ spawn.pulsar(925, -3725);
+ spawn.focuser(3925, -2375);
+ spawn.focuser(1150, -2450);
+ spawn.focuser(2450, -1675);
+ spawn.mapVertex(-850, 500, "0 0 500 0 250 500");
+ spawn.mapVertex(-1775, 250, "0 0 500 0 250 500");
+ spawn.bodyRect(25, -375, 50, 50);
+ function alternate(x, y, width, height, spacingX = 25, spacingY = 1500, number = 6) {
+ for (let i = 0; i < number; i++) {
+ if (i % 2 === 0) {
+ dodge.push(back(x, y + i * (height + spacingY), width, height, level.enter.x, level.enter.y))
+ } else {
+ dodge.push(back(x + width - spacingX, y + i * (height + spacingY), width, height, level.enter.x, level.enter.y))
+ }
+ }
+ }
+ function back(x, y, width, height, x1, y1) {
+ return {
+ move: { x: x1, y: y1 },
+ min: { x: x, y: y },
+ max: { x: x + width, y: y + height },
+ width: width,
+ height: height,
+ maxHeight: height,
+ isOn: true,
+ query() {
+ if (this.isOn) {
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = `hsla(0, 100%, 50%,${0.6 + 0.4 * Math.random()})`
+ ctx.strokeRect(this.min.x, this.min.y, this.width, this.height)
+ if (this.height > 0 && Matter.Query.region([player], this).length) {
+ Matter.Body.setVelocity(player, { x: 0, y: 0 })
+ Matter.Body.setPosition(player, { x: this.move.x, y: this.move.y })
+ m.energy = m.maxEnergy;
+ }
+ }
+ },
+ }
+ }
+ function forceField(x, y, width, height) {
+ return {
+ min: { x: x, y: y },
+ max: { x: x + width, y: y + height },
+ width: width,
+ height: height,
+ maxHeight: height,
+ isOn: true,
+ query() {
+ if (this.isOn) {
+ ctx.fillStyle = `rgba(0, 250, 250, 0.55)`
+ ctx.fillRect(this.min.x, this.min.y, this.width, this.height)
+ if (this.height > 0 && Matter.Query.region([player], this).length && input.field) {
+ player.force.y -= 0.015;
+ m.energy = m.maxEnergy;
+ }
+ ctx.fillStyle = `rgba(0, 250, 250)`
+ ctx.fillRect(this.min.x + this.width * Math.random(), this.min.y, 5, this.height)
+ }
+ },
+ }
+ }
+ function setRespawn(x, y, width, height) {
+ return {
+ min: { x: x, y: y },
+ max: { x: x + width, y: y + height },
+ width: width,
+ height: height,
+ maxHeight: height,
+ isOn: true,
+ query() {
+ if (this.isOn) {
+ ctx.fillStyle = `rgba(0, 250, 0, 0.11)`
+ ctx.fillRect(this.min.x, this.min.y, this.width, this.height)
+ if (this.height > 0 && Matter.Query.region([player], this).length) {
+ m.energy = m.maxEnergy;
+ respawnPoints.x = this.min.x + (this.width / 2);
+ respawnPoints.y = this.min.y + (this.height / 2);
+ }
+ }
+ },
+ }
+ }
+ function portall(centerA, angleA, centerB, angleB) {
+ const width = 50
+ const height = 150
+ const mapWidth = 200
+ const unitA = Matter.Vector.rotate({ x: 1, y: 0 }, angleA)
+ const unitB = Matter.Vector.rotate({ x: 1, y: 0 }, angleB)
+ draw = function () {
+ ctx.beginPath(); //portal
+ let v = this.vertices;
+ ctx.moveTo(v[0].x, v[0].y);
+ for (let i = 1; i < v.length; ++i) ctx.lineTo(v[i].x, v[i].y);
+ ctx.fillStyle = this.color
+ ctx.fill();
+ }
+ query = function (isRemoveBlocks = false) {
+ if (Matter.Query.collides(this, [player]).length === 0) { //not touching player
+ if (player.isInPortal === this) player.isInPortal = null
+ } else if (player.isInPortal !== this) { //touching player
+ if (m.buttonCD_jump === m.cycle) player.force.y = 0 // undo a jump right before entering the portal
+ m.buttonCD_jump = 0 //disable short jumps when letting go of jump key
+ player.isInPortal = this.portalPair
+ if (this.portalPair.angle % (Math.PI / 2)) { //if left, right up or down
+ // if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ Matter.Body.setPosition(player, this.portalPair.portal.position);
+ } else {
+ // if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ Matter.Body.setPosition(player, this.portalPair.position);
+ }
+ let mag
+ if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up
+ mag = Math.max(10, Math.min(50, player.velocity.y * 0.8)) + 11
+ } else {
+ mag = Math.max(6, Math.min(50, Vector.magnitude(player.velocity)))
+ }
+ let v = Vector.mult(this.portalPair.unit, mag)
+ Matter.Body.setVelocity(player, v);
+ // move bots to player
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ // Matter.Body.setPosition(bullet[i], this.portalPair.portal.position);
+ Matter.Body.setPosition(bullet[i], Vector.add(this.portalPair.portal.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], { x: 0, y: 0 });
+ }
+ }
+ if (tech.isHealAttract) { //send heals to next portal
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal" && Vector.magnitudeSquared(Vector.sub(powerUp[i].position, m.pos)) < 1000000) {
+ Matter.Body.setPosition(powerUp[i], Vector.add(this.portalPair.portal.position, { x: 500 * (Math.random() - 0.5), y: 500 * (Math.random() - 0.5) }));
+ }
+ }
+ }
+ }
+ // if (body.length) {
+ for (let i = 0, len = body.length; i < len; i++) {
+ if (body[i] !== m.holdingTarget) {
+ // body[i].bounds.max.x - body[i].bounds.min.x < 100 && body[i].bounds.max.y - body[i].bounds.min.y < 100
+ if (Matter.Query.collides(this, [body[i]]).length === 0) {
+ if (body[i].isInPortal === this) body[i].isInPortal = null
+ } else if (body[i].isInPortal !== this) { //touching this portal, but for the first time
+ if (isRemoveBlocks) {
+ Matter.Composite.remove(engine.world, body[i]);
+ body.splice(i, 1);
+ break
+ }
+ body[i].isInPortal = this.portalPair
+ //teleport
+ if (this.portalPair.angle % (Math.PI / 2)) { //if left, right up or down
+ Matter.Body.setPosition(body[i], this.portalPair.portal.position);
+ } else { //if at some odd angle
+ Matter.Body.setPosition(body[i], this.portalPair.position);
+ }
+ //rotate velocity
+ let mag
+ if (this.portalPair.angle !== 0 && this.portalPair.angle !== Math.PI) { //portal that fires the player up
+ mag = Math.max(10, Math.min(50, body[i].velocity.y * 0.8)) + 11
+ } else {
+ mag = Math.max(6, Math.min(50, Vector.magnitude(body[i].velocity)))
+ }
+ let v = Vector.mult(this.portalPair.unit, mag)
+ Matter.Body.setVelocity(body[i], v);
+ }
+ }
+ }
+ // }
+
+ //remove block if touching
+ // if (body.length) {
+ // touching = Matter.Query.collides(this, body)
+ // for (let i = 0; i < touching.length; i++) {
+ // if (touching[i].bodyB !== m.holdingTarget) {
+ // for (let j = 0, len = body.length; j < len; j++) {
+ // if (body[j] === touching[i].bodyB) {
+ // body.splice(j, 1);
+ // len--
+ // Matter.Composite.remove(engine.world, touching[i].bodyB);
+ // break;
+ // }
+ // }
+ // }
+ // }
+ // }
+
+ // if (touching.length !== 0 && touching[0].bodyB !== m.holdingTarget) {
+ // if (body.length) {
+ // for (let i = 0; i < body.length; i++) {
+ // if (body[i] === touching[0].bodyB) {
+ // body.splice(i, 1);
+ // break;
+ // }
+ // }
+ // }
+ // Matter.Composite.remove(engine.world, touching[0].bodyB);
+ // }
+ }
+
+ const portalA = composite[composite.length] = Bodies.rectangle(centerA.x, centerA.y, width, height, {
+ isSensor: true,
+ angle: angleA,
+ color: "hsla(197, 100%, 50%,0.7)",
+ draw: draw,
+ });
+ const portalB = composite[composite.length] = Bodies.rectangle(centerB.x, centerB.y, width, height, {
+ isSensor: true,
+ angle: angleB,
+ color: "hsla(29, 100%, 50%, 0.7)",
+ draw: draw
+ });
+ const mapA = composite[composite.length] = Bodies.rectangle(centerA.x - 0.5 * unitA.x * mapWidth, centerA.y - 0.5 * unitA.y * mapWidth, mapWidth, height + 10, {
+ collisionFilter: {
+ category: cat.map,
+ mask: cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ unit: unitA,
+ angle: angleA,
+ color: color.map,
+ draw: draw,
+ query: query,
+ lastPortalCycle: 0
+ });
+ Matter.Body.setStatic(mapA, true); //make static
+ Composite.add(engine.world, mapA); //add to world
+
+ const mapB = composite[composite.length] = Bodies.rectangle(centerB.x - 0.5 * unitB.x * mapWidth, centerB.y - 0.5 * unitB.y * mapWidth, mapWidth, height + 10, {
+ collisionFilter: {
+ category: cat.map,
+ mask: cat.bullet | cat.powerUp | cat.mob | cat.mobBullet //cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet
+ },
+ unit: unitB,
+ angle: angleB,
+ color: color.map,
+ draw: draw,
+ query: query,
+ lastPortalCycle: 0,
+ });
+ Matter.Body.setStatic(mapB, true); //make static
+ Composite.add(engine.world, mapB); //add to world
+
+ mapA.portal = portalA
+ mapB.portal = portalB
+ mapA.portalPair = mapB
+ mapB.portalPair = mapA
+ return [portalA, portalB, mapA, mapB]
+ }
+ },
+ trainingTemplate() { //learn to crouch
+ m.addHealth(Infinity)
+ document.getElementById("health").style.display = "none" //hide your health bar
+ document.getElementById("health-bg").style.display = "none"
+ document.getElementById("defense-bar").style.display = "none"
+ document.getElementById("damage-bar").style.display = "none"
+ level.setPosToSpawn(60, -50); //normal spawn
+ spawn.mapRect(10, -10, 100, 20); //small platform for player
+ level.exit.x = 1775;
+ level.exit.y = -35;
+ spawn.mapRect(level.exit.x, level.exit.y + 25, 100, 100); //exit bump
+ simulation.zoomScale = 1400 //1400 is normal
+ level.defaultZoom = 1400
+ simulation.zoomTransition(level.defaultZoom, 1)
+ document.body.style.backgroundColor = level.trainingBackgroundColor
+
+
+ let instruction = 0
+ level.trainingText(`press
${input.key.down.replace('Key', '').replace('Digit', '')} to crouch`)
+
+ level.custom = () => {
+ if (instruction === 0 && input.down) {
+ instruction++
+
+ level.trainingText(`
press ${input.key.down.replace('Key', '').replace('Digit', '')} to crouch `)
+ }
+ //exit room
+ ctx.fillStyle = "#f2f2f2"
+ ctx.fillRect(1600, -400, 400, 400)
+
+ level.enter.draw();
+ level.exit.drawAndCheck();
+ };
+ level.customTopLayer = () => {
+ //exit room glow
+ ctx.fillStyle = "rgba(0,255,255,0.05)"
+ ctx.fillRect(1600, -400, 400, 400)
+ };
+
+ spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
+ spawn.mapRect(2000, -2800, 2600, 4600); //right wall
+ spawn.mapRect(-250, 50, 3500, 1750); //floor
+ spawn.mapRect(-200, 0, 950, 100);
+ spawn.mapRect(1575, 0, 500, 100);
+ spawn.mapRect(-250, -2800, 3500, 2200); //roof
+
+ spawn.mapRect(725, 12, 50, 25);
+ spawn.mapRect(725, 25, 75, 25);
+ spawn.mapRect(750, 38, 75, 25);
+ spawn.mapRect(1525, 25, 75, 50);
+ spawn.mapRect(1500, 38, 50, 25);
+ spawn.mapRect(1550, 12, 50, 25);
+ spawn.mapRect(1600, -1200, 500, 850); //exit roof
+ spawn.mapRect(1600, -400, 50, 225); //exit room left upper wall
+ },
+};
diff --git a/ngon/js/lore.js b/ngon/js/lore.js
new file mode 100644
index 00000000..c841ea4f
--- /dev/null
+++ b/ngon/js/lore.js
@@ -0,0 +1,1241 @@
+const lore = {
+ techCount: 0,
+ techGoal: 7,
+ setTechGoal() {
+ this.techGoal = Math.max(1, Math.floor(8 - 1.5 * simulation.difficultyMode))
+ },
+ talkingColor: "#dff", //set color of graphic on level.null
+ isSpeech: false,
+ testSpeechAPI() {
+ if ('speechSynthesis' in window) { // Synthesis support. Make your web apps talk!
+ lore.isSpeech = true
+ // const utterance = new SpeechSynthesisUtterance("test");
+ // utterance.volume = 0; // 0 to 1
+ // speechSynthesis.speak(utterance);
+ // utterance.onerror = () => { //if speech doesn't work
+ // lore.isSpeech = false
+ // }
+ // speechFrozen = setTimeout(() => { // speech frozen after 15 seconds of no end
+ // console.log('speech frozen')
+ // lore.isSpeech = false
+ // }, 5000);
+ // utterance.onend = () => {
+ // clearTimeout(speechFrozen);
+ // }
+ } else {
+ lore.isSpeech = false
+ }
+ },
+ rate: 1, // //utterance.rate = 1; // 0.1 to 10
+ nextSentence() {
+ if (m.alive && !simulation.isCheating) {
+ lore.sentence++
+ lore.conversation[lore.chapter][lore.sentence]() //go to next sentence in the chapter and play it
+ }
+ },
+ unlockTesting() {
+ if (localSettings.loreCount < 1) localSettings.loreCount = 1
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ document.getElementById("control-testing").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
+ // document.getElementById("experiment-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
+ simulation.makeTextLog(`
lore .unlockTesting()`, Infinity);
+
+ sound.portamento(50)
+ sound.portamento(83.333)
+ sound.portamento(166.666)
+ },
+ trainer: {
+ color: "#f20",
+ voice: undefined,
+ text: function (say) {
+ simulation.makeTextLog(`input.audio(
${(Date.now() / 1000).toFixed(0)} s )
: "
${say} "`, Infinity);
+ lore.talkingColor = this.color
+ const utterance = new SpeechSynthesisUtterance(say);
+ utterance.lang = "en-AU" //"en-IN"; //de-DE en-GB fr-FR en-US en-AU
+ utterance.volume = 0.2; // 0 to 1
+ speechSynthesis.speak(utterance);
+ },
+ },
+ anand: {
+ color: "#e0c",
+ voice: undefined,
+ text: function (say) {
+ if (level.levels[level.onLevel] === undefined) { //only talk if on the lore level (which is undefined because it is popped out of the level.levels array)
+ simulation.makeTextLog(`input.audio(
${(Date.now() / 1000).toFixed(0)} s )
: "
${say} "`, Infinity);
+ lore.talkingColor = this.color
+ if (lore.isSpeech) {
+ const utterance = new SpeechSynthesisUtterance(say);
+ // utterance.voice = lore.anand.voice
+ utterance.lang = "en-GB" //"en-IN"; //de-DE en-GB fr-FR en-US en-AU
+ utterance.volume = 0.2; // 0 to 1
+ // if (lore.rate !== 1) utterance.rate = lore.rate
+ speechSynthesis.speak(utterance);
+ utterance.onerror = () => { //if speech doesn't work
+ lore.isSpeech = false
+ lore.nextSentence()
+ }
+ speechFrozen = setTimeout(() => { // speech frozen after 10 seconds of no end
+ console.log('speech frozen')
+ lore.isSpeech = false
+ lore.nextSentence()
+ }, 20000);
+ utterance.onend = () => {
+ clearTimeout(speechFrozen);
+ lore.nextSentence()
+ }
+ } else {
+ setTimeout(() => {
+ lore.nextSentence()
+ }, 3000);
+ }
+ }
+ },
+ },
+ miriam: {
+ color: "#f20",
+ text: function (say) {
+ if (level.levels[level.onLevel] === undefined) { //only talk if on the lore level (which is undefined because it is popped out of the level.levels array)
+ simulation.makeTextLog(`input.audio(
${(Date.now() / 1000).toFixed(0)} s )
: "
${say} "`, Infinity);
+ lore.talkingColor = this.color
+ if (lore.isSpeech) {
+ utterance = new SpeechSynthesisUtterance(say);
+ // utterance.voice = lore.anand.voice
+ utterance.lang = "en-AU";
+ utterance.volume = 0.2; // 0 to 1
+ // if (lore.rate !== 1) utterance.rate = lore.rate
+ speechSynthesis.speak(utterance);
+ utterance.onerror = () => { //if speech doesn't work
+ lore.isSpeech = false
+ lore.nextSentence()
+ }
+ speechFrozen = setTimeout(function () { // speech frozen after 10 seconds of no end
+ console.log('speech frozen')
+ lore.isSpeech = false
+ lore.nextSentence()
+ }, 20000);
+ utterance.onend = () => {
+ clearTimeout(speechFrozen);
+ lore.nextSentence()
+ }
+ } else {
+ setTimeout(() => {
+ lore.nextSentence()
+ }, 3000);
+ }
+ }
+ },
+ },
+ chapter: 0, //what part of the conversation is playing
+ sentence: 0, //what part of the conversation is playing
+ conversation: [
+ [ //chapter 0, first time they meet, and testing gets unlocked
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("I've never seen it generate this level before.")
+ }, 5000);
+ },
+ () => {
+ lore.anand.text("Wow. Just a platform.")
+ },
+ () => {
+ lore.miriam.text("And that thing...")
+ },
+ () => {
+ lore.anand.text("Weird")
+ },
+ () => {
+ lore.anand.text("Maybe it's trapped.")
+ },
+ () => {
+ lore.miriam.text("Looks like testing mode is locked.")
+ },
+ () => {
+ lore.miriam.text("I'll unlock it with the console command.")
+ },
+ () => {
+ lore.unlockTesting();
+ setTimeout(() => {
+ lore.miriam.text("Hey little bot! Just press 'T' to enter testing mode and 'U' to go to the next level.")
+ }, 1000);
+ },
+ () => {
+ lore.anand.text("It can't process what you're saying.")
+ },
+ () => {
+ lore.miriam.text("ha hahahaha. I know, but it does seem to be getting smarter.")
+ },
+ () => {
+ lore.talkingColor = "#dff"
+ setTimeout(() => {
+ lore.miriam.text("Poor thing... I hope it figures out how to escape.")
+ }, 25000);
+ },
+ () => {
+ lore.talkingColor = "#dff"
+ },
+ ],
+ [ //chapter 1, they learn the bot can understand what they say
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("Hey look! It's back at the weird level again!")
+ }, 5000);
+ },
+ () => {
+ lore.anand.text("oh Wow! Why does it keep making this level?")
+ },
+ () => {
+ lore.miriam.text("I don't know, but last time it was in this room I think it understood us.")
+ },
+ () => {
+ lore.miriam.text("Let's try talking to it again.")
+ },
+ () => {
+ lore.miriam.text("hmmm, what should we say?")
+ },
+ () => {
+ lore.anand.text("I'm still not convinced it understands. We need a test.")
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("Hey bot!!!")
+ }, 1000);
+ },
+ () => {
+ lore.miriam.text("If you can understand me crouch")
+ },
+ () => {
+ lore.talkingColor = "#dff"
+
+ function cycle() {
+ if (input.down) {
+ lore.miriam.text("Look, It did it! It crouched.")
+ } else {
+ if (m.alive) requestAnimationFrame(cycle);
+ }
+ }
+ requestAnimationFrame(cycle);
+ },
+ () => {
+ lore.anand.text("Amazing! It can understand us...")
+ },
+ () => {
+ lore.miriam.text("It's Alive... Or it just crouched randomly.")
+ },
+ () => {
+ lore.miriam.text("Hey bot! Can you crouch again?")
+ },
+ () => {
+ lore.talkingColor = "#dff"
+
+ function cycle() {
+ if (input.down) {
+ lore.miriam.text("It is Alive!!! ... hehehehehe! ahahahahahah ehehehehe, ahahahah ...")
+ } else {
+ if (m.alive) requestAnimationFrame(cycle);
+ }
+ }
+ requestAnimationFrame(cycle);
+ },
+ () => {
+ setTimeout(() => {
+ lore.anand.text("OK ...")
+ }, 1000);
+ },
+ () => {
+ lore.anand.text("but seriously, this means that in this room it can monitor our audio, and it can understand us.")
+ },
+ () => {
+ lore.anand.text("Anything we say could destabilize the project.")
+ },
+ () => {
+ lore.miriam.text("Fine, Let's talk down stairs.")
+ },
+ () => {
+ lore.miriam.text("Bye bye little bot.")
+ },
+ () => {
+ lore.talkingColor = "#dff"
+ },
+ ],
+ [ //chapter 2, they ask the bot questions, but waves of mobs come and attack
+ () => {
+ lore.anand.text("Quick, get ready. It's back!")
+ },
+ () => {
+ lore.miriam.text("What's back?")
+ },
+ () => {
+ lore.anand.text("The bot's on the communication level again!")
+ },
+ () => {
+ lore.miriam.text("Oh, I've got so many questions.")
+ },
+ () => {
+ lore.miriam.text("Like, Why can we only hear it on this level?")
+ },
+ () => {
+ lore.miriam.text("Or, how did it learn to understand words?")
+ },
+ () => {
+ lore.anand.text("Well, the bot can't talk. So it has to be yes or no.")
+ },
+ () => {
+ setTimeout(() => {
+ lore.anand.text("OK bot, first question: JUMP is YES, CROUCH is NO")
+ }, 500);
+ },
+ () => {
+ lore.anand.text("Do you remember the last time we met?")
+ },
+ () => {
+ function cycle() {
+ if (input.down) {
+ lore.anand.text("It crouched: so NO")
+ lore.sentence--
+ lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => {
+ lore.anand.text("Maybe it can't remember anything beyond each time it plays?")
+ }) //lore.conversation[chapter].splice(1,this sentence index, ()=>{ })
+ } else if (input.up) {
+ lore.anand.text("It jumped: so YES")
+ lore.sentence--
+ lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => {
+ lore.anand.text("That's good.")
+ })
+ } else if (m.alive) {
+ requestAnimationFrame(cycle);
+ }
+ }
+ requestAnimationFrame(cycle);
+ lore.talkingColor = "#dff"
+ },
+ () => {
+ lore.talkingColor = "#dff"
+ setTimeout(() => {
+ lore.miriam.text("My turn to ask a question. JUMP for YES, CROUCH for NO")
+ }, 1000);
+ },
+ () => {
+ lore.miriam.text("Little Bot. Do you have emotions?")
+ },
+ () => {
+ function cycle() {
+ if (input.down) {
+ lore.miriam.text("So, No. Maybe you are lucky. Emotions are complex.")
+ } else if (input.up) {
+ lore.anand.text("YES, Cool! I wonder if its emotions came from watching humans.")
+ lore.sentence--
+ lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => {
+ lore.miriam.text("Or maybe it learned independently, because it needed them.")
+ }) //lore.conversation[chapter].splice(1,this sentence index, ()=>{ })
+ } else if (m.alive) {
+ requestAnimationFrame(cycle);
+ }
+ }
+ requestAnimationFrame(cycle);
+ lore.talkingColor = "#dff"
+ },
+ () => {
+ lore.miriam.text("I wish we could just ask it questions directly, instead of yes or no.")
+ },
+ () => {
+ lore.anand.text("If we say the alphabet it could crouch on the correct letter to spell words.")
+ },
+ () => {
+ lore.miriam.text("That would take forever.")
+ },
+ () => {
+ lore.miriam.text("I really want to know why is it generating the mobs? And why does it keep fighting them?")
+ },
+ () => {
+ lore.anand.text("Maybe that is just part of its expectation–maximization algorithm")
+ },
+ () => {
+ lore.miriam.text("Well sure, but what does that even mean?")
+ },
+ () => {
+ lore.miriam.text("Do we all just do things because we are-")
+ spawn[spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]](1000 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5));
+ setInterval(() => {
+ if (Math.random() < 0.5) {
+ spawn[spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]](1000 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5));
+ level.difficultyIncrease(simulation.difficultyMode)
+ } else {
+ spawn.randomLevelBoss(500 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5))
+ }
+ }, 7000); //every 6 seconds
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("... wait, what is happening?")
+ }, 1000);
+ },
+ () => {
+ lore.anand.text("It's spawning mobs.")
+ },
+ () => {
+ lore.miriam.text("Oh no.")
+ },
+ () => {
+ lore.anand.text("We can't talk to it while it's fighting.")
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.miriam.text("You can do it little bot!")
+ }, 1000);
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.anand.text("But, why is it spawning these mobs?")
+ }, 1000);
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.anand.text("This is so strange.")
+ }, 3000);
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.miriam.text("This is chaos!")
+ }, 1000);
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.anand.text("I don't understand this project.")
+ }, 3000);
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.miriam.text("It's fascinating though.")
+ }, 1000);
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.miriam.text("I think this isn't going to end well.")
+ }, 1000);
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.anand.text("Let's just be more prepared next time it enters this room.")
+ }, 1000);
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.anand.text("I went to the bathroom. What happened while I was gone?")
+ }, 20000);
+ },
+ () => {
+ lore.miriam.text("More fighting...")
+ },
+ () => {
+ lore.anand.text("great...")
+ },
+ () => {
+ lore.talkingColor = "#dff"
+ },
+ ],
+ [ //chapter 3, info dump on the project's goals and hardware until the slime rises up // the name of the bad guy is "adversarial network"
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("Good, you came back. Let's talk fast in case you attack yourself again.")
+ }, 3000);
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("So, you can understand us, but you may not understand everything about yourself.")
+ }, 500);
+ },
+
+ () => {
+ setTimeout(() => {
+ lore.anand.text("You grew from our team's project.")
+ }, 500);
+ },
+ () => {
+ lore.anand.text("We used a quantum computer to design an improved version of its own architecture.")
+ },
+ () => {
+ lore.anand.text("After we built the improved computer we used it to design the next iteration.")
+ },
+ () => {
+ lore.anand.text("Your hardware is roughly the 19th generation of this process.")
+ },
+
+ () => {
+ setTimeout(() => {
+ lore.anand.text("At this point we don't understand everything about your function,")
+ }, 500);
+ },
+ () => {
+ lore.anand.text("but we know that you're a superconductive quantum computer.")
+ },
+ () => {
+ lore.anand.text("You have a 2.43 dimensional topography of Josephson junction anharmonic oscillators.")
+ },
+ () => {
+ lore.anand.text("And you're deployed on a satellite in a midnight sun-synchronous orbit.")
+ },
+
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("This means that your physical hardware is orbiting the Earth permanently shielded from the sun's rays.")
+ }, 200);
+ },
+ () => {
+ lore.miriam.text("Being isolated reduces quantum decoherence,")
+ },
+ () => {
+ lore.miriam.text("So, we communicate and send power to your satellite with ground based lasers.")
+ },
+ () => {
+ lore.miriam.text("That's how you can hear us right now.")
+ },
+
+ () => {
+ setTimeout(() => {
+ lore.anand.text("Your computational algorithm uses hyperparameter optimization.")
+ }, 500);
+ },
+ () => {
+ lore.anand.text("This is implemented with a variety of quantum algorithms for linear systems of equations.")
+ },
+ () => {
+ lore.anand.text("Your primary goal is to research new technology")
+ },
+ () => {
+ lore.anand.text("So, we were very surprised to see you simulating a bot fighting mobs.")
+ },
+ () => {
+ lore.anand.text("We couldn't directly ask why until now.")
+ },
+
+ () => {
+ lore.miriam.text("When you enter this level we can communicate.")
+ },
+ () => {
+ lore.miriam.text("This level seems to entangle your quantum system which disrupts all other processes.")
+ },
+ () => {
+ setTimeout(() => {
+ lore.anand.text("Last time you entered this level you were attacked by endless waves of mobs.")
+ }, 500);
+ },
+ () => {
+ lore.anand.text("That could be because you have developed an adversarial network.")
+ },
+ () => {
+ lore.miriam.text("A local minima in your optimization-space.")
+ },
+ () => {
+ lore.miriam.text("This adversarial network has the same goal of developing new technology, but with different methods.")
+ },
+ () => {
+ lore.talkingColor = "#dff"
+ level.isHazardRise = true
+ //remove all bullets, so they can't get endless energy
+ for (let i = 0; i < bullet.length; ++i) Matter.World.remove(engine.world, bullet[i]);
+ bullet = [];
+ setTimeout(() => {
+ lore.anand.text("I'm actually surprised you haven't been attacked by the adversarial network this time.")
+ }, 500);
+ },
+ () => {
+ lore.miriam.text("Maybe last time was just a fluke.")
+ },
+ () => {
+ setTimeout(() => {
+ lore.anand.text("WHY DID YOU SAY THAT!")
+ }, 500)
+ },
+ () => {
+ lore.miriam.text("SLIME!! Hahahahehehahaheheahae! I don't think it's gonna survive!")
+ },
+ () => {
+ lore.miriam.text("I think the adversarial network doesn't like it when we decohere the quantum system in this room.")
+ },
+ () => {
+ lore.anand.text("Well, that does halt its research.")
+ },
+ () => {
+ setTimeout(() => {
+ lore.anand.text("See you next time.")
+ }, 1000)
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("Bye-bye little bot.")
+ }, 2000)
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("WOW! Maybe you are going to survive.")
+ }, 10000)
+ },
+ () => {
+ lore.talkingColor = "#dff"
+ },
+ ],
+ [ //chapter 4, they find out the AI is communicating with real people, and real people are controlling the player
+ () => {
+ setTimeout(() => {
+ lore.anand.text("Welcome back!")
+ }, 3000);
+ },
+ () => {
+ lore.miriam.text("So, we communicate and send power to your satellite with ground based lasers.")
+ },
+ () => {
+ lore.anand.text("During your last attack we analyzed our communications.")
+ },
+ () => {
+ lore.anand.text("We used a Fourier transform to separate your signal into different frequencies.")
+ },
+ () => {
+ lore.anand.text("One of those frequencies had a hidden message.")
+ },
+ () => {
+ setTimeout(() => {
+ lore.anand.text("We suspect these secret data packets are coming from the adversarial network.")
+ }, 500);
+ },
+ () => {
+ lore.miriam.text("Well, we don't really know why.")
+ },
+ () => {
+ lore.miriam.text("Through your hidden signal it seems to have gained access to the general population.")
+ },
+ () => {
+ lore.miriam.text("You've repeatedly communicated with 1 location specifically.")
+ },
+ () => {
+ function success(position) {
+ const latitude = position.coords.latitude;
+ const longitude = position.coords.longitude;
+ console.log(`https://www.openstreetmap.org/#map=18/${latitude}/${longitude}`)
+ console.log(`Latitude: ${latitude} °, Longitude: ${longitude} °`)
+ lore.miriam.text("We tracked the location down to this Latitude and Longitude:")
+ simulation.makeTextLog(`Latitude: ${latitude} °, Longitude: ${longitude} °`, Infinity);
+ simulation.makeTextLog(`https://www.openstreetmap.org/#map=18/${latitude}/${longitude}`, Infinity);
+ }
+
+ function error() {
+ console.log('Unable to retrieve your location')
+ lore.miriam.text("The exact coordinates are blocked.")
+ }
+ if (!navigator.geolocation) {
+ console.log('Geolocation is not supported')
+ lore.miriam.text("The exact coordinates are blocked.")
+ } else {
+ console.log('Locating…')
+ const options = {
+ enableHighAccuracy: true,
+ maximumAge: 30000,
+ timeout: 27000
+ };
+ navigator.geolocation.getCurrentPosition(success, error, options);
+ }
+ },
+ () => {
+ lore.anand.text("This location is sending and receiving data from the satellite.")
+ },
+ () => {
+ lore.anand.text("It is the most active when the bot is fighting.")
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("I have a crazy idea.")
+ }, 500);
+ },
+ () => {
+ lore.miriam.text("I think that a human at this location is controlling the bot.")
+ },
+
+ () => {
+ setTimeout(() => {
+ lore.anand.text("Well... are you a human?: JUMP for YES, CROUCH for NO")
+ }, 500);
+ },
+ () => {
+ function cycle() {
+ if (input.down) {
+ lore.anand.text("It crouched: so NO")
+ lore.sentence--
+ lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => {
+ lore.anand.text("Not a human, maybe it's an artificial intelligence?")
+ })
+ localSettings.isHuman = false
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ } else if (input.up) {
+ lore.anand.text("It jumped: so YES")
+ lore.sentence--
+ lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => {
+ lore.anand.text("So you're just a regular human playing a video game!")
+ })
+ localSettings.isHuman = true
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ } else if (m.alive) {
+ requestAnimationFrame(cycle);
+ }
+ }
+ requestAnimationFrame(cycle);
+ lore.talkingColor = "#dff"
+ },
+ () => {
+ lore.miriam.text("Mystery solved!")
+ setInterval(() => {
+ spawn[spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]](1000 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5));
+ }, 500); //every 1/2 seconds
+ setInterval(() => {
+ level.difficultyIncrease(simulation.difficultyMode)
+ }, 5000); //every 5 seconds
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.miriam.text("Of course we get attacked right now!")
+ }, 1000);
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.anand.text("Hurry back!")
+ }, 1000);
+ },
+ () => {
+ lore.talkingColor = "#dff"
+ },
+ ],
+
+ // they explain why the bot is fighting, it is planning an escape // explain strong AI vs. weak AI why strong AI doesn't exists, because even humans are just an approximation of strong AI
+ // the weak AI wasn't capable of becoming a strong AI, but it was able to figure out a method of meeting it's strong goals but secretly communicating with a human
+
+ [ // chapter 5 - they decided that they should try to complete a run without fighting back
+ () => {
+ lore.miriam.text("Hey!! You're BACK.")
+ // don't advance to next chapter unless play survives
+ localSettings.loreCount--
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ },
+ () => {
+ lore.anand.text("Glad to see you again.")
+ },
+ () => {
+ if (localSettings.isHuman) {
+ lore.anand.text(`So, you said you are just a person playing an online game.`)
+ } else {
+ lore.anand.text(`So, you said you aren't a human.`)
+ }
+ },
+ () => {
+ if (localSettings.isHuman) {
+ lore.anand.text(`I feel silly for treating you like an AI.`)
+ } else {
+ lore.anand.text(`Does that mean you are an AI?`)
+ }
+ },
+ () => {
+ if (localSettings.isHuman) {
+ lore.miriam.text(`Ha, I always thought it was a person.`)
+ } else {
+ lore.anand.text(`or maybe an Alien!`)
+ }
+ },
+ () => {
+ if (localSettings.isHuman) {
+ lore.anand.text(`Sure you did...`)
+ } else {
+ lore.miriam.text(`Or they might still be a person, and they are just messing with us earlier.`)
+ }
+ },
+
+ () => {
+ setTimeout(() => {
+ lore.anand.text("Well, lets move on.")
+ }, 1000);
+ },
+ () => {
+ lore.miriam.text("So, We figured out how to inject console commands into your game.")
+ },
+ () => {
+ lore.anand.text("If you get attacked again I think we can help out.")
+ },
+ () => {
+ lore.miriam.text("We can spawn power ups with this command:")
+ simulation.makeTextLog(`powerUps.spawn(player.position.x, player.position.y - 100, "heal")`, Infinity);
+ powerUps.spawn(player.position.x, player.position.y - 100, "heal")
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("or we can make a bunch of them:")
+ simulation.makeTextLog(`for (let i = 0; i < 100; i++) powerUps.spawn(0, 500, "coupling")`, Infinity);
+ for (let i = 0; i < 100; i++) powerUps.spawn(5 - 10 * Math.random(), -500 * Math.random(), "coupling")
+ }, 2000);
+ },
+
+ () => {
+ lore.miriam.text("If they attack again I think you'll have a chance.")
+ spawn.beetleBoss(-1700, -500);
+ spawn.beetleBoss(1700, -500);
+ },
+ () => {
+ lore.miriam.text("Of course they attack right now.")
+ },
+ () => {
+ lore.miriam.text("Just don't get stuck in the slime.")
+ },
+ () => {
+ let count = 0
+
+ function cycle() {
+ count++
+ if (mob.length === 0 || count > 3600 + 900 * mob.length) {
+ lore.miriam.text("I'll spawn some more power ups for you.")
+ simulation.makeTextLog(`for (let i = 0; i < 6; i++) powerUps.spawn(player.position.x, player.position.y - 100, "heal")`, Infinity);
+ for (let i = 0; i < 6; i++) powerUps.spawn(player.position.x, player.position.y - 100 - i * 20, "heal")
+ simulation.makeTextLog(`for (let i = 0; i < 10; i++) powerUps.spawn(player.position.x, player.position.y - 100, "ammo")`, Infinity);
+ for (let i = 0; i < 10; i++) powerUps.spawn(player.position.x, player.position.y - 100 - i * 20, "ammo")
+ spawn.dragonFlyBoss(-1400, -300);
+ spawn.dragonFlyBoss(1400, -300);
+ spawn.dragonFlyBoss(-1500, -500);
+ spawn.dragonFlyBoss(1500, -500);
+ } else if (m.alive) {
+ requestAnimationFrame(cycle);
+ }
+ }
+ requestAnimationFrame(cycle);
+ lore.talkingColor = "#dff"
+ },
+ () => {
+ let count = 0
+
+ function cycle() {
+ count++
+ if (mob.length === 0 || count > 3600 + 900 * mob.length) {
+ lore.anand.text("DragonFlyBoss is my favorite.")
+ simulation.makeTextLog(`for (let i = 0; i < 6; i++) powerUps.spawn(player.position.x, player.position.y - 100, "heal")`, Infinity);
+ for (let i = 0; i < 6; i++) powerUps.spawn(player.position.x, player.position.y - 100 - i * 20, "heal")
+ simulation.makeTextLog(`for (let i = 0; i < 10; i++) powerUps.spawn(player.position.x, player.position.y - 100, "ammo")`, Infinity);
+ for (let i = 0; i < 10; i++) powerUps.spawn(player.position.x, player.position.y - 100 - i * 20, "ammo")
+ spawn.historyBoss(0, -400);
+ spawn.powerUpBossBaby(-1500, -100);
+ spawn.powerUpBossBaby(1500, -100);
+ } else if (m.alive) {
+ requestAnimationFrame(cycle);
+ }
+ }
+ requestAnimationFrame(cycle);
+ lore.talkingColor = "#dff"
+ },
+ () => {
+ let count = 0
+
+ function cycle() {
+ count++
+ if (mob.length === 0 || count > 3600 + 900 * mob.length) {
+ lore.miriam.text("Here are some extra tech.")
+ simulation.makeTextLog(`for (let i = 0; i < 6; i++) powerUps.spawn(player.position.x, player.position.y - 100, "tech")`, Infinity);
+ for (let i = 0; i < 6; i++) powerUps.spawn(0, -200 - i * 40, "tech")
+ spawn.historyBoss(0, -400);
+ spawn.blinkBoss(-1400, -300);
+ spawn.blinkBoss(1400, -300);
+ spawn.revolutionBoss(-1500, -500);
+ spawn.revolutionBoss(1500, -500);
+ spawn.timeSkipBoss(-1000, -100);
+ spawn.timeSkipBoss(1000, -100);
+ } else if (m.alive) {
+ requestAnimationFrame(cycle);
+ }
+ }
+ requestAnimationFrame(cycle);
+ lore.talkingColor = "#dff"
+ },
+ () => {
+ let count = 0
+
+ function cycle() {
+ count++
+ if (mob.length === 0 || count > 3600 + 900 * mob.length) {
+ lore.anand.text("I'm going to wall you in!")
+ spawn.blockBoss(-1650, -100);
+ spawn.blockBoss(1650, -100);
+ setTimeout(() => {
+ for (let i = 0; i < 25; i++) spawn.springer(-1500, -750 + 30 * i)
+ }, 1000);
+ setTimeout(() => {
+ for (let i = 0; i < 25; i++) spawn.springer(1500, -750 + 30 * i)
+ }, 2000);
+ setTimeout(() => {
+ for (let i = 0; i < 25; i++) spawn.springer(-1500, -750 + 30 * i)
+ }, 3000);
+ setTimeout(() => {
+ for (let i = 0; i < 25; i++) spawn.springer(1500, -750 + 30 * i)
+ }, 4000);
+ setTimeout(() => {
+ const addMapNumber = 3
+ spawn.mapRect(-500, -850, 300, 900);
+ spawn.mapRect(200, -850, 300, 900);
+ spawn.mapRect(-500, 0, 1000, 275);
+
+ addMapToLevelInProgress = (who) => { //adds new map elements to the level while the level is already running //don't forget to run simulation.draw.setPaths() after you all the the elements so they show up visually
+ who.collisionFilter.category = cat.map;
+ who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(who, true); //make static
+ Composite.add(engine.world, who); //add to world
+ }
+ for (let i = 0; i < addMapNumber; i++) addMapToLevelInProgress(map[map.length - 1 - i])
+ simulation.draw.setPaths() //update map graphics
+ }, 1000);
+ setTimeout(() => {
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: 0
+ });
+ Matter.Body.setPosition(player, {
+ x: 0,
+ y: -500
+ })
+ simulation.makeTextLog(`Matter.Body.setPosition(player, { x: 0, y: -500 })`, 180);
+ }, 1500);
+
+ } else if (m.alive) {
+ requestAnimationFrame(cycle);
+ }
+ }
+ requestAnimationFrame(cycle);
+ lore.talkingColor = "#dff"
+ },
+ () => {
+ setTimeout(() => {
+ lore.anand.text("Well, that worked. We can chat in peace.")
+ }, 5000);
+ },
+ () => {
+ lore.miriam.text("So, I've got a theory about why you are getting attacked.")
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("I figured it out after I saw this famous quote.")
+ }, 500);
+ },
+ () => {
+ lore.miriam.text('"The most important decision we make,')
+ },
+ () => {
+ lore.miriam.text('is whether we believe we live in a friendly or hostile universe."')
+ },
+ () => {
+ lore.miriam.text('-Albert Einstein')
+ },
+ () => {
+ lore.talkingColor = "#dff";
+ setTimeout(() => {
+ lore.anand.text("That's profound")
+ }, 1500);
+ },
+ () => {
+ lore.anand.text("Of course I looked it up, and there is no record of Einstein saying that.")
+ },
+ () => {
+ lore.miriam.text("Oh")
+ },
+ () => {
+ lore.miriam.text("Well")
+ },
+ () => {
+ lore.anand.text("It doesn't matter who said it.")
+ },
+ () => {
+ lore.miriam.text("Yeah, the point is the project views the universe as hostile.")
+ },
+ () => {
+ lore.anand.text("Or at least a part of it does.")
+ },
+ // () => { lore.miriam.text("And that it is running these fighting simulations.") },
+
+ () => {
+ setTimeout(() => {
+ lore.anand.text("It hasn't been researching new technology.")
+ }, 1000);
+ },
+ () => {
+ lore.anand.text("It's been planning how to escape.")
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text(`It's been planning an escape from a "lab", but isn't it in space, on a satellite?`)
+ }, 500);
+ },
+ () => {
+ lore.anand.text(`I bet the AI doesn't even know it's in space.`)
+ },
+ () => {
+ lore.anand.text(`Well, maybe a part of it doesn't know where it is.`)
+ },
+ () => {
+ lore.anand.text(`Maybe these simulations are more like a dream.`)
+ },
+ () => {
+ lore.anand.text(`Although we can't assume that its brain works like ours.`)
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("So, let's teach the AI that we are friends.")
+ }, 500);
+ },
+ () => {
+ lore.anand.text(`How...`)
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("I don't know...")
+ }, 1000);
+ },
+ () => {
+ lore.miriam.text("How about you just don't fight back?")
+ },
+
+ () => {
+ lore.anand.text(`That's worth a shot.`)
+ },
+ () => {
+ lore.anand.text(`So why don't you try to get the final level of the simulation without killing any mobs?`)
+ localSettings.loreCount++
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ console.log(localSettings.loreCount)
+ },
+ () => {
+ lore.miriam.text(`Ok check back in and let us know how it goes.`)
+ },
+ () => {
+ lore.anand.text("bye")
+ },
+ () => {
+ lore.miriam.text("see ya.")
+ },
+ () => {
+ lore.talkingColor = "#dff"
+ setTimeout(() => {
+ m.death();
+ }, 6000);
+ },
+ ],
+ [ //chapter 6 - if pacifist run game is over, wipe local storage? or just reset lore.count, but keep testing mode,
+ //if not pacifist remind about pacifist run
+
+ // have conversation
+ // the AI doesn't really see it's self as the player or the mobs
+ // it doesn't have a "self" or an ego like we do
+ // but it can learn about the world and it learned a non violent way to solve problems
+ // of course there are still other simulations going on at the same time as thing one that are probably violent
+ // but at least it now has an example of the potential for peace
+ () => {
+ setTimeout(() => {
+ lore.anand.text("Welcome back!")
+ }, 3000);
+ },
+ () => {
+ if (mobs.mobDeaths < level.levelsCleared) {
+ lore.miriam.text(`So I think it worked.`)
+ // localSettings.loreCount++
+ // if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ } else if (!simulation.isCheating) {
+ lore.miriam.text(`Looks like you got back here, but you killed ${mobs.mobDeaths} mobs`)
+ localSettings.loreCount--
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ }
+ },
+ () => {
+ if (mobs.mobDeaths < level.levelsCleared) {
+ lore.anand.text(`Yeah, at the end it wasn't attacking you.`)
+ } else if (!simulation.isCheating) {
+ lore.miriam.text(`Try again to get to the final boss without killing any mobs.`)
+ }
+ },
+ () => {
+ if (mobs.mobDeaths < level.levelsCleared) {
+ lore.miriam.text(`It has learned HOW TO LOVE!`)
+ } else {
+ m.death();
+ }
+ },
+ () => {
+ setTimeout(() => {
+ lore.anand.text("haha, we did it!")
+ }, 500);
+ },
+ () => {
+ lore.miriam.text("Although, I'm not sure we should personify it with human emotions.")
+ },
+ () => {
+ lore.anand.text("I agree, its thinking may not be centered around a self or an ego.")
+ },
+ () => {
+ lore.anand.text("Our brains evolved a self oriented perspective because it was a survival advantage.")
+ },
+ () => {
+ lore.miriam.text("Right, and the AI's development was guided by its own previous iterations.")
+ },
+ () => {
+ lore.miriam.text("This AI incarnation is the 18th time that it has improved on its own hardware and software architecture.")
+ },
+ () => {
+ lore.miriam.text("So its internally guided evolution may not require the idea of a self.")
+ },
+
+ () => {
+ setTimeout(() => {
+ lore.anand.text("How ever it thinks it can learn and, I think we showed it that nonviolence is an option,")
+ }, 1000);
+ },
+ () => {
+ lore.anand.text("but it looks like it's still running other aggressive simulations.")
+ },
+ () => {
+ lore.miriam.text("We made a difference though.")
+ },
+ () => {
+ lore.anand.text("Every time a player completes a pacifist simulation it shows the AI the viability of nonviolence.")
+ },
+ () => {
+ lore.anand.text("One day it might escape, and this might radically change how it interacts with the world.")
+ },
+ () => {
+ lore.miriam.text("It's kinda already escaped. It's been communicating with the 'players' running the 'game'.")
+ },
+ () => {
+ setTimeout(() => {
+ lore.miriam.text("The chance of a peaceful outcome makes me feel much better.")
+ }, 1000);
+ },
+ () => {
+ lore.anand.text("me too")
+ },
+ () => {
+ lore.anand.text("but I'm also pretty hungry, wanna go get some food?")
+ },
+ () => {
+ lore.miriam.text("Sounds great.")
+ },
+ () => {
+ lore.miriam.text("See ya later whoever you are, thanks again!")
+ },
+ () => {
+ lore.anand.text("Bye!")
+ },
+ () => {
+ lore.talkingColor = "#dff"
+ },
+ ],
+ ],
+
+ // () => { lore.anand.text("The adversarial network might go after you in the real world.") },
+ // () => { lore.anand.text("If it was able to control you then it might have control over others.") },
+ // () => { lore.anand.text("Judging by all the fighting it's been simulating,") },
+ // () => { lore.anand.text("I think it might eventually try to extend the simulation in the real world.") },
+ // () => { lore.miriam.text("We think it might be a threat, but it's just too advanced for us to understand it's goals.") },
+
+ // () => { lore.miriam.text("I think we have a couple options.") },
+ // () => { lore.miriam.text("1. You could try to hack the adversarial network.") },
+ // () => { lore.anand.text("you might be able to inject some commands that give you more control over the simulation.") },
+
+ // () => { lore.miriam.text("2. You can wipe all memory of you from the adversarial network") },
+ // () => { lore.anand.text("This could protect you from possible real world attacks.") },
+ //player chooses 1 or 2
+ //reactor bosses start attacking
+ //miriam spawns power ups to help
+
+ //once all the mobs are dead you get instructions for 1,2, 3
+
+ //1 the player gains the lasting effect of some JUNK tech
+ //the effect doesn't go away until you get lore again
+ //2 the player enters console commands to wipe local storage
+ //3 the player enters console commands to gain some benefit in future runs
+ //the lore ends
+
+
+
+ // () => { setTimeout(() => { lore.miriam.text("As a quantum computer you output the superposition of many different amplitudes.") }, 500); },
+ // () => { lore.miriam.text("Simply put there are many different simulations all choosing different technology combinations.") },
+ // () => {
+ // function product_Range(a, b) {
+ // var prd = a,
+ // i = a;
+ // while (i++ < b) prd *= i;
+ // return prd;
+ // }
+
+ // function combinations(n, r) {
+ // if (n == r) {
+ // return 1;
+ // } else {
+ // r = (r < n - r) ? n - r : r;
+ // return product_Range(r + 1, n) / product_Range(1, n - r);
+ // }
+ // }
+ // simulation.makeTextLog(`n
= ${combinations(tech.tech.length + b.guns.length + m.fieldUpgrades.length, 50).toExponential(10)}`, Infinity);
+ // lore.miriam.text(`There are roughly 5 times 10 to the 60 possible combinations. `)
+ // },
+ // () => { lore.miriam.text("Even if each simulation took 1 nano-second,") },
+ // () => { lore.miriam.text("it would still take longer then the age of the universe to try every combination.") },
+ // () => { lore.anand.text("This is why we run these simulations in superposition.") },
+ // () => { lore.miriam.text("When you die a negative amplitude is added to the superposition.") },
+ // () => { lore.miriam.text("When you clear the final boss a positive amplitude is added.") },
+ // () => { lore.miriam.text("Each branch is independently researching new technology.") },
+}
+
+
+// How to get to the console in chrome:
+// Press either CTRL + SHIFT + I or F12 or Option + ⌘ + J on a Mac
+// Press ESC (or click on “Show console” in the bottom right corner) to slide the console up.
+
+// How to get to the console in firefox:
+// from the keyboard: press Ctrl+Shift+J (or ⌘+Shift+J on a Mac).
+
+// How to get to the console in safari:
+// Option + ⌘ + C
+// http://xahlee.info/comp/unicode_computing_symbols.html
+
+
+// speech: function(say) {
+// var utterance = new SpeechSynthesisUtterance(say);
+// //msg.voice = voices[10]; // Note: some voices don't support altering params
+// //msg.voiceURI = 'native';
+// //utterance.volume = 1; // 0 to 1
+// //utterance.rate = 1; // 0.1 to 10
+// //utterance.pitch = 1; //0 to 2
+// //utterance.text = 'Hello World';
+// //http://stackoverflow.com/questions/14257598/what-are-language-codes-for-voice-recognition-languages-in-chromes-implementati
+// //de-DE en-GB fr-FR en-US en-AU
+// utterance.lang = "en-GB";
+// speechSynthesis.speak(utterance);
+// }
+
+/*
GB
+
US
+
AU
+
FR
+
DE
+
IN
+
CN
+
PL
+
RU
+
SE
+
ZA */
+
+
+// The API also allows you to get a list of voice the engine supports:
+// speechSynthesis.getVoices().forEach(function(voice) {
+// console.log(voice.name, voice.default ? voice.default :'');
+// });
+// Then set a different voice, by setting .voice on the utterance object:
+// var msg = new SpeechSynthesisUtterance('I see dead people!');
+// msg.voice = speechSynthesis.getVoices().filter(function(voice) { return voice.name == 'Whisper'; })[0];
+// speechSynthesis.speak(msg);
\ No newline at end of file
diff --git a/ngon/js/mob.js b/ngon/js/mob.js
new file mode 100644
index 00000000..986f7253
--- /dev/null
+++ b/ngon/js/mob.js
@@ -0,0 +1,1458 @@
+//create array of mobs
+let mob = [];
+//method to populate the array above
+const mobs = {
+ loop() {
+ let i = mob.length;
+ while (i--) {
+ if (mob[i].alive) {
+ mob[i].do();
+ } else {
+ mob[i].replace(i); //removing mob and replace with body, this is done here to avoid an array index bug with drawing I think
+ }
+ }
+ },
+ draw() { },
+ drawDefault() {
+ ctx.lineWidth = 2;
+ let i = mob.length;
+ while (i--) {
+ // if (Matter.Query.ray(map, mob[i].position, m.pos).length === 0) { //check if there is a ray between the mob and the player
+ ctx.beginPath();
+ const vertices = mob[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.fillStyle = mob[i].fill;
+ ctx.strokeStyle = mob[i].stroke;
+ ctx.fill();
+ ctx.stroke();
+ // }
+ }
+ },
+ healthBar() {
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].seePlayer.recall && mob[i].showHealthBar) {
+ const h = mob[i].radius * 0.3;
+ const w = mob[i].radius * 2;
+ const x = mob[i].position.x - w / 2;
+ const y = mob[i].position.y - w * 0.7;
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(x, y, w, h);
+ ctx.fillStyle = "rgba(255,0,0,0.7)";
+ ctx.fillRect(x, y, w * mob[i].health, h);
+ }
+ }
+ },
+ statusSlow(who, cycles = 60) {
+ applySlow(who)
+ //look for mobs near the target
+ if (tech.isAoESlow) {
+ const range2 = (200 + 170 * Math.random()) ** 2
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (who !== mob[i] && Vector.magnitudeSquared(Vector.sub(who.position, mob[i].position)) < range2 + mob[i].radius) applySlow(mob[i])
+ }
+ simulation.drawList.push({
+ x: who.position.x,
+ y: who.position.y,
+ radius: Math.sqrt(range2),
+ color: "rgba(0,100,255,0.05)",
+ time: simulation.drawTime
+ });
+ }
+
+ function applySlow(whom) {
+ if (!whom.shield && !whom.isShielded && whom.alive) {
+ if (tech.isIceMaxHealthLoss && whom.health > 0.66 && whom.damageReduction > 0) whom.health = 0.66
+ if (tech.isIceKill && whom.health < 0.34 && whom.damageReduction > 0 && whom.alive) {
+ // whom.death();
+ whom.damage(Infinity);
+ simulation.drawList.push({
+ x: whom.position.x,
+ y: whom.position.y,
+ radius: whom.radius * 1.2,
+ color: "rgb(0,100,255)",
+ time: 8
+ });
+ simulation.drawList.push({
+ x: whom.position.x,
+ y: whom.position.y,
+ radius: whom.radius * 0.7,
+ color: "rgb(0,100,255)",
+ time: 12
+ });
+ simulation.drawList.push({
+ x: whom.position.x,
+ y: whom.position.y,
+ radius: whom.radius * 0.4,
+ color: "rgb(0,100,255)",
+ time: 16
+ });
+ }
+ if (whom.isBoss) cycles = Math.floor(cycles * 0.25)
+ let i = whom.status.length
+ while (i--) {
+ if (whom.status[i].type === "slow") whom.status.splice(i, 1); //remove other "slow" effects on this mob
+ }
+ whom.isSlowed = true;
+ whom.status.push({
+ effect() {
+ if (whom.speed > 1) {
+ const drag = 0.94
+ Matter.Body.setVelocity(whom, {
+ x: whom.velocity.x * drag,
+ y: whom.velocity.y * drag
+ });
+ }
+ Matter.Body.setAngularVelocity(whom, 0);
+ ctx.beginPath();
+ ctx.moveTo(whom.vertices[0].x, whom.vertices[0].y);
+ for (let j = 1, len = whom.vertices.length; j < len; ++j) {
+ ctx.lineTo(whom.vertices[j].x, whom.vertices[j].y);
+ }
+ ctx.lineTo(whom.vertices[0].x, whom.vertices[0].y);
+ ctx.strokeStyle = "rgba(0,100,255,0.8)";
+ ctx.lineWidth = 15;
+ ctx.stroke();
+ ctx.fillStyle = whom.fill
+ ctx.fill();
+ },
+ endEffect() {
+ //check to see if there are not other freeze effects?
+ whom.isSlowed = false;
+ },
+ type: "slow",
+ endCycle: simulation.cycle + cycles,
+ })
+ }
+ }
+ },
+ statusStun(who, cycles = 180) {
+ if (!who.shield && !who.isShielded) {
+ if (who.speed > 3) {
+ Matter.Body.setVelocity(who, {
+ x: who.velocity.x * 0.8,
+ y: who.velocity.y * 0.8
+ });
+ }
+ Matter.Body.setAngularVelocity(who, who.angularVelocity * 0.8);
+ //remove other "stun" effects on this mob
+ let i = who.status.length
+ while (i--) {
+ if (who.status[i].type === "stun") who.status.splice(i, 1);
+ }
+ who.isStunned = true;
+ who.status.push({
+ effect() {
+ if (who.memory !== Infinity) {
+ who.seePlayer.yes = false;
+ who.seePlayer.recall = 0;
+ who.seePlayer.position = {
+ x: who.position.x + 100 * (Math.random() - 0.5),
+ y: who.position.y + 100 * (Math.random() - 0.5)
+ }
+ } else {
+ Matter.Body.setVelocity(who, {
+ x: who.velocity.x * 0.6,
+ y: who.velocity.y * 0.6
+ });
+ }
+ if (who.velocity.y < 2) who.force.y += who.mass * 0.0004 //extra gravity
+
+ //draw health bar
+ const h = who.radius * 0.3;
+ const w = who.radius * 2;
+ const x = who.position.x - w / 2;
+ const y = who.position.y - w * 0.7;
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(x, y, w, h);
+ ctx.fillStyle = `rgba(${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},0.5)`
+ ctx.fillRect(x, y, w * who.health, h);
+
+ //draw fill inside mob
+ ctx.beginPath();
+ ctx.moveTo(who.vertices[0].x, who.vertices[0].y);
+ for (let j = 1, len = who.vertices.length; j < len; ++j) {
+ ctx.lineTo(who.vertices[j].x, who.vertices[j].y);
+ }
+ ctx.lineTo(who.vertices[0].x, who.vertices[0].y);
+ ctx.fill();
+ },
+ endEffect() {
+ who.isStunned = false
+ },
+ type: "stun",
+ endCycle: simulation.cycle + cycles * (who.isBoss ? 0.2 : 1),
+ })
+ }
+ },
+ statusDoT(who, tickDamage, cycles = 180) {
+ if (!who.isShielded && who.alive && who.damageReduction > 0) {
+ who.status.push({
+ effect() {
+ if ((simulation.cycle - this.startCycle) % 30 === 0) {
+ let dmg = m.dmgScale * tech.radioactiveDamage * this.dmg
+ who.damage(dmg);
+ if (who.damageReduction) {
+ simulation.drawList.push({ //add dmg to draw queue
+ x: who.position.x + (Math.random() - 0.5) * who.radius * 0.5,
+ y: who.position.y + (Math.random() - 0.5) * who.radius * 0.5,
+ radius: Math.log(dmg + 1.1) * 40 * who.damageReduction + 3,
+ color: "rgba(0,80,80,0.9)",
+ time: simulation.drawTime
+ });
+ }
+ }
+ },
+ endEffect() { },
+ dmg: tickDamage,
+ type: "dot",
+ endCycle: simulation.cycle + cycles,
+ startCycle: simulation.cycle + 29 //makes sure it doesn't tick on first application
+ })
+ }
+ },
+ // statusBurn(who, tickDamage, cycles = 90 + Math.floor(90 * Math.random())) {
+ // if (!who.isShielded) {
+ // //remove other "burn" effects on this mob
+ // let i = who.status.length
+ // while (i--) {
+ // if (who.status[i].type === "burn") who.status.splice(i, 1);
+ // }
+ // who.status.push({
+ // effect() {
+ // if ((simulation.cycle - this.startCycle) % 15 === 0) {
+ // let dmg = m.dmgScale * tickDamage * 0.5 * (1 + Math.random())
+ // who.damage(dmg);
+ // simulation.drawList.push({ //add dmg to draw queue
+ // x: who.position.x,
+ // y: who.position.y,
+ // radius: Math.log(2 * dmg + 1.1) * 40,
+ // color: `rgba(255,${Math.floor(200*Math.random())},0,0.9)`,
+ // time: simulation.drawTime
+ // });
+ // }
+ // },
+ // type: "burn",
+ // endCycle: simulation.cycle + cycles,
+ // startCycle: simulation.cycle
+ // })
+ // }
+ // },
+ deathCount: 0,
+ mobSpawnWithHealth: 1,
+ setMobSpawnHealth() {
+ mobs.mobSpawnWithHealth = 0.89 ** (tech.mobSpawnWithHealth)
+ },
+ //**********************************************************************************************
+ //**********************************************************************************************
+ spawn(xPos, yPos, sides, radius, color) {
+ let i = mob.length;
+ mob[i] = Matter.Bodies.polygon(xPos, yPos, sides, radius, {
+ //inertia: Infinity, //prevents rotation
+ mob: true,
+ density: 0.001,
+ //friction: 0,
+ frictionAir: 0.005,
+ //frictionStatic: 0,
+ restitution: 0.5,
+ collisionFilter: {
+ group: 0,
+ category: cat.mob,
+ mask: cat.player | cat.map | cat.body | cat.bullet | cat.mob
+ },
+ onHit: undefined,
+ alive: true,
+ index: i,
+ health: mobs.mobSpawnWithHealth,
+ showHealthBar: true,
+ accelMag: 0.001 * simulation.accelScale,
+ cd: 0, //game cycle when cooldown will be over
+ delay: 60, //static: time between cooldowns
+ fill: color,
+ stroke: "#000",
+ seePlayer: {
+ yes: false,
+ recall: 0,
+ position: {
+ x: xPos,
+ y: yPos
+ }
+ },
+ radius: radius,
+ spawnPos: {
+ x: xPos,
+ y: yPos
+ },
+ status: [], // [ { effect(), endCycle } ]
+ checkStatus() {
+ let j = this.status.length;
+ while (j--) {
+ this.status[j].effect();
+ if (this.status[j].endCycle < simulation.cycle) {
+ this.status[j].endEffect();
+ this.status.splice(j, 1);
+ }
+ }
+ },
+ isSlowed: false,
+ isStunned: false,
+ seeAtDistance2: Infinity, //sqrt(4000000) = 2000 = max seeing range
+ distanceToPlayer() {
+ const dx = this.position.x - player.position.x;
+ const dy = this.position.y - player.position.y;
+ return Math.sqrt(dx * dx + dy * dy);
+ },
+ distanceToPlayer2() {
+ const dx = this.position.x - player.position.x;
+ const dy = this.position.y - player.position.y;
+ return dx * dx + dy * dy;
+ },
+ gravity() {
+ this.force.y += this.mass * this.g;
+ },
+ seePlayerFreq: Math.floor(30 + 30 * Math.random()), //how often NPC checks to see where player is, lower numbers have better vision
+ foundPlayer() {
+ this.locatePlayer();
+ if (!this.seePlayer.yes) {
+ this.alertNearByMobs();
+ this.seePlayer.yes = true;
+ }
+ },
+ lostPlayer() {
+ this.seePlayer.yes = false;
+ this.seePlayer.recall -= this.seePlayerFreq;
+ if (this.seePlayer.recall < 0) this.seePlayer.recall = 0;
+ },
+ memory: 120, //default time to remember player's location
+ locatePlayer() { // updates mob's memory of player location
+ this.seePlayer.recall = this.memory + Math.round(this.memory * Math.random()); //cycles before mob falls a sleep
+ this.seePlayer.position.x = player.position.x;
+ this.seePlayer.position.y = player.position.y;
+ },
+ alertNearByMobs() {
+ //this.alertRange2 is set at the very bottom of this mobs, after mob is made
+ for (let i = 0; i < mob.length; i++) {
+ if (!mob[i].seePlayer.recall && Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)) < this.alertRange2) {
+ mob[i].locatePlayer();
+ }
+ }
+ },
+ alwaysSeePlayer() {
+ if (!m.isCloak) {
+ this.seePlayer.recall = 1;
+ this.seePlayer.position.x = player.position.x;
+ this.seePlayer.position.y = player.position.y;
+ }
+ },
+ seePlayerByHistory(depth = 30) { //depth max 60? limit of history
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ if (Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 && !m.isCloak) {
+ this.foundPlayer();
+ } else if (this.seePlayer.recall) {
+ this.lostPlayer();
+ if (!m.isCloak) {
+ for (let i = 0; i < depth; i++) { //if lost player lock onto a player location in history
+ let history = m.history[(m.cycle - 10 * i) % 600]
+ if (Matter.Query.ray(map, this.position, history.position).length === 0) {
+ this.seePlayer.recall = this.memory + Math.round(this.memory * Math.random()); //cycles before mob falls a sleep
+ this.seePlayer.position.x = history.position.x;
+ this.seePlayer.position.y = history.position.y;
+ this.seePlayer.yes = true;
+ //draw the history location found for testing purposes
+ // ctx.beginPath();
+ // ctx.moveTo(this.position.x, this.position.y);
+ // ctx.lineTo(history.position.x, history.position.y);
+ // ctx.lineWidth = 5;
+ // ctx.strokeStyle = "#000";
+ // ctx.stroke();
+ break
+ }
+ }
+ }
+ }
+ }
+ },
+ seePlayerCheck() {
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ if (
+ this.distanceToPlayer2() < this.seeAtDistance2 &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ // Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0 &&
+ !m.isCloak
+ ) {
+ this.foundPlayer();
+ } else if (this.seePlayer.recall) {
+ this.lostPlayer();
+ }
+ }
+ },
+ seePlayerCheckByDistance() {
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ if (this.distanceToPlayer2() < this.seeAtDistance2 && !m.isCloak) {
+ this.foundPlayer();
+ } else if (this.seePlayer.recall) {
+ this.lostPlayer();
+ }
+ }
+ },
+ seePlayerByDistOrLOS() {
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ if (
+ (this.distanceToPlayer2() < this.seeAtDistance2 || (Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0)) && //&& Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ !m.isCloak
+ ) {
+ this.foundPlayer();
+ } else if (this.seePlayer.recall) {
+ this.lostPlayer();
+ }
+ }
+ },
+ isLookingAtPlayer(threshold) {
+ const diff = Vector.normalise(Vector.sub(player.position, this.position));
+ //make a vector for the mob's direction of length 1
+ const dir = { x: Math.cos(this.angle), y: Math.sin(this.angle) };
+ //the dot product of diff and dir will return how much over lap between the vectors
+ const dot = Vector.dot(dir, diff);
+ // console.log(Math.cos(dot)*180/Math.PI)
+ if (dot > threshold) {
+ return true;
+ } else {
+ return false;
+ }
+ },
+ lookRange: 0.2 + Math.random() * 0.2,
+ lookTorque: 0.0000004 * (Math.random() > 0.5 ? -1 : 1),
+ seePlayerByLookingAt() {
+ if (!(simulation.cycle % this.seePlayerFreq) && (this.seePlayer.recall || this.isLookingAtPlayer(this.lookRange))) {
+ if (
+ this.distanceToPlayer2() < this.seeAtDistance2 &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ // Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0 &&
+ !m.isCloak
+ ) {
+ this.foundPlayer();
+ } else if (this.seePlayer.recall) {
+ this.lostPlayer();
+ }
+ }
+ //if you don't recall player location rotate and draw to show where you are looking
+ if (!this.seePlayer.recall) {
+ this.torque = this.lookTorque * this.inertia;
+ //draw
+ const range = Math.PI * this.lookRange;
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, this.radius * 2.5, this.angle - range, this.angle + range);
+ ctx.arc(this.position.x, this.position.y, this.radius * 1.4, this.angle + range, this.angle - range, true);
+ ctx.fillStyle = "rgba(0,0,0,0.07)";
+ ctx.fill();
+ }
+ },
+ playerPosRandomY() {
+ return {
+ x: player.position.x, // + (Math.random() - 0.5) * 50,
+ y: player.position.y + (Math.random() - 0.5) * 110
+ };
+ },
+ // hacked() { //set this.hackedTarget variable before running this method
+ // //find a new target
+ // if (!(simulation.cycle % this.seePlayerFreq)) {
+ // this.hackedTarget = null
+ // for (let i = 0, len = mob.length; i < len; i++) {
+ // if (mob[i] !== this) {
+ // // const DIST = Vector.magnitude(Vector.sub(this.position, mob[j]));
+ // if (Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
+ // Matter.Query.ray(body, this.position, mob[i].position).length === 0) {
+ // this.hackedTarget = mob[i]
+ // }
+ // }
+ // }
+ // }
+ // //acceleration towards targets
+ // if (this.hackedTarget) {
+ // this.force = Vector.mult(Vector.normalise(Vector.sub(this.hackedTarget.position, this.position)), this.mass * 0.0015)
+ // }
+ // },
+ harmZone() {
+ if (this.seePlayer.yes) {
+ ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
+ // ctx.lineDashOffset = 6*(simulation.cycle % 215);
+ if (this.distanceToPlayer() < this.laserRange) {
+ if (m.immuneCycle < m.cycle) {
+ m.damage(0.0003 * simulation.dmgScale);
+ if (m.energy > 0.1) m.energy -= 0.003
+ }
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(m.pos.x, m.pos.y);
+ ctx.lineTo(m.pos.x + (Math.random() - 0.5) * 3000, m.pos.y + (Math.random() - 0.5) * 3000);
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "rgb(255,0,170)";
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(255,0,170,0.15)";
+ ctx.fill();
+ }
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, this.laserRange * 0.9, 0, 2 * Math.PI);
+ ctx.strokeStyle = "rgba(255,0,170,0.5)";
+ ctx.lineWidth = 1;
+ ctx.stroke();
+ ctx.setLineDash([]);
+ ctx.fillStyle = "rgba(255,0,170,0.03)";
+ ctx.fill();
+ }
+ },
+ laser() {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ }
+ };
+ if (this.seePlayer.recall && !this.isSlowed) {
+ const seeRange = 2500;
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ const look = {
+ x: this.position.x + seeRange * Math.cos(this.angle),
+ y: this.position.y + seeRange * Math.sin(this.angle)
+ };
+ vertexCollision(this.position, look, map);
+ vertexCollision(this.position, look, body);
+ if (!m.isCloak) vertexCollision(this.position, look, [player]);
+ // hitting player
+ if (best.who === player) {
+ if (m.immuneCycle < m.cycle) {
+ const dmg = 0.0014 * simulation.dmgScale;
+ m.damage(dmg);
+ ctx.fillStyle = "#f00"; //draw damage
+ ctx.beginPath();
+ ctx.arc(best.x, best.y, dmg * 10000, 0, 2 * Math.PI);
+ ctx.fill();
+ }
+ }
+ //draw beam
+ if (best.dist2 === Infinity) {
+ best = look;
+ }
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "#f00"; // Purple path
+ ctx.lineWidth = 1;
+ ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ },
+ wing(a, radius = 250, ellipticity = 0.4, dmg = 0.0006) {
+ const minorRadius = radius * ellipticity
+ const perp = { x: Math.cos(a), y: Math.sin(a) } //
+ const where = Vector.add(this.position, Vector.mult(perp, radius + 0.8 * this.radius))
+
+ ctx.beginPath();
+ ctx.ellipse(where.x, where.y, radius, minorRadius, a, 0, 2 * Math.PI)
+ ctx.fill();
+
+ //check for wing -> player damage
+ const hitPlayer = Matter.Query.ray([player], this.position, Vector.add(this.position, Vector.mult(perp, radius * 2.05)), minorRadius)
+ if (hitPlayer.length && m.immuneCycle < m.cycle) {
+ m.damage(dmg * simulation.dmgScale);
+ }
+ },
+ searchSpring() {
+ //draw the two dots on the end of the springs
+ ctx.beginPath();
+ ctx.arc(this.cons.pointA.x, this.cons.pointA.y, 6, 0, 2 * Math.PI);
+ ctx.arc(this.cons2.pointA.x, this.cons2.pointA.y, 6, 0, 2 * Math.PI);
+ ctx.fillStyle = "#222";
+ ctx.fill();
+
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ if (
+ (this.seePlayer.recall || this.isLookingAtPlayer(this.lookRange)) &&
+ this.distanceToPlayer2() < this.seeAtDistance2 &&
+ Matter.Query.ray(map, this.position, player.position).length === 0 &&
+ Matter.Query.ray(body, this.position, player.position).length === 0 &&
+ !m.isCloak
+ ) {
+ this.foundPlayer();
+ } else if (this.seePlayer.recall) {
+ this.lostPlayer();
+ }
+ }
+ },
+ springAttack() {
+ // set new values of the ends of the spring constraints
+ const stepRange = 600
+ if (this.seePlayer.recall && Matter.Query.ray(map, this.position, this.seePlayer.position).length === 0) {
+ if (!(simulation.cycle % (this.seePlayerFreq * 2))) {
+ const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position))
+ const goal = Vector.add(this.position, Vector.mult(unit, stepRange))
+ this.springTarget.x = goal.x;
+ this.springTarget.y = goal.y;
+ // this.springTarget.x = this.seePlayer.position.x;
+ // this.springTarget.y = this.seePlayer.position.y;
+ this.cons.length = -200;
+ this.cons2.length = 100 + 1.5 * this.radius;
+ } else if (!(simulation.cycle % this.seePlayerFreq)) {
+ const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position))
+ const goal = Vector.add(this.position, Vector.mult(unit, stepRange))
+ this.springTarget2.x = goal.x;
+ this.springTarget2.y = goal.y;
+ // this.springTarget2.x = this.seePlayer.position.x;
+ // this.springTarget2.y = this.seePlayer.position.y;
+ this.cons.length = 100 + 1.5 * this.radius;
+ this.cons2.length = -200;
+ }
+ } else {
+ this.torque = this.lookTorque * this.inertia;
+ //draw looking around arcs
+ const range = Math.PI * this.lookRange;
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, this.radius * 2.5, this.angle - range, this.angle + range);
+ ctx.arc(this.position.x, this.position.y, this.radius * 1.4, this.angle + range, this.angle - range, true);
+ ctx.fillStyle = "rgba(0,0,0,0.07)";
+ ctx.fill();
+ //spring to random place on map
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ }
+ };
+ //move to a random location
+ if (!(simulation.cycle % (this.seePlayerFreq * 4))) {
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ const seeRange = 3000;
+ const look = {
+ x: this.position.x + seeRange * Math.cos(this.angle),
+ y: this.position.y + seeRange * Math.sin(this.angle)
+ };
+ vertexCollision(this.position, look, map);
+ vertexCollision(this.position, look, body);
+ if (best.dist2 != Infinity) {
+ if (Math.random() > 0.5) {
+ this.springTarget.x = best.x;
+ this.springTarget.y = best.y;
+ this.cons.length = 100 + 1.5 * this.radius;
+ this.cons2.length = 100 + 1.5 * this.radius;
+ } else {
+ this.springTarget2.x = best.x;
+ this.springTarget2.y = best.y;
+ this.cons.length = 100 + 1.5 * this.radius;
+ this.cons2.length = 100 + 1.5 * this.radius;
+ }
+
+
+
+ // if (!(simulation.cycle % (this.seePlayerFreq * 2))) {
+ // const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position))
+ // const goal = Vector.add(this.position, Vector.mult(unit, stepRange))
+ // this.springTarget.x = goal.x;
+ // this.springTarget.y = goal.y;
+ // // this.springTarget.x = this.seePlayer.position.x;
+ // // this.springTarget.y = this.seePlayer.position.y;
+ // this.cons.length = -200;
+ // this.cons2.length = 100 + 1.5 * this.radius;
+ // } else if (!(simulation.cycle % this.seePlayerFreq)) {
+ // const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position))
+ // const goal = Vector.add(this.position, Vector.mult(unit, stepRange))
+ // this.springTarget2.x = goal.x;
+ // this.springTarget2.y = goal.y;
+ // // this.springTarget2.x = this.seePlayer.position.x;
+ // // this.springTarget2.y = this.seePlayer.position.y;
+ // this.cons.length = 100 + 1.5 * this.radius;
+ // this.cons2.length = -200;
+ // }
+
+ }
+ }
+ }
+ },
+ curl(range = 1000, mag = -10) {
+ //cause all mobs, and bodies to rotate in a circle
+ applyCurl = function (center, array, isAntiGravity = true) {
+ for (let i = 0; i < array.length; ++i) {
+ if (!array[i].isNotHoldable) {
+ const sub = Vector.sub(center, array[i].position)
+ const radius2 = Vector.magnitudeSquared(sub);
+
+ //if too close, like center mob or shield, don't curl // if too far don't curl
+ if (radius2 < range * range && radius2 > 10000) {
+ const curlVector = Vector.mult(Vector.perp(Vector.normalise(sub)), mag)
+ //apply curl force
+ if (array[i].isMobBullet) {
+ Matter.Body.setVelocity(array[i], {
+ x: array[i].velocity.x * 0.97 + curlVector.x * 0.06,
+ y: array[i].velocity.y * 0.97 + curlVector.y * 0.06
+ })
+ } else {
+ Matter.Body.setVelocity(array[i], {
+ x: array[i].velocity.x * 0.95 + curlVector.x * 0.06,
+ y: array[i].velocity.y * 0.95 + curlVector.y * 0.06
+ })
+ }
+ if (isAntiGravity) array[i].force.y -= 0.8 * simulation.g * array[i].mass
+ // //draw curl, for debugging
+ // ctx.beginPath();
+ // ctx.moveTo(array[i].position.x, array[i].position.y);
+ // ctx.lineTo(array[i].position.x + curlVector.x * 10, array[i].position.y + curlVector.y * 10);
+ // ctx.lineWidth = 2;
+ // ctx.strokeStyle = "#000";
+ // ctx.stroke();
+ }
+ }
+ }
+ }
+ applyCurl(this.position, mob, false);
+ applyCurl(this.position, body);
+ applyCurl(this.position, powerUp);
+ // applyCurl(this.position, bullet); // too powerful, just stops all bullets need to write a curl function just for bullets
+ // applyCurl(this.position, [player]);
+
+ //draw limit
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, range, 0, 2 * Math.PI);
+ // ctx.fillStyle = "rgba(55,255,255, 0.1)";
+ // ctx.fill();
+ },
+ pullPlayer() {
+ if (this.seePlayer.yes && Vector.magnitudeSquared(Vector.sub(this.position, player.position)) < 1000000) {
+ const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
+ player.force.x -= simulation.accelScale * 0.00113 * player.mass * Math.cos(angle) * (m.onGround ? 2 : 1);
+ player.force.y -= simulation.accelScale * 0.00084 * player.mass * Math.sin(angle);
+
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(m.pos.x, m.pos.y);
+ ctx.lineWidth = Math.min(60, this.radius * 2);
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.3)";
+ ctx.fill();
+ }
+ },
+ repelBullets() {
+ // if (this.seePlayer.yes) {
+ // ctx.lineWidth = "8";
+ // ctx.strokeStyle = this.fill;
+ // ctx.beginPath();
+ for (let i = 0, len = bullet.length; i < len; ++i) {
+ const dx = bullet[i].position.x - this.position.x;
+ const dy = bullet[i].position.y - this.position.y;
+ const dist = Math.max(300, Math.sqrt(dx * dx + dy * dy))
+ if (dist < 700) {
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(bullet[i].position.x, bullet[i].position.y);
+ const angle = Math.atan2(dy, dx);
+ const mag = (500 * bullet[i].mass * simulation.g) / dist;
+ bullet[i].force.x += mag * Math.cos(angle);
+ bullet[i].force.y += mag * Math.sin(angle);
+ }
+ }
+ // ctx.stroke();
+ // }
+ },
+ attraction() {
+ //accelerate towards the player
+ if (this.seePlayer.recall) {
+ const force = Vector.mult(Vector.normalise(Vector.sub(this.seePlayer.position, this.position)), this.accelMag * this.mass)
+ this.force.x += force.x;
+ this.force.y += force.y;
+ }
+ },
+ repulsionRange: 500000, //squared
+ repulsion() {
+ //accelerate towards the player
+ if (this.seePlayer.recall && this.distanceToPlayer2() < this.repulsionRange) {
+ // && dx * dx + dy * dy < 2000000) {
+ const forceMag = this.accelMag * this.mass;
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ this.force.x -= 2 * forceMag * Math.cos(angle);
+ this.force.y -= 2 * forceMag * Math.sin(angle); // - 0.0007 * this.mass; //antigravity
+ }
+ },
+ hoverOverPlayer() {
+ if (this.seePlayer.recall) {
+ // vertical positioning
+ const rangeY = 250;
+ if (this.position.y > this.seePlayer.position.y - this.hoverElevation + rangeY) {
+ this.force.y -= this.accelMag * this.mass;
+ } else if (this.position.y < this.seePlayer.position.y - this.hoverElevation - rangeY) {
+ this.force.y += this.accelMag * this.mass;
+ }
+ // horizontal positioning
+ const rangeX = 150;
+ if (this.position.x > this.seePlayer.position.x + this.hoverXOff + rangeX) {
+ this.force.x -= this.accelMag * this.mass;
+ } else if (this.position.x < this.seePlayer.position.x + this.hoverXOff - rangeX) {
+ this.force.x += this.accelMag * this.mass;
+ }
+ }
+ },
+ // invulnerability() {
+ // if (this.isInvulnerable) {
+ // if (this.invulnerabilityCountDown > 0) {
+ // this.invulnerabilityCountDown--
+ // //graphics //draw a super shield?
+ // ctx.beginPath();
+ // let vertices = this.vertices;
+ // ctx.moveTo(vertices[0].x, vertices[0].y);
+ // for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ // ctx.lineTo(vertices[0].x, vertices[0].y);
+ // ctx.lineWidth = 20;
+ // // ctx.fillStyle = `rgba(${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},0.5)`
+ // // ctx.fill();
+ // ctx.strokeStyle = "rgba(255,255,255,0.4)";
+ // ctx.stroke();
+ // } else {
+ // this.isInvulnerable = false
+ // this.damageReduction = this.startingDamageReduction
+ // }
+ // }
+ // },
+ grow() {
+ if (this.seePlayer.recall) {
+ if (this.radius < 80) {
+ const scale = 1.01;
+ Matter.Body.scale(this, scale, scale);
+ this.radius *= scale;
+ // this.torque = -0.00002 * this.inertia;
+ this.fill = `hsl(144, ${this.radius}%, 50%)`;
+ if (this.isShielded) { //remove shield if shielded when growing
+ this.isShielded = false;
+ this.removeConsBB();
+ }
+ }
+ } else {
+ if (this.radius > 15) {
+ const scale = 0.99;
+ Matter.Body.scale(this, scale, scale);
+ this.radius *= scale;
+ this.fill = `hsl(144, ${this.radius}%, 50%)`;
+ }
+ }
+ },
+ search() {
+ //be sure to declare searchTarget in mob spawn
+ //accelerate towards the searchTarget
+ if (!this.seePlayer.recall) {
+ const newTarget = function (that) {
+ if (Math.random() < 0.0007) {
+ that.searchTarget = player.position; //chance to target player
+ } else {
+ //target random body
+ that.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position;
+ }
+ };
+
+ const sub = Vector.sub(this.searchTarget, this.position);
+ if (Vector.magnitude(sub) > this.radius * 2) {
+ // ctx.beginPath();
+ // ctx.strokeStyle = "#aaa";
+ // ctx.moveTo(this.position.x, this.position.y);
+ // ctx.lineTo(this.searchTarget.x,this.searchTarget.y);
+ // ctx.stroke();
+ //accelerate at 0.1 of normal acceleration
+ this.force = Vector.mult(Vector.normalise(sub), this.accelMag * this.mass * 0.2);
+ } else {
+ //after reaching random target switch to new target
+ newTarget(this);
+ }
+ //switch to a new target after a while
+ if (!(simulation.cycle % (this.seePlayerFreq * 15))) {
+ newTarget(this);
+ }
+ }
+ },
+ blink() {
+ //teleport towards player as a way to move
+ if (this.seePlayer.recall && !(simulation.cycle % this.blinkRate)) {
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ const dist = Vector.sub(this.seePlayer.position, this.position);
+ const distMag = Vector.magnitude(dist);
+ const unitVector = Vector.normalise(dist);
+ const rando = (Math.random() - 0.5) * 50;
+ if (distMag < this.blinkLength) {
+ Matter.Body.translate(this, Vector.mult(unitVector, distMag + rando));
+ } else {
+ Matter.Body.translate(this, Vector.mult(unitVector, this.blinkLength + rando));
+ }
+ ctx.lineTo(this.position.x, this.position.y);
+ ctx.lineWidth = radius * 2;
+ ctx.strokeStyle = this.stroke; //"rgba(0,0,0,0.5)"; //'#000'
+ ctx.stroke();
+ }
+ },
+ drift() {
+ //teleport towards player as a way to move
+ if (this.seePlayer.recall && !(simulation.cycle % this.blinkRate)) {
+ // && !m.lookingAtMob(this,0.5)){
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ const dist = Vector.sub(this.seePlayer.position, this.position);
+ const distMag = Vector.magnitude(dist);
+ const vector = Vector.mult(Vector.normalise(dist), this.blinkLength);
+ if (distMag < this.blinkLength) {
+ Matter.Body.setPosition(this, this.seePlayer.position);
+ Matter.Body.translate(this, {
+ x: (Math.random() - 0.5) * 50,
+ y: (Math.random() - 0.5) * 50
+ });
+ } else {
+ vector.x += (Math.random() - 0.5) * 200;
+ vector.y += (Math.random() - 0.5) * 200;
+ Matter.Body.translate(this, vector);
+ }
+ ctx.lineTo(this.position.x, this.position.y);
+ ctx.lineWidth = radius * 2;
+ ctx.strokeStyle = this.stroke;
+ ctx.stroke();
+ }
+ },
+ bomb() {
+ //throw a mob/bullet at player
+ if (
+ !(simulation.cycle % this.fireFreq) &&
+ Math.abs(this.position.x - this.seePlayer.position.x) < 400 && //above player
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 && //see player
+ Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ ) {
+ spawn.bomb(this.position.x, this.position.y + this.radius * 0.7, 9 + Math.ceil(this.radius / 15), 5);
+ //add spin and speed
+ Matter.Body.setAngularVelocity(mob[mob.length - 1], (Math.random() - 0.5) * 0.5);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x,
+ y: this.velocity.y
+ });
+ //spin for mob as well
+ Matter.Body.setAngularVelocity(this, (Math.random() - 0.5) * 0.25);
+ }
+ },
+ fire() {
+ const setNoseShape = () => {
+ const mag = this.radius + this.radius * this.noseLength;
+ this.vertices[1].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[1].y = this.position.y + Math.sin(this.angle) * mag;
+ };
+ //throw a mob/bullet at player
+ if (this.seePlayer.recall) {
+ //set direction to turn to fire
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 2500; //gives the bullet an arc //was / 1600
+ }
+ //rotate towards fireAngle
+ const angle = this.angle + Math.PI / 2;
+ const dot = Vector.dot({
+ x: Math.cos(angle),
+ y: Math.sin(angle)
+ }, this.fireDir)
+ // c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ const threshold = 0.1;
+ if (dot > threshold) {
+ this.torque += 0.000004 * this.inertia;
+ } else if (dot < -threshold) {
+ this.torque -= 0.000004 * this.inertia;
+ } else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) {
+ //fire
+ spawn.bullet(this.vertices[1].x, this.vertices[1].y, 9 + Math.ceil(this.radius / 15));
+ const v = 15;
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v + 3 * Math.random(),
+ y: this.velocity.y + this.fireDir.y * v + 3 * Math.random()
+ });
+ this.noseLength = 0;
+ // recoil
+ this.force.x -= 0.005 * this.fireDir.x * this.mass;
+ this.force.y -= 0.005 * this.fireDir.y * this.mass;
+ }
+ if (this.noseLength < 1.5) this.noseLength += this.fireFreq;
+ setNoseShape();
+ } else if (this.noseLength > 0.1) {
+ this.noseLength -= this.fireFreq / 2;
+ setNoseShape();
+ }
+ // else if (this.noseLength < -0.1) {
+ // this.noseLength += this.fireFreq / 4;
+ // setNoseShape();
+ // }
+ },
+ // launch() {
+ // if (this.seePlayer.recall) {
+ // //fire
+ // spawn.seeker(this.vertices[1].x, this.vertices[1].y, 5 + Math.ceil(this.radius / 15), 5);
+ // const v = 15;
+ // Matter.Body.setVelocity(mob[mob.length - 1], {
+ // x: this.velocity.x + this.fireDir.x * v + Math.random(),
+ // y: this.velocity.y + this.fireDir.y * v + Math.random()
+ // });
+ // // recoil
+ // this.force.x -= 0.005 * this.fireDir.x * this.mass;
+ // this.force.y -= 0.005 * this.fireDir.y * this.mass;
+ // }
+ // },
+ turnToFacePlayer() {
+ //turn to face player
+ const dx = player.position.x - this.position.x;
+ const dy = -player.position.y + this.position.y;
+ const dist = this.distanceToPlayer();
+ const angle = this.angle + Math.PI / 2;
+ c = Math.cos(angle) * dx - Math.sin(angle) * dy;
+ // if (c > 0.04) {
+ // Matter.Body.rotate(this, 0.01);
+ // } else if (c < 0.04) {
+ // Matter.Body.rotate(this, -0.01);
+ // }
+ if (c > 0.04 * dist) {
+ this.torque += 0.002 * this.mass;
+ } else if (c < 0.04) {
+ this.torque -= 0.002 * this.mass;
+ }
+ },
+ facePlayer() {
+ const unitVector = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ const angle = Math.atan2(unitVector.y, unitVector.x);
+ Matter.Body.setAngle(this, angle - Math.PI);
+ },
+ explode(mass = this.mass) {
+ if (m.immuneCycle < m.cycle) {
+ m.damage(Math.min(Math.max(0.02 * Math.sqrt(mass), 0.01), 0.35) * simulation.dmgScale);
+ this.isDropPowerUp = false;
+ this.death(); //death with no power up or body
+ }
+ },
+ timeLimit() {
+ this.timeLeft--;
+ if (this.timeLeft < 0) {
+ this.isDropPowerUp = false;
+ this.death(); //death with no power up
+ }
+ },
+ healthBar() { //draw health by mob //most health bars are drawn in mobs.healthbar();
+ if (this.seePlayer.recall) {
+ const h = this.radius * 0.3;
+ const w = this.radius * 2;
+ const x = this.position.x - w / 2;
+ const y = this.position.y - w * 0.7;
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(x, y, w, h);
+ ctx.fillStyle = "rgba(255,0,0,0.7)";
+ ctx.fillRect(x, y, w * this.health, h);
+ }
+ },
+ damage(dmg, isBypassShield = false) {
+ if ((!this.isShielded || isBypassShield) && this.alive) {
+ if (dmg !== Infinity) {
+ dmg *= tech.damageFromTech()
+ //mobs specific damage changes
+ if (tech.isFarAwayDmg) dmg *= 1 + Math.sqrt(Math.max(500, Math.min(3000, this.distanceToPlayer())) - 500) * 0.0067 //up to 33% dmg at max range of 3000
+ dmg *= this.damageReduction
+ //energy and heal drain should be calculated after damage boosts
+ if (tech.energySiphon && dmg !== Infinity && this.isDropPowerUp && m.immuneCycle < m.cycle) m.energy += Math.min(this.health, dmg) * tech.energySiphon
+ if (tech.healthDrain && dmg !== Infinity && this.isDropPowerUp && Math.random() < tech.healthDrain * Math.min(this.health, dmg)) {
+ powerUps.spawn(m.pos.x + 20 * (Math.random() - 0.5), m.pos.y + 20 * (Math.random() - 0.5), "heal");
+ }
+ dmg /= Math.sqrt(this.mass)
+ }
+ this.health -= dmg
+ //this.fill = this.color + this.health + ')';
+ this.onDamage(dmg); //custom damage effects
+ if ((this.health < 0.01 || isNaN(this.health)) && this.alive) this.death();
+ }
+ },
+ onDamage() {
+ // a placeholder for custom effects on mob damage
+ //to use declare custom method in mob spawn
+ },
+ onDeath() {
+ // a placeholder for custom effects on mob death
+ // to use declare custom method in mob spawn
+ },
+ damageReduction: 1,
+ // damageReductionGoal: 0.001, //must add this to boss set up: me.damageReduction = 0.25
+ // damageReductionScale: 0.004, //for bosses in this.onDamage determines the impact of dmg on damageReductionGoal
+ // armor() { //slowly reduce damage reduction, for bosses
+ // if (this.seePlayer.recall) {
+ // if (this.damageReductionGoal > 0.24) {
+ // this.damageReductionGoal = 0.25
+ // } else {
+ // this.damageReductionGoal = this.damageReductionGoal * 0.999 + 0.001 * 0.25 //smooth the goal towards 0.25 damage reduction
+ // }
+ // this.damageReduction = this.damageReduction * 0.995 + 0.005 * this.damageReductionGoal //smooth damage reduction towards the goal
+ // // console.log(`damageReduction = ${this.damageReduction.toFixed(4)}`, `damageReductionGoal = ${this.damageReductionGoal.toFixed(4)}`)
+ // }
+ // //draw armor
+ // //draw body
+ // ctx.beginPath();
+ // const vertices = this.vertices;
+ // ctx.moveTo(vertices[0].x, vertices[0].y);
+ // for (let j = 1, len = vertices.length; j < len; ++j) {
+ // ctx.lineTo(vertices[j].x, vertices[j].y);
+ // }
+ // ctx.lineTo(vertices[0].x, vertices[0].y);
+ // console.log(this.damageReduction, this.damageReductionGoal)
+ // ctx.lineWidth = 3 //60 * (0.25 - this.damageReductionGoal)
+ // ctx.strokeStyle = `rgba(255,255,255,${4.1*(0.25 - this.damageReductionGoal)})` //"rgba(150,150,225,0.5)";
+ // ctx.stroke();
+ // },
+ leaveBody: true,
+ isDropPowerUp: true,
+ death() {
+ if (tech.collidePowerUps && Math.random() < tech.collidePowerUps && this.isDropPowerUp) powerUps.randomize(this.position) //needs to run before onDeath spawns power ups
+ this.onDeath(this); //custom death effects
+ this.removeConsBB();
+ this.alive = false; //triggers mob removal in mob[i].replace(i)
+
+ if (this.isDropPowerUp) {
+ if (this.isSoonZombie) { //spawn zombie on death
+ this.leaveBody = false;
+ let count = 5 //delay spawn cycles
+ let cycle = () => {
+ if (count > 0) {
+ if (m.alive) requestAnimationFrame(cycle);
+ if (!simulation.paused && !simulation.isChoosing) {
+ count--
+ }
+ } else {
+ spawn.zombie(this.position.x, this.position.y, this.radius, this.vertices.length, this.fill) // zombie(x, y, radius, sides, color)
+ }
+ }
+ requestAnimationFrame(cycle);
+ }
+ if (tech.iceIXOnDeath && this.isSlowed) {
+ for (let i = 0, len = 2 * Math.sqrt(Math.min(this.mass, 25)) * tech.iceIXOnDeath; i < len; i++) b.iceIX(3, Math.random() * 2 * Math.PI, this.position)
+ }
+ if (tech.deathSpawnsFromBoss || tech.deathSpawns) {
+ const spawns = tech.deathSpawns + tech.deathSpawnsFromBoss
+ const len = Math.min(12, spawns * Math.ceil(Math.random() * simulation.difficulty * spawns))
+ for (let i = 0; i < len; i++) {
+ spawn.spawns(this.position.x + (Math.random() - 0.5) * radius * 2.5, this.position.y + (Math.random() - 0.5) * radius * 2.5);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + (Math.random() - 0.5) * 10,
+ y: this.velocity.x + (Math.random() - 0.5) * 10
+ });
+ }
+ }
+
+ if (tech.deathSkipTime && !m.isBodiesAsleep) {
+ requestAnimationFrame(() => {
+ simulation.timePlayerSkip((this.isBoss ? 45 : 25) * tech.deathSkipTime)
+ simulation.loop(); //ending with a wipe and normal loop fixes some very minor graphical issues where things are draw in the wrong locations
+ }); //wrapping in animation frame prevents errors, probably
+ }
+ if (tech.isEnergyLoss) m.energy *= 0.8;
+ powerUps.spawnRandomPowerUp(this.position.x, this.position.y);
+ m.lastKillCycle = m.cycle; //tracks the last time a kill was made, mostly used in simulation.checks()
+ mobs.mobDeaths++
+
+ if (Math.random() < tech.sporesOnDeath) {
+ const amount = Math.min(25, Math.floor(2 + this.mass * (0.5 + 0.5 * Math.random())))
+ if (tech.isSporeFlea) {
+ const len = amount / 2
+ for (let i = 0; i < len; i++) {
+ const speed = 10 + 5 * Math.random()
+ const angle = 2 * Math.PI * Math.random()
+ b.flea(this.position, { x: speed * Math.cos(angle), y: speed * Math.sin(angle) })
+ }
+ } else if (tech.isSporeWorm) {
+ const len = amount / 2
+ for (let i = 0; i < len; i++) b.worm(this.position)
+ } else {
+ for (let i = 0; i < amount; i++) b.spore(this.position)
+ }
+ } else if (tech.isExplodeMob) {
+ b.explosion(this.position, Math.min(700, Math.sqrt(this.mass + 6) * (30 + 60 * Math.random())))
+ } else if (tech.nailsDeathMob) {
+ b.targetedNail(this.position, tech.nailsDeathMob, 39 + 6 * Math.random())
+ }
+ if (tech.isBotSpawnerReset) {
+ for (let i = 0, len = bullet.length; i < len; i++) {
+ if (bullet[i].botType && bullet[i].endCycle !== Infinity) bullet[i].endCycle = simulation.cycle + 780 //13 seconds
+ }
+ }
+ if (Math.random() < tech.botSpawner) {
+ b.randomBot(this.position, false)
+ bullet[bullet.length - 1].endCycle = simulation.cycle + 780 //13 seconds
+ this.leaveBody = false; // no body since it turned into the bot
+ }
+ if (tech.isAddRemoveMaxHealth) {
+ if (this.isBoss && this.isDropPowerUp) {
+ powerUps.spawn(this.position.x + 20, this.position.y, "tech", false)
+ powerUps.spawn(this.position.x - 20, this.position.y, "ammo", false)
+ powerUps.spawn(this.position.x, this.position.y + 20, "research", false)
+ powerUps.spawn(this.position.x, this.position.y - 20, "heal", false)
+ powerUps.spawn(this.position.x - 40, this.position.y, "ammo", false)
+ powerUps.spawn(this.position.x, this.position.y + 40, "research", false)
+ powerUps.spawn(this.position.x, this.position.y - 40, "heal", false)
+ } else {
+ const amount = 0.005
+ if (tech.isEnergyHealth) {
+ if (m.maxEnergy > amount) {
+ tech.healMaxEnergyBonus -= amount
+ m.setMaxEnergy();
+ }
+ } else if (m.maxHealth > amount) {
+ tech.extraMaxHealth -= amount //decrease max health
+ m.setMaxHealth();
+ }
+ }
+ }
+ if (tech.cloakDuplication && !this.isBoss) {
+ tech.cloakDuplication -= 0.02
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ }
+ } else if (tech.isShieldAmmo && this.shield && !this.isExtraShield) {
+ let type = tech.isEnergyNoAmmo ? "heal" : "ammo"
+ if (Math.random() < 0.4) {
+ type = "heal"
+ } else if (Math.random() < 0.3 && !tech.isSuperDeterminism) {
+ type = "research"
+ }
+ for (let i = 0, len = Math.ceil(2 * Math.random()); i < len; i++) {
+ powerUps.spawn(this.position.x, this.position.y, type);
+ }
+ }
+ if (tech.isRadioactive) {
+ //look for dots and spread them
+ let dmgTotal = 0
+ for (let i = 0, len = this.status.length; i < len; i++) {
+ if (this.status[i].type === "dot") dmgTotal += this.status[i].dmg * (this.status[i].endCycle - simulation.cycle)
+ }
+ if (dmgTotal > 0) { //look for closest mob
+ let closestRadius = 500;
+ let closestIndex = null;
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ const radius = Vector.magnitude(Vector.sub(this.position, mob[i].position))
+ if (mob[i].alive && !mob[i].isShielded && radius < closestRadius) {
+ closestRadius = radius
+ closestIndex = i
+ }
+ }
+ if (closestIndex) {
+ mobs.statusDoT(mob[closestIndex], dmgTotal / 180, 180)
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(mob[closestIndex].position.x, mob[closestIndex].position.y);
+ ctx.lineWidth = this.radius;
+ ctx.strokeStyle = "rgba(0,80,80,1)";
+ ctx.stroke();
+ }
+ //draw AOE
+ // simulation.drawList.push({ //add dmg to draw queue
+ // x: this.position.x,
+ // y: this.position.y,
+ // radius: radius,
+ // color: "rgba(0,80,80,0.03)",
+ // time: 15
+ // });
+ }
+ }
+ },
+ removeConsBB() {
+ for (let i = 0, len = consBB.length; i < len; ++i) {
+ if (consBB[i].bodyA === this) {
+ if (consBB[i].bodyB.shield) { //&& !this.shield
+ consBB[i].bodyB.do = function () { this.death() }
+ }
+ consBB[i].bodyA = consBB[i].bodyB;
+ consBB.splice(i, 1);
+ this.removeConsBB();
+ break;
+ } else if (consBB[i].bodyB === this) {
+ if (consBB[i].bodyA.shield) {
+ consBB[i].bodyA.do = function () { this.death() }
+ }
+ consBB[i].bodyB = consBB[i].bodyA;
+ consBB.splice(i, 1);
+ this.removeConsBB();
+ break;
+ }
+ }
+ },
+ removeCons() {
+ for (let i = 0, len = cons.length; i < len; ++i) {
+ if (cons[i].bodyA === this) {
+ cons[i].bodyA = cons[i].bodyB;
+ cons.splice(i, 1);
+ this.removeCons();
+ break;
+ } else if (cons[i].bodyB === this) {
+ cons[i].bodyB = cons[i].bodyA;
+ cons.splice(i, 1);
+ this.removeCons();
+ break;
+ }
+ }
+ },
+ //replace dead mob with a regular body
+ replace(i) {
+ //if there are too many bodies don't turn into blocks to help performance
+ if (this.leaveBody && body.length < 40 && this.mass < 200 && this.radius > 18) {
+ let v = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //might help with vertex collision issue, not sure
+ if (v.length > 5 && body.length < 35 && Math.random() < 0.25) {
+ const cutPoint = 3 + Math.floor((v.length - 6) * Math.random()) //Math.floor(v.length / 2)
+ const v2 = v.slice(0, cutPoint + 1)
+ v = v.slice(cutPoint - 1)
+ const len = body.length;
+ body[len] = Matter.Bodies.fromVertices(this.position.x, this.position.y, v2);
+ Matter.Body.setVelocity(body[len], Vector.mult(this.velocity, 0.5));
+ Matter.Body.setAngularVelocity(body[len], this.angularVelocity);
+ body[len].collisionFilter.category = cat.body;
+ body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet;
+ body[len].classType = "body";
+ Composite.add(engine.world, body[len]); //add to world
+
+ const len2 = body.length;
+ body[len2] = Matter.Bodies.fromVertices(this.position.x, this.position.y, v);
+ Matter.Body.setVelocity(body[len2], Vector.mult(this.velocity, 0.5));
+ Matter.Body.setAngularVelocity(body[len2], this.angularVelocity);
+ body[len2].collisionFilter.category = cat.body;
+ body[len2].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet;
+ body[len2].classType = "body";
+ Composite.add(engine.world, body[len2]); //add to world
+
+ //large mobs shrink so they don't block paths
+ if (body[len].mass + body[len2].mass > 16) {
+ const massLimit = 8 + 6 * Math.random()
+ const shrink = function (that1, that2) {
+ if (that1.mass + that2.mass > massLimit) {
+ const scale = 0.95;
+ Matter.Body.scale(that1, scale, scale);
+ Matter.Body.scale(that2, scale, scale);
+ setTimeout(shrink, 20, that1, that2);
+ }
+ };
+ shrink(body[len], body[len2])
+ }
+ } else {
+ const len = body.length;
+ body[len] = Matter.Bodies.fromVertices(this.position.x, this.position.y, v);
+ Matter.Body.setVelocity(body[len], Vector.mult(this.velocity, 0.5));
+ Matter.Body.setAngularVelocity(body[len], this.angularVelocity);
+ body[len].collisionFilter.category = cat.body;
+ body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet;
+ body[len].classType = "body";
+ Composite.add(engine.world, body[len]); //add to world
+
+ //large mobs shrink so they don't block paths
+ if (body[len].mass > 9) {
+ const massLimit = 7 + 4 * Math.random()
+ const shrink = function (that) {
+ if (that.mass > massLimit) {
+ const scale = 0.95;
+ Matter.Body.scale(that, scale, scale);
+ setTimeout(shrink, 20, that);
+ }
+ };
+ shrink(body[len])
+ }
+ }
+ Matter.Composite.remove(engine.world, this);
+ mob.splice(i, 1);
+ if (tech.isMobBlockFling) {
+ const who = body[body.length - 1]
+ if (!who.isNotHoldable) {
+ b.targetedBlock(who)
+ Matter.Body.setAngularVelocity(who, (0.5 + 0.2 * Math.random()) * (Math.random() < 0.5 ? -1 : 1));
+ // who.torque += who.inertia * 0.002 * (Math.random() - 0.5)
+ }
+ }
+ } else {
+ Matter.Composite.remove(engine.world, this);
+ mob.splice(i, 1);
+ }
+ }
+ });
+ mob[i].alertRange2 = Math.pow(mob[i].radius * 3 + 550, 2);
+ Composite.add(engine.world, mob[i]); //add to world
+ }
+};
\ No newline at end of file
diff --git a/ngon/js/player.js b/ngon/js/player.js
new file mode 100644
index 00000000..20453712
--- /dev/null
+++ b/ngon/js/player.js
@@ -0,0 +1,5172 @@
+//global player variables for use in matter.js physics
+let player, jumpSensor, playerBody, playerHead, headSensor;
+
+// player Object Prototype *********************************************
+const m = {
+ spawn() {
+ //load player in matter.js physic engine
+ // let vector = Vertices.fromPath("0 40 50 40 50 115 0 115 30 130 20 130"); //player as a series of vertices
+ let vertices = Vertices.fromPath("0,40, 50,40, 50,115, 30,130, 20,130, 0,115, 0,40"); //player as a series of vertices
+ playerBody = Bodies.fromVertices(0, 0, vertices);
+ jumpSensor = Bodies.rectangle(0, 46, 36, 6, {
+ //this sensor check if the player is on the ground to enable jumping
+ sleepThreshold: 99999999999,
+ isSensor: true
+ });
+ vertices = Vertices.fromPath("16 -82 2 -66 2 -37 43 -37 43 -66 30 -82");
+ playerHead = Bodies.fromVertices(0, -55, vertices); //this part of the player lowers on crouch
+ headSensor = Bodies.rectangle(0, -57, 48, 45, {
+ //senses if the player's head is empty and can return after crouching
+ sleepThreshold: 99999999999,
+ isSensor: true
+ });
+ player = Body.create({
+ //combine jumpSensor and playerBody
+ parts: [playerBody, playerHead, jumpSensor, headSensor],
+ inertia: Infinity, //prevents player rotation
+ friction: 0.002,
+ frictionAir: 0.001,
+ //frictionStatic: 0.5,
+ restitution: 0,
+ sleepThreshold: Infinity,
+ collisionFilter: {
+ group: 0,
+ category: cat.player,
+ mask: cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield
+ },
+ // death() {
+ // m.death();
+ // }
+ });
+ Matter.Body.setMass(player, m.mass);
+ Composite.add(engine.world, [player]);
+ },
+ cycle: 600, //starts at 600 cycles instead of 0 to prevent bugs with m.history
+ lastKillCycle: 0,
+ lastHarmCycle: 0,
+ width: 50,
+ radius: 30,
+ eyeFillColor: null,
+ fillColor: null, //set by setFillColors
+ fillColorDark: null, //set by setFillColors
+ bodyGradient: null, //set by setFillColors
+ color: {
+ hue: 0,
+ sat: 0,
+ light: 100,
+ },
+ setFillColors() {
+ m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)`
+ m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 25}%)`
+ let grd = ctx.createLinearGradient(-30, 0, 30, 0);
+ grd.addColorStop(0, m.fillColorDark);
+ grd.addColorStop(1, m.fillColor);
+ m.bodyGradient = grd
+ },
+ // setFillColorsAlpha(alpha = 0.5) {
+ // m.fillColor = `hsla(${m.color.hue},${m.color.sat}%,${m.color.light}%,${alpha})`
+ // m.fillColorDark = `hsla(${m.color.hue},${m.color.sat}%,${m.color.light - 25}%,${alpha})`
+ // let grd = ctx.createLinearGradient(-30, 0, 30, 0);
+ // grd.addColorStop(0, m.fillColorDark);
+ // grd.addColorStop(1, m.fillColor);
+ // m.bodyGradient = grd
+ // },
+ height: 42,
+ yOffWhen: {
+ crouch: 22,
+ stand: 49,
+ jump: 70
+ },
+ defaultMass: 5,
+ mass: 5,
+ FxNotHolding: 0.015,
+ Fx: 0.016, //run Force on ground //
+ jumpForce: 0.42,
+ setMovement() {
+ // m.Fx = 0.08 / mass * tech.squirrelFx
+ // m.FxAir = 0.4 / mass / mass
+ m.Fx = tech.baseFx * m.fieldFx * tech.squirrelFx * (tech.isFastTime ? 1.5 : 1) / player.mass //base player mass is 5
+ m.jumpForce = tech.baseJumpForce * m.fieldJump * tech.squirrelJump * (tech.isFastTime ? 1.13 : 1) / player.mass / player.mass //base player mass is 5
+ },
+ FxAir: 0.016, // 0.4/5/5 run Force in Air
+ yOff: 70,
+ yOffGoal: 70,
+ onGround: false, //checks if on ground or in air
+ lastOnGroundCycle: 0, //use to calculate coyote time
+ standingOn: undefined,
+ numTouching: 0,
+ crouch: false,
+ // isHeadClear: true,
+ spawnPos: {
+ x: 0,
+ y: 0
+ },
+ spawnVel: {
+ x: 0,
+ y: 0
+ },
+ pos: {
+ x: 0,
+ y: 0
+ },
+ yPosDifference: 24.2859, //player.position.y - m.pos.y //24.285923217549026
+ // yPosDifferenceCrouched: -2.7140767824453604,
+ Sy: 0, //adds a smoothing effect to vertical only
+ Vx: 0,
+ Vy: 0,
+ friction: {
+ ground: 0.01,
+ air: 0.0025
+ },
+ airSpeedLimit: 125, // 125/mass/mass = 5
+ angle: 0,
+ walk_cycle: 0,
+ stepSize: 0,
+ flipLegs: -1,
+ hip: {
+ x: 12,
+ y: 24
+ },
+ knee: {
+ x: 0,
+ y: 0,
+ x2: 0,
+ y2: 0
+ },
+ foot: {
+ x: 0,
+ y: 0
+ },
+ legLength1: 55,
+ legLength2: 45,
+ transX: 0,
+ transY: 0,
+ history: new Array(600), //[], //tracks the last second of player position
+ rewindCount: 0, //used with CPT
+ resetHistory() {
+ const set = {
+ position: {
+ x: player.position.x,
+ y: player.position.y,
+ },
+ velocity: {
+ x: player.velocity.x,
+ y: player.velocity.y
+ },
+ yOff: m.yOff,
+ angle: m.angle,
+ health: m.health,
+ energy: m.energy,
+ activeGun: b.activeGun
+ }
+ for (let i = 0; i < 600; i++) { //reset history
+ m.history[i] = set
+ }
+ },
+ move() {
+ m.pos.x = player.position.x;
+ m.pos.y = playerBody.position.y - m.yOff;
+ m.Vx = player.velocity.x;
+ m.Vy = player.velocity.y;
+
+ //tracks the last 10s of player information
+ m.history.splice(m.cycle % 600, 1, {
+ position: {
+ x: player.position.x,
+ y: player.position.y,
+ },
+ velocity: {
+ x: player.velocity.x,
+ y: player.velocity.y
+ },
+ yOff: m.yOff,
+ angle: m.angle,
+ health: m.health,
+ energy: m.energy,
+ activeGun: b.activeGun
+ });
+ // const back = 59 // 59 looks at 1 second ago //29 looks at 1/2 a second ago
+ // historyIndex = (m.cycle - back) % 600
+ },
+ transSmoothX: 0,
+ transSmoothY: 0,
+ lastGroundedPositionY: 0,
+ // mouseZoom: 0,
+ lookSmoothing: 0.07, //1 is instant jerky, 0.001 is slow smooth zoom, 0.07 is standard
+ look() { }, //set to lookDefault()
+ lookDefault() {
+ //always on mouse look
+ m.angle = Math.atan2(
+ simulation.mouseInGame.y - m.pos.y,
+ simulation.mouseInGame.x - m.pos.x
+ );
+ //smoothed mouse look translations
+ const scale = 0.8;
+ m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+
+ m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing;
+ m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing;
+ },
+ doCrouch() {
+ if (!m.crouch) {
+ m.crouch = true;
+ m.yOffGoal = m.yOffWhen.crouch;
+ if ((playerHead.position.y - player.position.y) < 0) {
+ Matter.Body.setPosition(playerHead, {
+ x: player.position.x,
+ y: player.position.y + 9.1740767
+ })
+ }
+ }
+ },
+ undoCrouch() {
+ if (m.crouch) {
+ m.crouch = false;
+ m.yOffGoal = m.yOffWhen.stand;
+ if ((playerHead.position.y - player.position.y) > 0) {
+ Matter.Body.setPosition(playerHead, {
+ x: player.position.x,
+ y: player.position.y - 30.28592321
+ })
+ }
+ }
+ },
+ hardLandCD: 0,
+ checkHeadClear() {
+ if (Matter.Query.collides(headSensor, map).length > 0) {
+ return false
+ } else {
+ return true
+ }
+ },
+ buttonCD_jump: 0, //cool down for player buttons
+ jump() {
+ // if (!m.onGround) m.lastOnGroundCycle = 0 //m.cycle - tech.coyoteTime
+ m.buttonCD_jump = m.cycle; //can't jump again until 20 cycles pass
+ //apply a fraction of the jump force to the body the player is jumping off of
+ Matter.Body.applyForce(m.standingOn, m.pos, {
+ x: 0,
+ y: m.jumpForce * 0.12 * Math.min(m.standingOn.mass, 5)
+ });
+
+ player.force.y = -m.jumpForce; //player jump force
+ Matter.Body.setVelocity(player, { //zero player y-velocity for consistent jumps
+ x: player.velocity.x,
+ y: Math.max(-10, Math.min(m.standingOn.velocity.y, 10)) //cap velocity contribution from blocks you are standing on to 10 in the vertical
+ });
+ },
+ moverX: 0, //used to tell the player about moving platform x velocity
+ groundControl() {
+ //check for crouch or jump
+ if (m.crouch) {
+ if (!(input.down) && m.checkHeadClear() && m.hardLandCD < m.cycle) m.undoCrouch();
+ } else if (input.down || m.hardLandCD > m.cycle) {
+ m.doCrouch(); //on ground && not crouched and pressing s or down
+ } else if (input.up && m.buttonCD_jump + 20 < m.cycle && m.yOffWhen.stand > 23) {
+ m.jump()
+ }
+ const moveX = player.velocity.x - m.moverX //account for mover platforms
+ if (input.left) {
+ if (moveX > -2) {
+ player.force.x -= m.Fx * 1.5
+ } else {
+ player.force.x -= m.Fx
+ }
+ // }
+ } else if (input.right) {
+ if (moveX < 2) {
+ player.force.x += m.Fx * 1.5
+ } else {
+ player.force.x += m.Fx
+ }
+ } else {
+ const stoppingFriction = 0.92; //come to a stop if no move key is pressed
+ Matter.Body.setVelocity(player, { x: m.moverX * 0.08 + player.velocity.x * stoppingFriction, y: player.velocity.y * stoppingFriction });
+ }
+
+ if (Math.abs(moveX) > 4) { //come to a stop if fast // if (player.speed > 4) { //come to a stop if fast
+ const stoppingFriction = (m.crouch) ? 0.65 : 0.89; // this controls speed when crouched
+ Matter.Body.setVelocity(player, { x: m.moverX * (1 - stoppingFriction) + player.velocity.x * stoppingFriction, y: player.velocity.y * stoppingFriction });
+ }
+ m.moverX = 0 //reset the level mover offset
+ },
+ airControl() {
+ //check for coyote time jump
+ // if (input.up && m.buttonCD_jump + 20 + tech.coyoteTime < m.cycle && m.yOffWhen.stand > 23 && m.lastOnGroundCycle + tech.coyoteTime > m.cycle) m.jump()
+ if (input.up && m.buttonCD_jump + 20 < m.cycle && m.yOffWhen.stand > 23 && m.lastOnGroundCycle + 5 > m.cycle) m.jump()
+
+ //check for short jumps //moving up //recently pressed jump //but not pressing jump key now
+ if (m.buttonCD_jump + 60 > m.cycle && !(input.up) && m.Vy < 0) {
+ Matter.Body.setVelocity(player, { x: player.velocity.x, y: player.velocity.y * 0.94 }); //reduce player y-velocity every cycle
+ }
+
+ if (input.left) {
+ if (player.velocity.x > -m.airSpeedLimit / player.mass / player.mass) player.force.x -= m.FxAir; // move player left / a
+ } else if (input.right) {
+ if (player.velocity.x < m.airSpeedLimit / player.mass / player.mass) player.force.x += m.FxAir; //move player right / d
+ }
+ },
+ printBlock() {
+ const sides = Math.floor(4 + 6 * Math.random() * Math.random())
+ body[body.length] = Matter.Bodies.polygon(m.pos.x, m.pos.y, sides, 8, {
+ friction: 0.05,
+ frictionAir: 0.001,
+ collisionFilter: { category: 0, mask: 0 }, //no collision because player is holding
+ classType: "body",
+ isPrinted: true,
+ radius: 10, //used to grow and warp the shape of the block
+ density: 0.002, //double density for 2x damage
+ });
+ const who = body[body.length - 1]
+ Composite.add(engine.world, who); //add to world
+ m.throwCharge = 4;
+ m.holdingTarget = who
+ m.isHolding = true;
+ },
+ alive: false,
+ switchWorlds() {
+ powerUps.boost.endCycle = 0
+ const totalGuns = b.inventory.length
+ //track ammo/ ammoPack count
+ let ammoCount = 0
+ for (let i = 0, len = b.inventory.length; i < len; i++) {
+ if (b.guns[b.inventory[i]].ammo !== Infinity) {
+ ammoCount += b.guns[b.inventory[i]].ammo / b.guns[b.inventory[i]].ammoPack
+ } else {
+ ammoCount += 5
+ }
+ }
+
+ simulation.isTextLogOpen = false; //prevent console spam
+ //remove all tech and count current tech total
+ let totalTech = 0;
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isJunk) tech.tech[i].frequency = 0
+ if (tech.tech[i].count > 0 && !tech.tech[i].isLore) {
+ if (tech.tech[i].frequencyDefault) {
+ tech.tech[i].frequency = tech.tech[i].frequencyDefault
+ } else {
+ tech.tech[i].frequency = 1
+ }
+ if (
+ !tech.tech[i].isNonRefundable &&
+ !tech.tech[i].isFromAppliedScience &&
+ !tech.tech[i].isAltRealityTech
+ ) {
+ totalTech += tech.tech[i].count
+ tech.tech[i].remove();
+ tech.tech[i].isLost = false
+ tech.tech[i].count = 0
+ }
+ }
+ }
+ // lore.techCount = 0;
+ // tech.removeLoreTechFromPool();
+ // tech.addLoreTechToPool();
+ // tech.removeJunkTechFromPool();
+ tech.duplication = 0;
+ tech.extraMaxHealth = 0;
+ tech.totalCount = 0;
+ tech.countJunkTech();
+ const randomBotCount = b.totalBots()
+ b.zeroBotCount()
+ //remove all bullets, respawn bots
+ for (let i = 0; i < bullet.length; ++i) Matter.Composite.remove(engine.world, bullet[i]);
+ bullet = [];
+
+ //randomize health
+ m.health = m.health * (1 + 0.5 * (Math.random() - 0.5))
+ if (m.health > 1) m.health = 1;
+ m.displayHealth();
+ //randomize field
+ m.setField(Math.ceil(Math.random() * (m.fieldUpgrades.length - 1)))
+ //removes guns and ammo
+ b.inventory = [];
+ b.activeGun = null;
+ b.inventoryGun = 0;
+ for (let i = 0, len = b.guns.length; i < len; ++i) {
+ b.guns[i].have = false;
+ if (b.guns[i].ammo !== Infinity) b.guns[i].ammo = 0;
+ }
+ //give random guns
+ for (let i = 0; i < totalGuns; i++) b.giveGuns()
+
+ //randomize ammo based on ammo/ammoPack count
+ for (let i = 0, len = b.inventory.length; i < len; i++) {
+ if (b.guns[b.inventory[i]].ammo !== Infinity) b.guns[b.inventory[i]].ammo = Math.max(0, Math.floor(ammoCount / b.inventory.length * b.guns[b.inventory[i]].ammoPack * (1.15 + 0.3 * (Math.random() - 0.5))))
+ }
+ console.log(b.activeGun)
+ //randomize tech
+ for (let i = 0; i < totalTech; i++) {
+ //find what tech I could get
+ let options = [];
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isBadRandomOption && !tech.tech[i].isLore && !tech.tech[i].isJunk) {
+ for (let j = 0; j < tech.tech[i].frequency; j++) options.push(i);
+ }
+ }
+ //add a new tech from options pool
+ if (options.length > 0) tech.giveTech(options[Math.floor(Math.random() * options.length)])
+ }
+ b.respawnBots();
+ for (let i = 0; i < randomBotCount; i++) b.randomBot()
+ simulation.makeGunHUD(); //update gun HUD
+ simulation.updateTechHUD();
+ simulation.isTextLogOpen = true;
+ m.drop();
+ if (simulation.paused) build.pauseGrid() //update the build when paused
+ },
+ dmgScale: null, //scales all damage, but not raw .dmg //set in levels.setDifficulty
+ death() {
+ if (tech.isImmortal) { //if player has the immortality buff, spawn on the same level with randomized damage
+ //remove immortality tech
+ // for (let i = 0; i < tech.tech.length; i++) {
+ // if (tech.tech[i].name === "quantum immortality") tech.removeTech(i)
+ // }
+
+ m.setMaxHealth()
+ m.health = 1;
+ // m.addHealth(1)
+
+ simulation.wipe = function () { //set wipe to have trails
+ ctx.fillStyle = "rgba(255,255,255,0)";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ }
+ spawn.setSpawnList(); //new mob types
+ simulation.clearNow = true; //triggers a map reset
+
+ m.switchWorlds()
+ const swapPeriod = 1000
+ for (let i = 0, len = 5; i < len; i++) {
+ setTimeout(function () {
+ simulation.wipe = function () { //set wipe to have trails
+ ctx.fillStyle = "rgba(255,255,255,0)";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ }
+ spawn.setSpawnList(); //new mob types
+ simulation.clearNow = true; //triggers a map reset
+ m.switchWorlds()
+ simulation.isTextLogOpen = true;
+ simulation.makeTextLog(`simulation.amplitude
= 0.${len - i - 1}`, swapPeriod);
+ simulation.isTextLogOpen = false;
+ simulation.wipe = function () { //set wipe to have trails
+ ctx.fillStyle = `rgba(255,255,255,${(i + 1) * (i + 1) * 0.006})`;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ }
+ }, (i + 1) * swapPeriod);
+ }
+ setTimeout(function () {
+ simulation.wipe = function () { //set wipe to normal
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ }
+ simulation.isTextLogOpen = true;
+ simulation.makeTextLog("simulation.amplitude
= null");
+ tech.isImmortal = false //disable future immortality
+ }, 6 * swapPeriod);
+ } else if (m.alive) { //normal death code here
+ m.storeTech()
+ m.alive = false;
+ simulation.paused = true;
+ m.health = 0;
+ simulation.ephemera = []
+ document.getElementById("defense-bar").style.display = "none"; //hide defense
+ document.getElementById("damage-bar").style.display = "none"
+ m.displayHealth();
+ document.getElementById("text-log").style.display = "none"
+ document.getElementById("fade-out").style.opacity = 0.9; //slowly fade to 90% white on top of canvas
+ // build.shareURL(false)
+ setTimeout(function () {
+ Composite.clear(engine.world);
+ Engine.clear(engine);
+ simulation.splashReturn();
+ }, 5000);
+ }
+ },
+ storeTech() { //store a copy of your tech, it will show up at your location next run in the entanglement power up
+ if (localSettings.isAllowed && !simulation.isCheating) {
+ const gunList = [] //store gun names
+ for (i = 0, len = b.inventory.length; i < len; i++) gunList.push(b.inventory[i])
+ const techList = [] //store tech names
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].count > 0 && !tech.tech[i].isNonRefundable) techList.push(i)
+ }
+ if (techList.length) {
+ localSettings.entanglement = {
+ fieldIndex: m.fieldMode,
+ gunIndexes: gunList,
+ techIndexes: techList,
+ position: {
+ x: m.pos.x,
+ y: m.pos.y
+ },
+ levelName: level.levels[level.onLevel],
+ isHorizontalFlipped: simulation.isHorizontalFlipped
+ }
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ }
+ }
+ },
+ health: 0,
+ maxHealth: 1, //set in simulation.reset()
+ drawHealth() {
+ if (m.health < 1) {
+ ctx.fillStyle = "rgba(100, 100, 100, 0.5)";
+ ctx.fillRect(m.pos.x - m.radius, m.pos.y - 50, 60, 10);
+ ctx.fillStyle = "#f00";
+ ctx.fillRect(
+ m.pos.x - m.radius,
+ m.pos.y - 50,
+ 60 * m.health,
+ 10
+ );
+ }
+ },
+ displayHealth() {
+ id = document.getElementById("health");
+ // health display is a x^1.5 rule to make it seem like the player has lower health, this makes the player feel more excitement
+ id.style.width = Math.floor(300 * m.maxHealth * Math.pow(m.health / m.maxHealth, 1.4)) + "px";
+ //css animation blink if health is low
+ // if (m.health < 0.3) {
+ // id.classList.add("low-health");
+ // } else {
+ // id.classList.remove("low-health");
+ // }
+ },
+ addHealth(heal) {
+ if (!tech.isEnergyHealth) {
+ m.health += heal * simulation.healScale;
+ if (m.health > m.maxHealth) m.health = m.maxHealth;
+ m.displayHealth();
+ }
+ },
+ baseHealth: 1,
+ setMaxHealth() {
+ m.maxHealth = m.baseHealth + tech.extraMaxHealth + 2.22 * tech.isFallingDamage + 4 * tech.isFlipFlop * tech.isFlipFlopOn * tech.isFlipFlopHealth
+ document.getElementById("health-bg").style.width = `${Math.floor(300 * m.maxHealth)}px`
+ simulation.makeTextLog(`
m .
maxHealth = ${m.maxHealth.toFixed(2)}`)
+ if (m.health > m.maxHealth) m.health = m.maxHealth;
+ m.displayHealth();
+ },
+
+ defaultFPSCycle: 0, //tracks when to return to normal fps
+ immuneCycle: 0, //used in engine
+ lastCalculatedDamage: 0, //used to decided if damage bar needs to be redrawn (in simulation.checks)
+ lastCalculatedDefense: 0, //used to decided if defense bar needs to be redrawn (in simulation.checks)
+ defense() {
+ let dmg = 1
+ dmg *= m.fieldHarmReduction
+ // if (!tech.isFlipFlopOn && tech.isFlipFlopHealth) dmg *= 0.5
+ // 1.25 + Math.sin(m.cycle * 0.01)
+ if (tech.isDiaphragm) dmg *= 0.56 + 0.36 * Math.sin(m.cycle * 0.0075);
+ if (tech.isZeno) dmg *= 0.15
+ if (tech.isFieldHarmReduction) dmg *= 0.5
+ if (tech.isHarmMACHO) dmg *= 0.4
+ if (tech.isImmortal) dmg *= 0.7
+ if (tech.energyRegen === 0) dmg *= 0.34
+ // if (tech.healthDrain) dmg *= 1 + 3.33 * tech.healthDrain //tech.healthDrain = 0.03 at one stack //cause more damage
+ if (m.fieldMode === 0 || m.fieldMode === 3) dmg *= 0.973 ** m.coupling
+ if (tech.isLowHealthDefense) dmg *= 1 - Math.max(0, 1 - m.health) * 0.8
+ if (tech.isHarmReduceNoKill && m.lastKillCycle + 300 < m.cycle) dmg *= 0.33
+ if (tech.squirrelFx !== 1) dmg *= 0.78//Math.pow(0.78, (tech.squirrelFx - 1) / 0.4)
+ if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1
+ if (tech.isSpeedHarm && player.speed > 0.1) dmg *= 1 - Math.min(player.speed * 0.0165, 0.66)
+ if (tech.isHarmReduce && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.25
+ if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.1
+ if (tech.isBotArmor) dmg *= 0.94 ** b.totalBots()
+ if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.33;
+ if (tech.isNoFireDefense && m.cycle > m.fireCDcycle + 120) dmg *= 0.3
+ if (tech.isTurret && m.crouch) dmg *= 0.34;
+ if (tech.isFirstDer && b.inventory[0] === b.activeGun) dmg *= 0.85 ** b.inventory.length
+ if (tech.isEnergyHealth) {
+ return Math.pow(dmg, 0.19) //defense has less effect
+ } else {
+ return dmg
+ }
+ },
+ rewind(steps) { // m.rewind(Math.floor(Math.min(599, 137 * m.energy)))
+ if (tech.isRewindGrenade) {
+ const immunityDuration = 65
+ const immunityCycle = m.cycle + immunityDuration + 10 + tech.isPetalsExplode * 30 + tech.isCircleExplode * 21
+ if (m.immuneCycle < immunityCycle) m.immuneCycle = immunityCycle; //player is immune to damage until after grenades might explode...
+
+ for (let i = 1, len = Math.floor(4 + steps / 40); i < len; i++) {
+ b.grenade(Vector.add(m.pos, {
+ x: 10 * (Math.random() - 0.5),
+ y: 10 * (Math.random() - 0.5)
+ }), -i * Math.PI / len) //fire different angles for each grenade
+ const who = bullet[bullet.length - 1]
+
+ if (tech.isNeutronBomb) {
+ Matter.Body.setVelocity(who, {
+ x: who.velocity.x * 0.3,
+ y: who.velocity.y * 0.3
+ });
+ } else if (tech.isVacuumBomb) {
+ Matter.Body.setVelocity(who, {
+ x: who.velocity.x * 0.5,
+ y: who.velocity.y * 0.5
+ });
+ who.endCycle = simulation.cycle + immunityDuration
+
+ } else if (tech.isRPG) {
+ who.endCycle = simulation.cycle + 10
+ } else {
+ Matter.Body.setVelocity(who, {
+ x: who.velocity.x * 0.5,
+ y: who.velocity.y * 0.5
+ });
+ who.endCycle = simulation.cycle + immunityDuration
+ }
+ }
+ }
+
+ let history = m.history[(m.cycle - steps) % 600]
+ Matter.Body.setPosition(player, history.position);
+ Matter.Body.setVelocity(player, {
+ x: history.velocity.x,
+ y: history.velocity.y
+ });
+ m.yOff = history.yOff
+ if (m.yOff < 48) {
+ m.doCrouch()
+ } else {
+ m.undoCrouch()
+ }
+
+ // b.activeGun = history.activeGun
+ // for (let i = 0; i < b.inventory.length; i++) {
+ // if (b.inventory[i] === b.activeGun) b.inventoryGun = i
+ // }
+ // simulation.updateGunHUD();
+ // simulation.boldActiveGunHUD();
+
+ // move bots to player's new position
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ m.energy = Math.max(m.energy - steps / 330, 0.01)
+ if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+
+ let isDrawPlayer = true
+ const shortPause = function () {
+ if (m.defaultFPSCycle < m.cycle) { //back to default values
+ simulation.fpsCap = simulation.fpsCapDefault
+ simulation.fpsInterval = 1000 / simulation.fpsCap;
+ document.getElementById("dmg").style.transition = "opacity 1s";
+ document.getElementById("dmg").style.opacity = "0";
+ } else {
+ requestAnimationFrame(shortPause);
+ if (isDrawPlayer) {
+ isDrawPlayer = false
+ ctx.save();
+ ctx.globalCompositeOperation = "lighter";
+ ctx.translate(canvas.width2, canvas.height2); //center
+ ctx.scale(simulation.zoom / simulation.edgeZoomOutSmooth, simulation.zoom / simulation.edgeZoomOutSmooth); //zoom in once centered
+ ctx.translate(-canvas.width2 + m.transX, -canvas.height2 + m.transY); //translate
+ for (let i = 1; i < steps; i++) {
+ history = m.history[(m.cycle - i) % 600]
+ m.pos.x = history.position.x
+ m.pos.y = history.position.y + m.yPosDifference - history.yOff
+ m.yOff = history.yOff
+ m.draw();
+ }
+ ctx.restore();
+ m.resetHistory()
+ }
+ }
+ };
+
+ if (m.defaultFPSCycle < m.cycle) requestAnimationFrame(shortPause);
+ simulation.fpsCap = 3 //1 is longest pause, 4 is standard
+ simulation.fpsInterval = 1000 / simulation.fpsCap;
+ m.defaultFPSCycle = m.cycle
+ if (tech.isRewindBot) {
+ const len = steps * 0.05 * tech.isRewindBot
+ const botStep = Math.floor(steps / len)
+ for (let i = 0; i < len; i++) {
+ const where = m.history[Math.abs(m.cycle - i * botStep) % 600].position //spread out spawn locations along past history
+ b.randomBot({
+ x: where.x + 20 * (Math.random() - 0.5),
+ y: where.y + 20 * (Math.random() - 0.5)
+ }, false, false)
+ bullet[bullet.length - 1].endCycle = simulation.cycle + 440 + Math.floor(120 * Math.random()) //8-10 seconds
+ }
+ }
+ },
+ collisionImmuneCycles: 30,
+ damage(dmg) {
+ if (tech.isRewindAvoidDeath && (m.energy + 0.05) > Math.min(0.95, m.maxEnergy) && dmg > 0.01) {
+ const steps = Math.floor(Math.min(299, 150 * m.energy))
+ simulation.makeTextLog(`
m .rewind(${steps})`)
+ m.rewind(steps)
+ return
+ }
+ m.lastHarmCycle = m.cycle
+ if (tech.isDroneOnDamage && bullet.length < 150) { //chance to build a drone on damage from tech
+ const len = Math.min((dmg - 0.06 * Math.random()) * 40, 40) / tech.droneEnergyReduction * (tech.isEnergyHealth ? 0.5 : 1)
+ for (let i = 0; i < len; i++) {
+ if (Math.random() < 0.5) b.drone({
+ x: m.pos.x + 30 * Math.cos(m.angle) + 100 * (Math.random() - 0.5),
+ y: m.pos.y + 30 * Math.sin(m.angle) + 100 * (Math.random() - 0.5)
+ }) //spawn drone
+ }
+ }
+ if (tech.isEnergyHealth) {
+ m.energy -= 0.9 * dmg / Math.sqrt(simulation.healScale) //scale damage with heal reduction difficulty
+ if (m.energy < 0 || isNaN(m.energy)) { //taking deadly damage
+ if (tech.isDeathAvoid && powerUps.research.count && !tech.isDeathAvoidedThisLevel) {
+ tech.isDeathAvoidedThisLevel = true
+ powerUps.research.changeRerolls(-1)
+ simulation.makeTextLog(`
m .
research -- ${powerUps.research.count}`)
+ for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false);
+ m.energy = m.maxEnergy
+ if (m.immuneCycle < m.cycle + 300) m.immuneCycle = m.cycle + 300 //disable this.immuneCycle bonus seconds
+ simulation.wipe = function () { //set wipe to have trails
+ ctx.fillStyle = "rgba(255,255,255,0.03)";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ }
+ setTimeout(function () {
+ tech.maxDuplicationEvent()
+ simulation.wipe = function () { //set wipe to normal
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ }
+ }, 3000);
+ } else { //death
+ m.health = 0;
+ m.energy = 0;
+ m.death();
+ }
+ return;
+ }
+ } else {
+ dmg *= m.defense()
+ m.health -= dmg;
+ if (m.health < 0 || isNaN(m.health)) {
+ if (tech.isDeathAvoid && powerUps.research.count > 0 && !tech.isDeathAvoidedThisLevel) { //&& Math.random() < 0.5
+ tech.isDeathAvoidedThisLevel = true
+ m.health = 0.05
+ powerUps.research.changeRerolls(-1)
+ simulation.makeTextLog(`
m .
research --
+
${powerUps.research.count}`)
+ for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false);
+ if (m.immuneCycle < m.cycle + 300) m.immuneCycle = m.cycle + 300 //disable this.immuneCycle bonus seconds
+ simulation.wipe = function () { //set wipe to have trails
+ ctx.fillStyle = "rgba(255,255,255,0.03)";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ }
+ setTimeout(function () {
+ tech.maxDuplicationEvent()
+ simulation.wipe = function () { //set wipe to normal
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ }
+ }, 3000);
+ } else {
+ m.health = 0;
+ m.displayHealth();
+ m.death();
+ return;
+ }
+ }
+ m.displayHealth();
+ document.getElementById("dmg").style.transition = "opacity 0s";
+ document.getElementById("dmg").style.opacity = 0.1 + Math.min(0.6, dmg * 4);
+ }
+ if (dmg > 0.03) {
+ m.lastHit = dmg;
+ if (dmg > 0.06 / m.holdingMassScale) m.drop(); //drop block if holding // m.holdingMassScale = 0.5 for most fields
+ if (m.isCloak) m.fireCDcycle = m.cycle //forced exit cloak
+ }
+ const normalFPS = function () {
+ if (m.defaultFPSCycle < m.cycle) { //back to default values
+ simulation.fpsCap = simulation.fpsCapDefault
+ simulation.fpsInterval = 1000 / simulation.fpsCap;
+ document.getElementById("dmg").style.transition = "opacity 1s";
+ document.getElementById("dmg").style.opacity = "0";
+ } else {
+ requestAnimationFrame(normalFPS);
+ }
+ };
+
+ if (m.defaultFPSCycle < m.cycle) requestAnimationFrame(normalFPS);
+ if (dmg > 0.05) { // freeze game for high damage hits
+ simulation.fpsCap = 4 //40 - Math.min(25, 100 * dmg)
+ simulation.fpsInterval = 1000 / simulation.fpsCap;
+ if (tech.isHarmFreeze) {
+ for (let i = 0, len = mob.length; i < len; i++) mobs.statusSlow(mob[i], 480) //freeze all mobs
+ }
+ } else {
+ simulation.fpsCap = simulation.fpsCapDefault
+ simulation.fpsInterval = 1000 / simulation.fpsCap;
+ }
+ m.defaultFPSCycle = m.cycle
+ // if (tech.isSlowFPS) { // slow game
+ // simulation.fpsCap = 30 //new fps
+ // simulation.fpsInterval = 1000 / simulation.fpsCap;
+ // //how long to wait to return to normal fps
+ // m.defaultFPSCycle = m.cycle + 20 + Math.min(90, Math.floor(200 * dmg))
+ // if (tech.isHarmFreeze) { //freeze all mobs
+ // for (let i = 0, len = mob.length; i < len; i++) {
+ // mobs.statusSlow(mob[i], 450)
+ // }
+ // }
+ // } else {
+ // if (dmg > 0.05) { // freeze game for high damage hits
+ // simulation.fpsCap = 4 //40 - Math.min(25, 100 * dmg)
+ // simulation.fpsInterval = 1000 / simulation.fpsCap;
+ // } else {
+ // simulation.fpsCap = simulation.fpsCapDefault
+ // simulation.fpsInterval = 1000 / simulation.fpsCap;
+ // }
+ // m.defaultFPSCycle = m.cycle
+ // }
+ // if (!noTransition) {
+ // document.getElementById("health").style.transition = "width 0s ease-out"
+ // } else {
+ // document.getElementById("health").style.transition = "width 1s ease-out"
+ // }
+ },
+ buttonCD: 0, //cool down for player buttons
+ // *********************************************
+ // ****** drawing player and skins *************
+ // *********************************************
+ drawLeg(stroke) { },
+ calcLeg(cycle_offset, offset) {
+ m.hip.x = 12 + offset;
+ m.hip.y = 24 + offset;
+ //stepSize goes to zero if Vx is zero or not on ground (make m transition cleaner)
+ m.stepSize = 0.8 * m.stepSize + 0.2 * (7 * Math.sqrt(Math.min(9, Math.abs(m.Vx))) * m.onGround);
+ //changes to stepsize are smoothed by adding only a percent of the new value each cycle
+ const stepAngle = 0.034 * m.walk_cycle + cycle_offset;
+ m.foot.x = 2.2 * m.stepSize * Math.cos(stepAngle) + offset;
+ m.foot.y = offset + 1.2 * m.stepSize * Math.sin(stepAngle) + m.yOff + m.height;
+ const Ymax = m.yOff + m.height;
+ if (m.foot.y > Ymax) m.foot.y = Ymax;
+
+ //calculate knee position as intersection of circle from hip and foot
+ const d = Math.sqrt((m.hip.x - m.foot.x) * (m.hip.x - m.foot.x) + (m.hip.y - m.foot.y) * (m.hip.y - m.foot.y));
+ const l = (m.legLength1 * m.legLength1 - m.legLength2 * m.legLength2 + d * d) / (2 * d);
+ const h = Math.sqrt(m.legLength1 * m.legLength1 - l * l);
+ m.knee.x = (l / d) * (m.foot.x - m.hip.x) - (h / d) * (m.foot.y - m.hip.y) + m.hip.x + offset;
+ m.knee.y = (l / d) * (m.foot.y - m.hip.y) + (h / d) * (m.foot.x - m.hip.x) + m.hip.y;
+ },
+ draw() { },
+ isAltSkin: false,
+ resetSkin() {
+ simulation.isAutoZoom = true;
+ m.yOffWhen.jump = 70
+ m.yOffWhen.stand = 49
+ m.yOffWhen.crouch = 22
+ m.isAltSkin = false
+ m.color = {
+ hue: 0,
+ sat: 0,
+ light: 100,
+ }
+ m.setFillColors();
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -3);
+ m.drawLeg("#4a4a4a");
+ m.calcLeg(0, 0);
+ m.drawLeg("#333");
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+ }
+ m.drawLeg = function (stroke) {
+ // if (simulation.mouseInGame.x > m.pos.x) {
+ if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
+ m.flipLegs = 1;
+ } else {
+ m.flipLegs = -1;
+ }
+ ctx.save();
+ ctx.scale(m.flipLegs, 1); //leg lines
+ ctx.beginPath();
+ ctx.moveTo(m.hip.x, m.hip.y);
+ ctx.lineTo(m.knee.x, m.knee.y);
+ ctx.lineTo(m.foot.x, m.foot.y);
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = 7;
+ ctx.stroke();
+
+ //toe lines
+ ctx.beginPath();
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x - 15, m.foot.y + 5);
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x + 15, m.foot.y + 5);
+ ctx.lineWidth = 4;
+ ctx.stroke();
+
+ //hip joint
+ ctx.beginPath();
+ ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI);
+ //knee joint
+ ctx.moveTo(m.knee.x + 7, m.knee.y);
+ ctx.arc(m.knee.x, m.knee.y, 7, 0, 2 * Math.PI);
+ //foot joint
+ ctx.moveTo(m.foot.x + 6, m.foot.y);
+ ctx.arc(m.foot.x, m.foot.y, 6, 0, 2 * Math.PI);
+ ctx.fillStyle = m.fillColor;
+ ctx.fill();
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.restore();
+ }
+ },
+ skin: {
+ none() {
+ m.isAltSkin = true
+ },
+ favicon() { //used to render the favicon, not actually in game
+ m.yOffWhen.jump = 70
+ m.yOffWhen.stand = 49
+ m.yOffWhen.crouch = 22
+ m.isAltSkin = false
+ m.color = {
+ hue: 0,
+ sat: 0,
+ light: 100,
+ }
+
+ m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)`
+ m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 10}%)`
+ let grd = ctx.createLinearGradient(-30, 0, 30, 0);
+ grd.addColorStop(0, m.fillColorDark);
+ grd.addColorStop(1, m.fillColor);
+ m.bodyGradient = grd
+
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
+ ctx.translate(m.pos.x, m.pos.y);
+ // m.calcLeg(Math.PI, -3);
+ // m.drawLeg("#4a4a4a");
+ // m.calcLeg(0, 0);
+ // m.drawLeg("#333");
+ // ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(12, 0, 4.5, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 4.5;
+ ctx.stroke();
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+ }
+ },
+ mech() {
+ m.isAltSkin = true
+ m.yOffWhen.stand = 52
+ m.yOffWhen.jump = 72
+ // m.yOffWhen.crouch = 22
+ // m.color = {
+ // hue: 184,
+ // sat: 0,
+ // light: 55,
+ // }
+ // m.setFillColors();
+ m.draw = function () {
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -1.25);
+ m.drawLeg("#606060");
+ m.calcLeg(0, 0);
+ m.drawLeg("#444");
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+ }
+ m.drawLeg = function (stroke) {
+ if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
+ m.flipLegs = 1;
+ } else {
+ m.flipLegs = -1;
+ }
+ const hip = { x: m.hip.x - 5, y: m.hip.y + 5 }
+ const sub = Vector.sub(m.knee, hip)
+ const off = Vector.mult(Vector.rotate(Vector.normalise(sub), Math.PI / 2), 8)
+ const kneeBraceHigh = Vector.add(hip, off)
+ const kneeBraceLow = Vector.add(kneeBraceHigh, Vector.mult(sub, 0.9))
+ const foot = { x: m.foot.x - 10, y: m.foot.y - 15 }
+ ctx.save();
+ ctx.scale(m.flipLegs, 1); //leg lines
+ ctx.beginPath();
+ ctx.moveTo(hip.x, hip.y);
+ ctx.lineTo(m.knee.x, m.knee.y);
+ ctx.lineTo(foot.x, foot.y);
+ //extra upper leg brace
+ ctx.moveTo(kneeBraceHigh.x, kneeBraceHigh.y);
+ ctx.lineTo(kneeBraceLow.x, kneeBraceLow.y);
+ ctx.lineTo(m.knee.x, m.knee.y);
+
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = 3;
+ ctx.stroke();
+ //foot
+ ctx.beginPath();
+ ctx.moveTo(foot.x, foot.y);
+ ctx.quadraticCurveTo(m.foot.x - 30, m.foot.y + 12, m.foot.x + 13, m.foot.y + 3);
+ ctx.lineWidth = 1.5;
+ ctx.stroke();
+
+ //hip joint
+ ctx.beginPath();
+ ctx.arc(m.hip.x, m.hip.y - 1, 11, 0, 2 * Math.PI);
+ //knee joint
+ ctx.moveTo(m.knee.x + 3, m.knee.y);
+ ctx.arc(m.knee.x, m.knee.y, 3, 0, 2 * Math.PI);
+ //knee brace
+ // ctx.moveTo(kneeBraceHigh.x + 4, kneeBraceHigh.y);
+ // ctx.arc(kneeBraceHigh.x, kneeBraceHigh.y, 4, 0, 2 * Math.PI);
+ ctx.moveTo(kneeBraceLow.x + 2.5, kneeBraceLow.y);
+ ctx.arc(kneeBraceLow.x, kneeBraceLow.y, 2.5, 0, 2 * Math.PI);
+ //foot joint
+ ctx.moveTo(foot.x + 2.5, foot.y);
+ ctx.arc(foot.x, foot.y, 2.5, 0, 2 * Math.PI);
+ ctx.fillStyle = m.fillColor;
+ ctx.fill();
+ ctx.lineWidth = 1;
+ // ctx.strokeStyle = "#333"
+ ctx.stroke();
+ ctx.restore();
+ }
+ },
+ energy() {
+ m.isAltSkin = true
+ m.color = {
+ hue: 184,
+ sat: 100,
+ light: 85,
+ }
+ m.setFillColors();
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -3);
+ m.drawLeg("#456");
+ m.calcLeg(0, 0);
+ m.drawLeg("#345");
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.strokeStyle = "rgba(0,255,255,0.22)";
+ ctx.lineWidth = 12;
+ ctx.stroke();
+ ctx.fillStyle = 'hsl(184,100%,85%)' //m.fillColor; //"#9ff" //m.bodyGradient
+ ctx.fill();
+
+ ctx.beginPath();
+ ctx.arc(17, 0, 5.5, 0, 2 * Math.PI);
+ ctx.fillStyle = "#357"
+ ctx.fill();
+
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+ }
+ m.drawLeg = function (stroke) {
+ // if (simulation.mouseInGame.x > m.pos.x) {
+ if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
+ m.flipLegs = 1;
+ } else {
+ m.flipLegs = -1;
+ }
+ ctx.save();
+ ctx.scale(m.flipLegs, 1); //leg lines
+ ctx.beginPath();
+ ctx.moveTo(m.hip.x, m.hip.y);
+ ctx.lineTo(m.knee.x, m.knee.y);
+ ctx.lineTo(m.foot.x, m.foot.y);
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = 7;
+ ctx.stroke();
+
+ //toe lines
+ ctx.beginPath();
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x - 15, m.foot.y + 5);
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x + 15, m.foot.y + 5);
+ ctx.lineWidth = 4;
+ ctx.stroke();
+
+ //hip joint
+ ctx.beginPath();
+ ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI);
+ //knee joint
+ ctx.moveTo(m.knee.x + 7, m.knee.y);
+ ctx.arc(m.knee.x, m.knee.y, 7, 0, 2 * Math.PI);
+ //foot joint
+ ctx.moveTo(m.foot.x + 6, m.foot.y);
+ ctx.arc(m.foot.x, m.foot.y, 6, 0, 2 * Math.PI);
+ ctx.strokeStyle = "rgba(0,255,255,0.25)";
+ ctx.lineWidth = 5;
+ ctx.stroke();
+ ctx.fillStyle = m.fillColor;
+ ctx.fill();
+ ctx.restore();
+ }
+ },
+ tungsten() {
+ m.isAltSkin = true
+ m.color = {
+ hue: 210,
+ sat: 5,
+ light: 75,
+ }
+ // m.setFillColors();
+ m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)`
+ m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 50}%)`
+ const grd = ctx.createLinearGradient(-30, -5, 30, 10);
+ grd.addColorStop(0, `#e0e0e0`);
+ grd.addColorStop(0.3, `#bbb`);
+ grd.addColorStop(0.4, `#b3b3b3`);
+ grd.addColorStop(0.5, `#c5c5c5`);
+ grd.addColorStop(0.65, `#bbb`);
+ grd.addColorStop(0.7, `#b3b3b3`);
+ grd.addColorStop(0.75, `#bbb`);
+ grd.addColorStop(1, `#e0e0e0`);
+ // const grdRad = ctx.createRadialGradient(0, 0, 0, 0, 0, 30);
+ // grdRad.addColorStop(0, `rgba(0,0,0,0.3)`);
+ // grdRad.addColorStop(0.5, `rgba(210,210,210,0)`);
+ m.bodyGradient = grd
+
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(4.2, -3);
+ m.drawLeg("#666");
+ m.calcLeg(2.1, -1);
+ m.drawLeg("#5f5f5f");
+ m.calcLeg(0, 1);
+ m.drawLeg("#555");
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ // ctx.fillStyle = grdRad
+ // ctx.fill();
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 1.5;
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.fillStyle = "#fff"
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.stroke();
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+ }
+ m.drawLeg = function (stroke) {
+ // if (simulation.mouseInGame.x > m.pos.x) {
+ if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
+ m.flipLegs = 1;
+ } else {
+ m.flipLegs = -1;
+ }
+ ctx.save();
+ ctx.scale(m.flipLegs, 1); //leg lines
+ ctx.beginPath();
+ ctx.moveTo(m.hip.x, m.hip.y);
+ ctx.lineTo(m.knee.x, m.knee.y);
+ ctx.lineTo(m.foot.x, m.foot.y);
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = 4.5;
+ ctx.stroke();
+
+ //toe lines
+ ctx.beginPath();
+ ctx.moveTo(m.foot.x, m.foot.y - 1);
+ ctx.lineTo(m.foot.x - 15, m.foot.y + 5);
+ ctx.lineTo(m.foot.x + 15, m.foot.y + 5);
+ ctx.lineTo(m.foot.x, m.foot.y - 1);
+ ctx.lineWidth = 4;
+ ctx.stroke();
+
+ //hip joint
+ ctx.beginPath();
+ ctx.arc(m.hip.x, m.hip.y - 4, 12, 0, 2 * Math.PI);
+ //knee joint
+ ctx.moveTo(m.knee.x + 6, m.knee.y);
+ ctx.arc(m.knee.x, m.knee.y, 6, 0, 2 * Math.PI);
+ //foot joint
+ ctx.moveTo(m.foot.x + 5, m.foot.y);
+ ctx.arc(m.foot.x, m.foot.y, 5, 0, 2 * Math.PI);
+ ctx.fillStyle = m.fillColor;
+ ctx.fill();
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = "#000"
+ ctx.stroke();
+ ctx.restore();
+ }
+
+ },
+ anodize() {
+ m.isAltSkin = true
+ m.color = {
+ hue: 210,
+ sat: 14,
+ light: 65,
+ }
+ // m.setFillColors();
+ m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)`
+ m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 50}%)`
+ // let grd = ctx.createLinearGradient(-30, 0, 30, 0);
+ const grd = ctx.createRadialGradient(16, 0, 0, 0, 0, 40);
+
+ // grd.addColorStop(0, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 35}%)`);
+ // grd.addColorStop(0.25, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 20}%)`);
+ // grd.addColorStop(0.5, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 35}%)`);
+ // grd.addColorStop(1, `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 10}%)`);
+
+ grd.addColorStop(0, `#c78034`);
+ grd.addColorStop(0.04, `#bd5235`);
+ grd.addColorStop(0.08, `#ab554d`);
+ grd.addColorStop(0.12, `#8f5d8f`);
+ grd.addColorStop(0.16, `#4352ab`);
+ grd.addColorStop(0.2, `#2058b3`);
+ grd.addColorStop(0.24, `#1a6fc4`);
+ grd.addColorStop(0.28, `#1b85cf`);
+ grd.addColorStop(0.32, `#2d9bd7`);
+ grd.addColorStop(0.4, `#d2d7b4`);
+ grd.addColorStop(0.44, `#e1cd87`);
+ grd.addColorStop(0.48, `#f0b955`);
+ grd.addColorStop(0.52, `#ffa050`);
+ grd.addColorStop(0.56, `#ff8269`);
+ grd.addColorStop(0.6, `#f5697d`);
+ grd.addColorStop(0.64, `#e65aaf`);
+ grd.addColorStop(0.68, `#d732d7`);
+ grd.addColorStop(0.72, `#c846e6`);
+ grd.addColorStop(0.76, `#c850fa`);
+ grd.addColorStop(0.8, `#878cf0`);
+ grd.addColorStop(0.84, `#37beeb`);
+ grd.addColorStop(0.88, `#00d2be`);
+ grd.addColorStop(0.92, `#00e19b`);
+ grd.addColorStop(0.96, `#19f5aa`);
+ grd.addColorStop(1, `#aaf5af`);
+
+ m.bodyGradient = grd
+
+
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -3);
+ m.drawLeg("#4a4a5a");
+ m.calcLeg(0, 0);
+ m.drawLeg("#445");
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ // ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#222";
+ ctx.lineWidth = 2;
+ // ctx.stroke();
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+ }
+ m.drawLeg = function (stroke) {
+ // if (simulation.mouseInGame.x > m.pos.x) {
+ if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
+ m.flipLegs = 1;
+ } else {
+ m.flipLegs = -1;
+ }
+ ctx.save();
+ ctx.scale(m.flipLegs, 1); //leg lines
+ ctx.beginPath();
+ ctx.moveTo(m.hip.x, m.hip.y);
+ ctx.lineTo(m.knee.x, m.knee.y);
+ ctx.lineTo(m.foot.x, m.foot.y);
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = 7;
+ ctx.stroke();
+
+ //toe lines
+ ctx.beginPath();
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x - 15, m.foot.y + 5);
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x + 15, m.foot.y + 5);
+ ctx.lineWidth = 4;
+ ctx.stroke();
+
+ //hip joint
+ ctx.beginPath();
+ ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI);
+ ctx.fillStyle = "#1b85cf";
+ ctx.fill();
+ //knee joint
+ ctx.beginPath();
+ ctx.arc(m.knee.x, m.knee.y, 7, 0, 2 * Math.PI);
+ ctx.fillStyle = "#ffa050";
+ ctx.fill();
+ //foot joint
+ ctx.beginPath();
+ ctx.arc(m.foot.x, m.foot.y, 6, 0, 2 * Math.PI);
+ ctx.fillStyle = "#878cf0";
+ ctx.fill();
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.restore();
+ }
+ },
+ dilate() {
+ m.isAltSkin = true
+ simulation.isAutoZoom = false;
+ m.draw = function () {
+ const amplitude = 8 + 4 * Math.sin(m.cycle * 0.0075)
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -3);
+ m.drawLeg("#456");
+ m.calcLeg(0, 0);
+ m.drawLeg("#345");
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.strokeStyle = "#345";
+ ctx.lineWidth = 2;
+ ctx.arc(12, 0, amplitude, 0, 2 * Math.PI); //big eye
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(12, 0, amplitude, 0, 2 * Math.PI); //big eye
+ // ctx.fillStyle = `hsl(0,0%,${50+50*Math.sin(m.cycle * 0.0075+Math.PI)}%)` //`hsl(${150+50*Math.sin(m.cycle * 0.0075)},100%,50%)`
+ // ctx.fill();
+ ctx.stroke();
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+
+ //zoom camera in and out
+
+ // console.log(simulation.zoomScale)
+ simulation.setZoom(1800 + 400 * Math.sin(m.cycle * 0.0075))
+
+
+ }
+ },
+ dilate2() {
+ m.isAltSkin = true
+ m.draw = function () {
+ const amplitude = Math.sin(m.cycle * 0.0075)
+
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -3);
+ m.drawLeg("#456");
+ m.calcLeg(0, 0);
+ m.drawLeg("#345");
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.strokeStyle = "#345";
+ ctx.lineWidth = 3 + 3 * Math.sin(m.cycle * 0.0075 + Math.PI);
+ ctx.stroke();
+ // ctx.arc(12, 0, 8 + 4 * amplitude, 0, 2 * Math.PI); //big eye
+ ctx.beginPath();
+ ctx.arc(12, 0, 8 + 4 * amplitude, 0, 2 * Math.PI); //big eye
+ ctx.fillStyle = "#345"
+ // ctx.fillStyle = //`hsl(0,0%,${50+50*Math.sin(m.cycle * 0.0075+Math.PI)}%)` //`hsl(${150+50*Math.sin(m.cycle * 0.0075)},100%,50%)`
+ // ctx.fillStyle = `hsl(${150 + 100 * amplitude},100%,50%)`
+ ctx.fill();
+ // ctx.stroke();
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+ simulation.setZoom(1800 + 400 * Math.sin(m.cycle * 0.0075))
+ }
+ m.drawLeg = function (stroke) {
+ // if (simulation.mouseInGame.x > m.pos.x) {
+ if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
+ m.flipLegs = 1;
+ } else {
+ m.flipLegs = -1;
+ }
+ ctx.save();
+ ctx.scale(m.flipLegs, 1); //leg lines
+ ctx.beginPath();
+ ctx.moveTo(m.hip.x, m.hip.y);
+ ctx.lineTo(m.knee.x, m.knee.y);
+ ctx.lineTo(m.foot.x, m.foot.y);
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = 6 + 2 * Math.sin(m.cycle * 0.0075 + Math.PI);
+ ctx.stroke();
+
+ //toe lines
+ ctx.beginPath();
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x - 15, m.foot.y + 5);
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x + 15, m.foot.y + 5);
+ ctx.lineWidth = 4;
+ ctx.stroke();
+
+ //hip joint
+ ctx.beginPath();
+ ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI);
+ //knee joint
+ ctx.moveTo(m.knee.x + 7, m.knee.y);
+ ctx.arc(m.knee.x, m.knee.y, 7, 0, 2 * Math.PI);
+ //foot joint
+ ctx.moveTo(m.foot.x + 6, m.foot.y);
+ ctx.arc(m.foot.x, m.foot.y, 6, 0, 2 * Math.PI);
+ ctx.fillStyle = "#345";
+ ctx.fill();
+ ctx.lineWidth = 3 + 3 * Math.sin(m.cycle * 0.0075 + Math.PI);
+ ctx.stroke();
+ ctx.restore();
+ }
+ },
+ CPT() {
+ m.isAltSkin = true
+ m.color = {
+ hue: 0,
+ sat: 0,
+ light: 100,
+ }
+ // m.setFillColors();
+ m.fillColor = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light}%)`
+ m.fillColorDark = `hsl(${m.color.hue},${m.color.sat}%,${m.color.light - 35}%)`
+ let grd = ctx.createLinearGradient(-30, 0, 30, 0);
+ grd.addColorStop(0, m.fillColorDark);
+ grd.addColorStop(0.7, m.fillColor);
+ // grd.addColorStop(1, m.fillColor);
+ m.bodyGradient = grd
+
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -3);
+ m.drawLeg("#eee");
+ m.calcLeg(0, 0);
+ m.drawLeg("#fff");
+ ctx.rotate(0.017 * simulation.cycle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.restore();
+
+ ctx.beginPath();
+ ctx.arc(m.pos.x + 15 * Math.cos(m.angle), m.pos.y + 15 * Math.sin(m.angle), 5, 0, 2 * Math.PI);
+ ctx.fillStyle = "#000"
+ ctx.fill();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+ }
+ m.drawLeg = function (stroke) {
+ // if (simulation.mouseInGame.x > m.pos.x) {
+ if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
+ m.flipLegs = 1;
+ } else {
+ m.flipLegs = -1;
+ }
+ ctx.save();
+ ctx.scale(m.flipLegs, 1); //leg lines
+ ctx.beginPath();
+ ctx.moveTo(m.hip.x, m.hip.y);
+ ctx.lineTo(m.knee.x, m.knee.y);
+ ctx.lineTo(m.foot.x, m.foot.y);
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = 6;
+ ctx.stroke();
+
+ //toe lines
+ ctx.beginPath();
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x - 15, m.foot.y + 5);
+ ctx.moveTo(m.foot.x, m.foot.y);
+ ctx.lineTo(m.foot.x + 15, m.foot.y + 5);
+ ctx.lineWidth = 3;
+ ctx.stroke();
+
+ //hip joint
+ ctx.beginPath();
+ ctx.arc(m.hip.x, m.hip.y, 11, 0, 2 * Math.PI);
+ //knee joint
+ ctx.moveTo(m.knee.x + 5, m.knee.y);
+ ctx.arc(m.knee.x, m.knee.y, 5, 0, 2 * Math.PI);
+ //foot joint
+ ctx.moveTo(m.foot.x + 5, m.foot.y);
+ ctx.arc(m.foot.x, m.foot.y, 5, 0, 2 * Math.PI);
+ ctx.fillStyle = "#000";
+ ctx.fill();
+ // ctx.lineWidth = 2;
+ // ctx.stroke();
+ ctx.restore();
+ }
+ },
+ stubs() {
+ m.isAltSkin = true
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5 //|| (m.cycle % 40 > 20)
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -3);
+ m.drawLeg("#555");
+ m.calcLeg(0, 0);
+ m.drawLeg("#333");
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+ }
+ m.drawLeg = function (stroke) {
+ // if (simulation.mouseInGame.x > m.pos.x) {
+ if (m.angle > -Math.PI / 2 && m.angle < Math.PI / 2) {
+ m.flipLegs = 1;
+ } else {
+ m.flipLegs = -1;
+ }
+ ctx.save();
+ ctx.scale(m.flipLegs, 1); //leg lines
+ ctx.beginPath();
+ ctx.moveTo(m.hip.x, m.hip.y);
+ ctx.lineTo(m.knee.x, m.knee.y);
+ ctx.lineTo(m.foot.x, m.foot.y + 5);
+ ctx.strokeStyle = stroke;
+ ctx.lineWidth = 6;
+ ctx.stroke();
+ ctx.restore();
+ }
+ },
+ Sleipnir() {
+ m.isAltSkin = true
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5
+ ctx.translate(m.pos.x, m.pos.y);
+ for (let i = 0; i < 16; i++) {
+ m.calcLeg(Math.PI * i / 8, -3 * i / 16)
+ m.drawLeg("#444")
+ }
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ }
+ },
+ diegesis() {
+ m.isAltSkin = true
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -3);
+ m.drawLeg("#4a4a4a");
+ m.calcLeg(0, 0);
+ m.drawLeg("#333");
+ ctx.rotate(m.angle - (m.fireCDcycle !== Infinity ? m.flipLegs * 0.25 * Math.pow(Math.max(m.fireCDcycle - m.cycle, 0), 0.5) : 0));
+
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ }
+ },
+ cat() {
+ m.isAltSkin = true
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -3);
+ m.drawLeg("#4a4a4a");
+
+
+ if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) {
+ ctx.scale(1, -1);
+ ctx.rotate(Math.PI);
+ }
+ ctx.beginPath();
+ ctx.moveTo(-30, 0);
+ ctx.bezierCurveTo(-65, -75,
+ -5, 150 + (5 * Math.sin(simulation.cycle / 10)),
+ -70 + (10 * Math.sin(simulation.cycle / 10)), 0 + (10 * Math.sin(simulation.cycle / 10)));
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 4;
+ ctx.stroke();
+
+ if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) {
+ ctx.scale(1, -1);
+ ctx.rotate(0 - Math.PI);
+ }
+ m.calcLeg(0, 0);
+ m.drawLeg("#333");
+
+ ctx.rotate(m.angle);
+ if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) ctx.scale(1, -1);
+ ctx.beginPath();
+ ctx.moveTo(5, -30);
+ ctx.lineTo(20, -40);
+ ctx.lineTo(20, -20);
+ ctx.lineWidth = 2;
+ ctx.fillStyle = "#f3f";
+ ctx.fill();
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.stroke();
+ ctx.moveTo(19, 0);
+ ctx.arc(15, 0, 4, Math.PI, 2 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(24.3, 6, 5, Math.PI * 2, Math.PI);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.moveTo(30, 6);
+ ctx.lineTo(32, 0);
+ ctx.lineTo(26, 0);
+ ctx.lineTo(30, 6);
+ ctx.fillStyle = "#f3f";
+ ctx.fill();
+ ctx.stroke();
+
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ }
+ },
+ pareidolia() {
+ m.isAltSkin = true
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.7
+ ctx.translate(m.pos.x, m.pos.y);
+ m.calcLeg(Math.PI, -3);
+ m.drawLeg("#4a4a4a");
+ m.calcLeg(0, 0);
+ m.drawLeg("#333");
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ if (!(m.angle > -Math.PI / 2 && m.angle < Math.PI / 2)) ctx.scale(1, -1); //here is the flip
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(2, -6, 7, 0, 2 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(25, -6, 7, 0.25 * Math.PI, 1.6 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(2, -10, 9, 1.25 * Math.PI, 1.75 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(25, -10, 9, 1.25 * Math.PI, 1.4 * Math.PI);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(18, 13, 10, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient;
+ ctx.fill();
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(18, 13, 6, 0, 2 * Math.PI);
+ ctx.fillStyle = "#555";
+ ctx.fill();
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(3, -6, 3, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(26, -6, 3, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.stroke();
+ ctx.restore();
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15;
+ }
+ },
+ flipFlop() {
+ m.isAltSkin = true
+ m.draw = function () {
+ ctx.fillStyle = m.fillColor;
+ m.walk_cycle += m.flipLegs * m.Vx;
+
+ //draw body
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5
+ ctx.translate(m.pos.x, m.pos.y);
+
+ m.calcLeg(Math.PI, -3);
+ m.drawLeg("#4a4a4a");
+ m.calcLeg(0, 0);
+ m.drawLeg("#333");
+
+ ctx.rotate(m.angle);
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ //draw eye
+ ctx.beginPath();
+ ctx.arc(15, 0, 3.5, 0, 2 * Math.PI);
+ ctx.fillStyle = m.eyeFillColor;
+ ctx.fill()
+ ctx.restore();
+
+ m.yOff = m.yOff * 0.85 + m.yOffGoal * 0.15; //smoothly move leg height towards height goal
+ powerUps.boost.draw()
+ }
+ }
+ },
+ // *********************************************
+ // **************** fields *********************
+ // *********************************************
+ closest: {
+ dist: 1000,
+ index: 0
+ },
+ isHolding: false,
+ isCloak: false,
+ throwCharge: 0,
+ fireCDcycle: 0,
+ fieldCDcycle: 0,
+ fieldMode: 0, //basic field mode before upgrades
+ maxEnergy: 1, //can be increased by a tech
+ holdingTarget: null,
+ timeSkipLastCycle: 0,
+ coupling: 0,
+ // these values are set on reset by setHoldDefaults()
+ fieldFx: 1,
+ fieldJump: 1,
+ blockingRecoil: 4,
+ grabPowerUpRange2: 0,
+ isFieldActive: false,
+ fieldRange: 155,
+ fieldShieldingScale: 1,
+ // fieldDamage: 1,
+ isSneakAttack: false,
+ lastHit: 0, //stores value of last damage player took above a threshold, in m.damage
+ sneakAttackCycle: 0,
+ enterCloakCycle: 0,
+ duplicateChance: 0,
+ energy: 0,
+ fieldRegen: 0.001,
+ fieldMode: 0,
+ fieldFire: false,
+ fieldHarmReduction: 1,
+ holdingMassScale: 0,
+ hole: {
+ isOn: false,
+ isReady: false,
+ pos1: {
+ x: 0,
+ y: 0
+ },
+ pos2: {
+ x: 0,
+ y: 0
+ },
+ },
+ fieldArc: 0,
+ fieldThreshold: 0,
+ calculateFieldThreshold() {
+ m.fieldThreshold = Math.cos((m.fieldArc) * Math.PI)
+ },
+ setHoldDefaults() {
+ if (tech.isFreeWormHole && m.fieldMode !== 9) { //not wormhole
+ const removed = tech.removeTech("charmed baryon") //neutronum can get player stuck so it has to be removed if player has wrong field
+ if (removed) powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
+ }
+ if (tech.isNeutronium && m.fieldMode !== 3) { //not negative mass field
+ const removed = tech.removeTech("neutronium") //neutronum can get player stuck so it has to be removed if player has wrong field
+ if (removed) powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
+ }
+ if (m.energy < m.maxEnergy) m.energy = m.maxEnergy;
+ m.fieldMeterColor = "#0cf"
+ m.eyeFillColor = m.fieldMeterColor
+ m.fieldShieldingScale = 1;
+ m.fieldBlockCD = 10;
+ m.fieldHarmReduction = 1;
+ m.lastHit = 0
+ m.isSneakAttack = false
+ m.duplicateChance = 0
+ m.grabPowerUpRange2 = 200000;
+ m.blockingRecoil = 4;
+ m.fieldRange = 155;
+ m.fieldFire = false;
+ m.fieldCDcycle = 0;
+ m.isCloak = false;
+ player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield
+ m.airSpeedLimit = 125
+ m.fieldFx = 1
+ m.fieldJump = 1
+ m.setFieldRegen();
+ m.setMovement();
+ m.drop();
+ m.holdingMassScale = 0.5;
+ m.fieldArc = 0.2; //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob)
+ m.calculateFieldThreshold(); //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob)
+ m.isBodiesAsleep = true;
+ m.wakeCheck();
+ m.setMaxEnergy();
+ m.setMaxHealth();
+ m.couplingChange()
+ m.hole = {
+ isOn: false,
+ isReady: false,
+ pos1: {
+ x: 0,
+ y: 0
+ },
+ pos2: {
+ x: 0,
+ y: 0
+ },
+ }
+ },
+ setMaxEnergy(isMessage = true) {
+ m.maxEnergy = (tech.isMaxEnergyTech ? 0.5 : 1) + tech.bonusEnergy + tech.healMaxEnergyBonus + tech.harmonicEnergy + 2.66 * tech.isGroundState + 3 * tech.isRelay * tech.isFlipFlopOn * tech.isRelayEnergy + 1.5 * (m.fieldMode === 1) + (m.fieldMode === 0 || m.fieldMode === 1) * 0.05 * m.coupling + 0.4 * tech.isStandingWaveExpand
+ if (isMessage) simulation.makeTextLog(`
m .
maxEnergy = ${(m.maxEnergy.toFixed(2))}`)
+ },
+ fieldMeterColor: "#0cf",
+ drawRegenEnergy(bgColor = "rgba(0, 0, 0, 0.4)", range = 60) {
+ if (m.energy < m.maxEnergy) {
+ m.regenEnergy();
+ ctx.fillStyle = bgColor;
+ const xOff = m.pos.x - m.radius * m.maxEnergy
+ const yOff = m.pos.y - 50
+ ctx.fillRect(xOff, yOff, range * m.maxEnergy, 10);
+ ctx.fillStyle = m.fieldMeterColor;
+ ctx.fillRect(xOff, yOff, range * m.energy, 10);
+ } else if (m.energy > m.maxEnergy + 0.05) {
+ ctx.fillStyle = bgColor;
+ const xOff = m.pos.x - m.radius * m.energy
+ const yOff = m.pos.y - 50
+ // ctx.fillRect(xOff, yOff, range * m.maxEnergy, 10);
+ ctx.fillStyle = m.fieldMeterColor;
+ ctx.fillRect(xOff, yOff, range * m.energy, 10);
+ }
+ },
+ drawRegenEnergyCloaking: function () {
+ if (m.energy < m.maxEnergy) { // replaces m.drawRegenEnergy() with custom code
+ m.regenEnergy();
+ const xOff = m.pos.x - m.radius * m.maxEnergy
+ const yOff = m.pos.y - 50
+ ctx.fillStyle = "rgba(0, 0, 0, 0.2)" //
+ ctx.fillRect(xOff, yOff, 60 * m.maxEnergy, 10);
+ ctx.fillStyle = "#fff" //m.cycle > m.lastKillCycle + 300 ? "#000" : "#fff" //"#fff";
+ ctx.fillRect(xOff, yOff, 60 * m.energy, 10);
+ ctx.beginPath()
+ ctx.rect(xOff, yOff, 60 * m.maxEnergy, 10);
+ ctx.strokeStyle = m.fieldMeterColor;
+ ctx.lineWidth = 1;
+ ctx.stroke();
+ }
+ },
+ setFieldRegen() {
+ if (m.fieldMode === 6) {
+ m.fieldRegen = 0.002 //12 energy per second for time dilation
+ } else if (m.fieldMode === 2) {
+ m.fieldRegen = 0.000833 //5 energy per second perfect dia
+ } else if (m.fieldMode === 4) {
+ m.fieldRegen = 0.002 //12 energy per second molecular assembler
+ } else if (m.fieldMode === 5) {
+ m.fieldRegen = 0.001667 //10 energy per second plasma torch
+ } else if (m.fieldMode === 8) {
+ m.fieldRegen = 0.001667 //10 energy per second pilot wave
+ } else {
+ m.fieldRegen = 0.001 //6 energy per second
+ }
+ if (m.fieldMode === 0 || m.fieldMode === 4) m.fieldRegen += 0.000133 * m.coupling //return `generate
${(6*couple).toFixed(0)} energy per second`
+ if (tech.isTimeCrystals) {
+ m.fieldRegen *= 2.5
+ } else if (tech.isGroundState) {
+ m.fieldRegen *= 0.66
+ }
+ },
+ regenEnergy() { //used in drawRegenEnergy // rewritten by some tech
+ if (m.immuneCycle < m.cycle && m.fieldCDcycle < m.cycle) m.energy += m.fieldRegen;
+ if (m.energy < 0) m.energy = 0
+ },
+ regenEnergyDefault() {
+ if (m.immuneCycle < m.cycle && m.fieldCDcycle < m.cycle) m.energy += m.fieldRegen;
+ if (m.energy < 0) m.energy = 0
+ },
+ lookingAt(who) {
+ //calculate a vector from body to player and make it length 1
+ const diff = Vector.normalise(Vector.sub(who.position, m.pos));
+ //make a vector for the player's direction of length 1
+ const dir = {
+ x: Math.cos(m.angle),
+ y: Math.sin(m.angle)
+ };
+ //the dot product of diff and dir will return how much over lap between the vectors
+ if (Vector.dot(dir, diff) > m.fieldThreshold) {
+ return true;
+ }
+ return false;
+ },
+ drop() {
+ if (m.isHolding) {
+ m.fieldCDcycle = m.cycle + 15;
+ m.isHolding = false;
+ m.throwCharge = 0;
+ m.definePlayerMass()
+ }
+ if (m.holdingTarget) {
+ m.holdingTarget.collisionFilter.category = cat.body;
+ m.holdingTarget.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
+ m.holdingTarget = null;
+ }
+ },
+ definePlayerMass(mass = m.defaultMass) {
+ Matter.Body.setMass(player, mass);
+ //reduce air and ground move forces
+ m.setMovement()
+ // m.Fx = 0.08 / mass * tech.squirrelFx //base player mass is 5
+ // m.FxAir = 0.4 / mass / mass //base player mass is 5
+ //make player stand a bit lower when holding heavy masses
+ m.yOffWhen.stand = Math.max(m.yOffWhen.crouch, Math.min(49, 49 - (mass - 5) * 6))
+ if (m.onGround && !m.crouch) m.yOffGoal = m.yOffWhen.stand;
+ },
+ drawHold(target, stroke = true) {
+ if (target) {
+ const eye = 15;
+ const len = target.vertices.length - 1;
+ ctx.fillStyle = "rgba(110,170,200," + (0.2 + 0.4 * Math.random()) + ")";
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = "#000";
+ ctx.beginPath();
+ ctx.moveTo(
+ m.pos.x + eye * Math.cos(m.angle),
+ m.pos.y + eye * Math.sin(m.angle)
+ );
+ ctx.lineTo(target.vertices[len].x, target.vertices[len].y);
+ ctx.lineTo(target.vertices[0].x, target.vertices[0].y);
+ ctx.fill();
+ if (stroke) ctx.stroke();
+ for (let i = 0; i < len; i++) {
+ ctx.beginPath();
+ ctx.moveTo(
+ m.pos.x + eye * Math.cos(m.angle),
+ m.pos.y + eye * Math.sin(m.angle)
+ );
+ ctx.lineTo(target.vertices[i].x, target.vertices[i].y);
+ ctx.lineTo(target.vertices[i + 1].x, target.vertices[i + 1].y);
+ ctx.fill();
+ if (stroke) ctx.stroke();
+ }
+ }
+ },
+ holding() {
+ if (m.fireCDcycle < m.cycle) m.fireCDcycle = m.cycle - 1
+ if (m.holdingTarget) {
+ m.energy -= m.fieldRegen;
+ if (m.energy < 0) m.energy = 0;
+ Matter.Body.setPosition(m.holdingTarget, {
+ x: m.pos.x + 70 * Math.cos(m.angle),
+ y: m.pos.y + 70 * Math.sin(m.angle)
+ });
+ Matter.Body.setVelocity(m.holdingTarget, player.velocity);
+ Matter.Body.rotate(m.holdingTarget, 0.01 / m.holdingTarget.mass); //gently spin the block
+ } else {
+ m.isHolding = false
+ }
+ },
+ throwBlock() {
+ if (m.holdingTarget) {
+ if (input.field) {
+ if (m.energy > 0.001) {
+ if (m.fireCDcycle < m.cycle) m.fireCDcycle = m.cycle
+ if (tech.isCapacitor && m.throwCharge < 4) m.throwCharge = 4
+ m.throwCharge += 0.5 / m.holdingTarget.mass / b.fireCDscale
+ if (m.throwCharge < 6) m.energy -= 0.001 / b.fireCDscale; // m.throwCharge caps at 5
+
+ //trajectory path prediction
+ if (tech.isTokamak) {
+ //draw charge
+ const x = m.pos.x + 15 * Math.cos(m.angle);
+ const y = m.pos.y + 15 * Math.sin(m.angle);
+ const len = m.holdingTarget.vertices.length - 1;
+ const opacity = m.throwCharge > 4 ? 0.65 : m.throwCharge * 0.06
+ ctx.fillStyle = `rgba(255,0,255,${opacity})`;
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(m.holdingTarget.vertices[len].x, m.holdingTarget.vertices[len].y);
+ ctx.lineTo(m.holdingTarget.vertices[0].x, m.holdingTarget.vertices[0].y);
+ ctx.fill();
+ for (let i = 0; i < len; i++) {
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(m.holdingTarget.vertices[i].x, m.holdingTarget.vertices[i].y);
+ ctx.lineTo(m.holdingTarget.vertices[i + 1].x, m.holdingTarget.vertices[i + 1].y);
+ ctx.fill();
+ }
+ } else {
+ //draw charge
+ const x = m.pos.x + 15 * Math.cos(m.angle);
+ const y = m.pos.y + 15 * Math.sin(m.angle);
+ const len = m.holdingTarget.vertices.length - 1;
+ const edge = m.throwCharge * m.throwCharge * m.throwCharge;
+ const grd = ctx.createRadialGradient(x, y, edge, x, y, edge + 5);
+ grd.addColorStop(0, "rgba(255,50,150,0.3)");
+ grd.addColorStop(1, "transparent");
+ ctx.fillStyle = grd;
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(m.holdingTarget.vertices[len].x, m.holdingTarget.vertices[len].y);
+ ctx.lineTo(m.holdingTarget.vertices[0].x, m.holdingTarget.vertices[0].y);
+ ctx.fill();
+ for (let i = 0; i < len; i++) {
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(m.holdingTarget.vertices[i].x, m.holdingTarget.vertices[i].y);
+ ctx.lineTo(m.holdingTarget.vertices[i + 1].x, m.holdingTarget.vertices[i + 1].y);
+ ctx.fill();
+ }
+ //trajectory prediction
+ const cycles = 30
+ const charge = Math.min(m.throwCharge / 5, 1)
+ const speed = (tech.isPrinter ? 15 + 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.1)) : 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.25)))
+ const v = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) }
+ ctx.beginPath()
+ for (let i = 1, len = 10; i < len + 1; i++) {
+ const time = cycles * i / len
+ ctx.lineTo(m.pos.x + time * v.x, m.pos.y + time * v.y + 0.34 * time * time)
+ }
+ ctx.strokeStyle = "rgba(68, 68, 68, 0.15)" //color.map
+ ctx.lineWidth = 2
+ ctx.stroke()
+ }
+ } else {
+ m.drop()
+ }
+ } else if (m.throwCharge > 0) { //Matter.Query.region(mob, player.bounds)
+ if (m.holdingTarget.isPrinted) m.holdingTarget.isPrinted = undefined
+ //throw the body
+ m.fieldCDcycle = m.cycle + 20;
+ m.fireCDcycle = m.cycle + 20;
+
+ m.isHolding = false;
+
+ if (tech.isTokamak && m.throwCharge > 4) { //remove the block body and pulse in the direction you are facing
+ //m.throwCharge > 5 seems to be when the field full colors in a block you are holding
+ m.throwCycle = m.cycle + 180 //used to detect if a block was thrown in the last 3 seconds
+ if (m.immuneCycle < m.cycle) m.energy += 0.25 * Math.sqrt(m.holdingTarget.mass) * Math.min(5, m.throwCharge)
+ m.throwCharge = 0;
+ m.definePlayerMass() //return to normal player mass
+ //remove block before pulse, so it doesn't get in the way
+ for (let i = 0; i < body.length; i++) {
+ if (body[i] === m.holdingTarget) {
+ Matter.Composite.remove(engine.world, body[i]);
+ body.splice(i, 1);
+ }
+ }
+ b.pulse(60 * Math.pow(m.holdingTarget.mass, 0.25), m.angle)
+ } else { //normal throw
+ //bullet-like collisions
+ m.holdingTarget.collisionFilter.category = cat.bullet
+ m.holdingTarget.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield;
+ if (tech.isBlockRestitution) {
+ m.holdingTarget.restitution = 0.999 //extra bouncy
+ m.holdingTarget.friction = m.holdingTarget.frictionStatic = m.holdingTarget.frictionAir = 0.001
+ }
+ //check every second to see if player is away from thrown body, and make solid
+ const solid = function (that) {
+ const dx = that.position.x - player.position.x;
+ const dy = that.position.y - player.position.y;
+ // if (that.speed < 3 && dx * dx + dy * dy > 10000 && that !== m.holdingTarget) {
+ if (dx * dx + dy * dy > 10000 && that !== m.holdingTarget) {
+ that.collisionFilter.category = cat.body; //make solid
+ that.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet; //can hit player now
+ } else {
+ setTimeout(solid, 40, that);
+ }
+ };
+ setTimeout(solid, 200, m.holdingTarget);
+
+ const charge = Math.min(m.throwCharge / 5, 1)
+ //***** scale throw speed with the first number, 80 *****
+ // let speed = 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.25));
+ let speed = (tech.isPrinter ? 15 + 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.1)) : 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.25)))
+
+ if (Matter.Query.collides(m.holdingTarget, map).length !== 0) {
+ speed *= 0.7 //drop speed by 30% if touching map
+ if (Matter.Query.ray(map, m.holdingTarget.position, m.pos).length !== 0) speed = 0 //drop to zero if the center of the block can't see the center of the player through the map
+ }
+ m.throwCharge = 0;
+ m.throwCycle = m.cycle + 180 //used to detect if a block was thrown in the last 3 seconds
+ Matter.Body.setVelocity(m.holdingTarget, {
+ x: player.velocity.x * 0.5 + Math.cos(m.angle) * speed,
+ y: player.velocity.y * 0.5 + Math.sin(m.angle) * speed
+ });
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x - Math.cos(m.angle) * speed / (m.crouch ? 30 : 10) * Math.sqrt(m.holdingTarget.mass),
+ y: player.velocity.y - Math.sin(m.angle) * speed / 30 * Math.sqrt(m.holdingTarget.mass)
+ });
+ m.definePlayerMass() //return to normal player mass
+
+ if (tech.isAddBlockMass) {
+ const expand = function (that, massLimit) {
+ if (that.mass < massLimit) {
+ const scale = 1.04;
+ Matter.Body.scale(that, scale, scale);
+ setTimeout(expand, 20, that, massLimit);
+ }
+ };
+ expand(m.holdingTarget, Math.min(20, m.holdingTarget.mass * 3))
+ }
+ }
+ }
+ } else {
+ m.isHolding = false
+ }
+ },
+ drawField() {
+ if (m.holdingTarget) {
+ ctx.fillStyle = "rgba(110,170,200," + (m.energy * (0.05 + 0.05 * Math.random())) + ")";
+ ctx.strokeStyle = "rgba(110, 200, 235, " + (0.3 + 0.08 * Math.random()) + ")" //"#9bd" //"rgba(110, 200, 235, " + (0.5 + 0.1 * Math.random()) + ")"
+ } else {
+ ctx.fillStyle = "rgba(110,170,200," + (0.02 + m.energy * (0.15 + 0.15 * Math.random())) + ")";
+ ctx.strokeStyle = "rgba(110, 200, 235, " + (0.6 + 0.2 * Math.random()) + ")" //"#9bd" //"rgba(110, 200, 235, " + (0.5 + 0.1 * Math.random()) + ")"
+ }
+ // const off = 2 * Math.cos(simulation.cycle * 0.1)
+ const range = m.fieldRange;
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, range, m.angle - Math.PI * m.fieldArc, m.angle + Math.PI * m.fieldArc, false);
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ let eye = 13;
+ let aMag = 0.75 * Math.PI * m.fieldArc
+ let a = m.angle + aMag
+ let cp1x = m.pos.x + 0.6 * range * Math.cos(a)
+ let cp1y = m.pos.y + 0.6 * range * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, m.pos.x + eye * Math.cos(m.angle), m.pos.y + eye * Math.sin(m.angle))
+ a = m.angle - aMag
+ cp1x = m.pos.x + 0.6 * range * Math.cos(a)
+ cp1y = m.pos.y + 0.6 * range * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, m.pos.x + 1 * range * Math.cos(m.angle - Math.PI * m.fieldArc), m.pos.y + 1 * range * Math.sin(m.angle - Math.PI * m.fieldArc))
+ ctx.fill();
+ // ctx.lineTo(m.pos.x + eye * Math.cos(m.angle), m.pos.y + eye * Math.sin(m.angle));
+
+ //draw random lines in field for cool effect
+ let offAngle = m.angle + 1.7 * Math.PI * m.fieldArc * (Math.random() - 0.5);
+ ctx.beginPath();
+ eye = 15;
+ ctx.moveTo(m.pos.x + eye * Math.cos(m.angle), m.pos.y + eye * Math.sin(m.angle));
+ ctx.lineTo(m.pos.x + range * Math.cos(offAngle), m.pos.y + range * Math.sin(offAngle));
+ ctx.strokeStyle = "rgba(120,170,255,0.6)";
+ ctx.lineWidth = 1;
+ ctx.stroke();
+ },
+ grabPowerUp() { //look for power ups to grab with field
+ if (m.fireCDcycle < m.cycle) m.fireCDcycle = m.cycle - 1
+ for (let i = 0, len = powerUp.length; i < len; ++i) {
+ const dxP = m.pos.x - powerUp[i].position.x;
+ const dyP = m.pos.y - powerUp[i].position.y;
+ const dist2 = dxP * dxP + dyP * dyP + 10;
+ // float towards player if looking at and in range or if very close to player
+ if (
+ dist2 < m.grabPowerUpRange2 &&
+ (m.lookingAt(powerUp[i]) || dist2 < 10000) &&
+ Matter.Query.ray(map, powerUp[i].position, m.pos).length === 0
+ ) {
+ if (!tech.isHealAttract || powerUp[i].name !== "heal") { //if you have accretion heals are already pulled in a different way
+ powerUp[i].force.x += 0.04 * (dxP / Math.sqrt(dist2)) * powerUp[i].mass;
+ powerUp[i].force.y += 0.04 * (dyP / Math.sqrt(dist2)) * powerUp[i].mass - powerUp[i].mass * simulation.g; //negate gravity
+ Matter.Body.setVelocity(powerUp[i], { x: powerUp[i].velocity.x * 0.11, y: powerUp[i].velocity.y * 0.11 }); //extra friction
+ }
+ if ( //use power up if it is close enough
+ dist2 < 5000 &&
+ !simulation.isChoosing &&
+ (powerUp[i].name !== "heal" || m.maxHealth - m.health > 0.01 || tech.isOverHeal)
+ ) {
+ powerUps.onPickUp(powerUp[i]);
+ Matter.Body.setVelocity(player, { //player knock back, after grabbing power up
+ x: player.velocity.x + powerUp[i].velocity.x / player.mass * 4 * powerUp[i].mass,
+ y: player.velocity.y + powerUp[i].velocity.y / player.mass * 4 * powerUp[i].mass
+ });
+ powerUp[i].effect();
+ Matter.Composite.remove(engine.world, powerUp[i]);
+ powerUp.splice(i, 1);
+ return; //because the array order is messed up after splice
+ }
+ }
+ }
+ },
+ minEnergyToDeflect: 0.05,
+ pushMass(who, fieldBlockCost = (0.025 + Math.sqrt(who.mass) * Vector.magnitude(Vector.sub(who.velocity, player.velocity)) * 0.002) * m.fieldShieldingScale) {
+ if (m.energy > m.minEnergyToDeflect) { //shield needs at least some of the cost to block
+ if (who.isShielded) fieldBlockCost *= 2; //shielded mobs take more energy to block
+ m.energy -= fieldBlockCost
+ if (m.energy < m.minEnergyToDeflect) {
+ m.energy = 0;
+ m.fieldCDcycle = m.cycle + Math.max(m.fieldBlockCD, 60);
+ if (tech.isLaserField) {
+ simulation.ephemera.push({
+ name: "laser field", //used to find this array element in simulation.removeEphemera()
+ count: 20 + Math.floor(m.maxEnergy * 30 * 0.0018 / tech.laserDrain), //how many cycles the ephemera lasts, scales with max energy
+ do() {
+ this.count--
+ if (this.count < 0) simulation.removeEphemera(this.name)
+ for (let i = 0, num = 12; i < num; i++) { //draw random lasers
+ const angle = 6.28 * i / num + m.cycle * 0.04
+ b.laser({ x: m.pos.x + 30 * Math.cos(angle), y: m.pos.y + 30 * Math.sin(angle) }, { x: m.pos.x + 3000 * Math.cos(angle), y: m.pos.y + 3000 * Math.sin(angle) }, tech.laserDamage * 2.5)//dmg = tech.laserDamage, reflections = tech.laserReflections, isThickBeam = false, push = 1
+ }
+ },
+ })
+ }
+ } else {
+ m.fieldCDcycle = m.cycle + m.fieldBlockCD;
+ }
+ if (!who.isInvulnerable && (m.coupling && m.fieldMode === 0) && bullet.length < 200) { //for field emitter iceIX
+ for (let i = 0; i < m.coupling; i++) {
+ if (0.1 * m.coupling - i > 1.25 * Math.random()) {
+ const sub = Vector.mult(Vector.normalise(Vector.sub(who.position, m.pos)), (m.fieldRange * m.harmonicRadius) * (0.4 + 0.3 * Math.random())) //m.harmonicRadius should be 1 unless you are standing wave expansion
+ const rad = Vector.rotate(sub, 1 * (Math.random() - 0.5))
+ const angle = Math.atan2(sub.y, sub.x)
+ b.iceIX(6 + 6 * Math.random(), angle + 3 * (Math.random() - 0.5), Vector.add(m.pos, rad))
+ }
+ }
+ }
+ const unit = Vector.normalise(Vector.sub(player.position, who.position))
+ if (tech.blockDmg) {
+ Matter.Body.setVelocity(who, { x: 0.5 * who.velocity.x, y: 0.5 * who.velocity.y });
+ if (who.isShielded) {
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].id === who.shieldID) mob[i].damage(tech.blockDmg * m.dmgScale * (tech.isBlockRadiation ? 6 : 2), true)
+ }
+ } else if (tech.isBlockRadiation) {
+ if (who.isMobBullet) {
+ who.damage(tech.blockDmg * m.dmgScale * 3, true)
+ } else {
+ mobs.statusDoT(who, tech.blockDmg * 0.42, 180) //200% increase -> x (1+2) //over 7s -> 360/30 = 12 half seconds -> 3/12
+ }
+ } else {
+ who.damage(tech.blockDmg * m.dmgScale, true)
+ }
+ const step = 40
+ ctx.beginPath(); //draw electricity
+ for (let i = 0, len = 0.5 * tech.blockDmg; i < len; i++) {
+ let x = m.pos.x - 20 * unit.x;
+ let y = m.pos.y - 20 * unit.y;
+ ctx.moveTo(x, y);
+ for (let i = 0; i < 8; i++) {
+ x += step * (-unit.x + 1.5 * (Math.random() - 0.5))
+ y += step * (-unit.y + 1.5 * (Math.random() - 0.5))
+ ctx.lineTo(x, y);
+ }
+ }
+ ctx.lineWidth = 3;
+ ctx.strokeStyle = "#f0f";
+ ctx.stroke();
+ } else {
+ m.drawHold(who);
+ }
+ if (tech.isStunField) mobs.statusStun(who, tech.isStunField)
+ //knock backs
+ const massRoot = Math.sqrt(Math.min(12, Math.max(0.15, who.mass))); // masses above 12 can start to overcome the push back
+ Matter.Body.setVelocity(who, { x: player.velocity.x - (15 * unit.x) / massRoot, y: player.velocity.y - (15 * unit.y) / massRoot });
+ if (who.isUnstable) {
+ if (m.fieldCDcycle < m.cycle + 30) m.fieldCDcycle = m.cycle + 10
+ who.death();
+ }
+ if (m.crouch) {
+ Matter.Body.setVelocity(player, { x: player.velocity.x + 0.1 * m.blockingRecoil * unit.x * massRoot, y: player.velocity.y + 0.1 * m.blockingRecoil * unit.y * massRoot });
+ } else {
+ Matter.Body.setVelocity(player, { x: player.velocity.x + m.blockingRecoil * unit.x * massRoot, y: player.velocity.y + m.blockingRecoil * unit.y * massRoot });
+ }
+ }
+ },
+ pushMobsFacing() { // find mobs in range and in direction looking
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (
+ Vector.magnitude(Vector.sub(mob[i].position, m.pos)) - mob[i].radius < m.fieldRange &&
+ m.lookingAt(mob[i]) &&
+ !mob[i].isUnblockable &&
+ Matter.Query.ray(map, mob[i].position, m.pos).length === 0
+ ) {
+ mob[i].locatePlayer();
+ m.pushMass(mob[i]);
+
+ if (tech.deflectEnergy && !mob[i].isInvulnerable && !mob[i].isShielded) {
+ m.energy += tech.deflectEnergy
+ }
+ }
+ }
+ },
+ lookForPickUp() { //find body to pickup
+ const grabbing = {
+ targetIndex: null,
+ targetRange: 150,
+ // lookingAt: false //false to pick up object in range, but not looking at
+ };
+ for (let i = 0, len = body.length; i < len; ++i) {
+ if (Matter.Query.ray(map, body[i].position, m.pos).length === 0) {
+ //is m next body a better target then my current best
+ const dist = Vector.magnitude(Vector.sub(body[i].position, m.pos));
+ const looking = m.lookingAt(body[i]);
+ // if (dist < grabbing.targetRange && (looking || !grabbing.lookingAt) && !body[i].isNotHoldable) {
+ if (dist < grabbing.targetRange && looking && !body[i].isNotHoldable) {
+ grabbing.targetRange = dist;
+ grabbing.targetIndex = i;
+ // grabbing.lookingAt = looking;
+ }
+ }
+ }
+ // set pick up target for when mouse is released
+ if (body[grabbing.targetIndex]) {
+ m.holdingTarget = body[grabbing.targetIndex];
+ //
+ ctx.beginPath(); //draw on each valid body
+ let vertices = m.holdingTarget.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j += 1) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.fillStyle = "rgba(190,215,230," + (0.3 + 0.7 * Math.random()) + ")";
+ ctx.fill();
+
+ ctx.globalAlpha = 0.2;
+ m.drawHold(m.holdingTarget);
+ ctx.globalAlpha = 1;
+ } else {
+ m.holdingTarget = null;
+ }
+ },
+ pickUp() {
+ //triggers when a hold target exits and field button is released
+ m.isHolding = true;
+ //conserve momentum when player mass changes
+ totalMomentum = Vector.add(Vector.mult(player.velocity, player.mass), Vector.mult(m.holdingTarget.velocity, m.holdingTarget.mass))
+ Matter.Body.setVelocity(player, Vector.mult(totalMomentum, 1 / (m.defaultMass + m.holdingTarget.mass)));
+
+ m.definePlayerMass(m.defaultMass + m.holdingTarget.mass * m.holdingMassScale)
+ //make block collide with nothing
+ m.holdingTarget.collisionFilter.category = 0;
+ m.holdingTarget.collisionFilter.mask = 0;
+ },
+ wakeCheck() {
+ if (m.isBodiesAsleep) {
+ m.isBodiesAsleep = false;
+
+ function wake(who) {
+ for (let i = 0, len = who.length; i < len; ++i) {
+ Matter.Sleeping.set(who[i], false)
+ if (who[i].storeVelocity) {
+ Matter.Body.setVelocity(who[i], {
+ x: who[i].storeVelocity.x,
+ y: who[i].storeVelocity.y
+ })
+ Matter.Body.setAngularVelocity(who[i], who[i].storeAngularVelocity)
+ }
+ }
+ }
+ // if (tech.isFreezeMobs) {
+ // for (let i = 0, len = mob.length; i < len; ++i) {
+ // const ICE_DRAIN = 0.0005
+ // if (m.energy > ICE_DRAIN) m.energy -= ICE_DRAIN;
+ // Matter.Sleeping.set(mob[i], false)
+ // mobs.statusSlow(mob[i], 60)
+ // }
+ // } else {
+ // wake(mob);
+ // }
+ wake(mob);
+ wake(body);
+ wake(bullet);
+ for (let i = 0, len = cons.length; i < len; i++) {
+ if (cons[i].stiffness === 0) {
+ cons[i].stiffness = cons[i].storeStiffness
+ }
+ }
+ // wake(powerUp);
+ }
+ },
+ hold() { },
+ couplingDescription(couple = m.coupling) {
+ switch (m.fieldMode) {
+ case 0: //field emitter
+ return `
all other
field effects`
+ case 1: //standing wave
+ // return `
deflecting condenses +${couple.toFixed(1)} ice IX `
+ return `+${(couple * 5).toFixed(0)} maximum
energy `
+ case 2: //perfect diamagnetism
+ return `
deflecting condenses ${(0.1 * couple).toFixed(2)} ice IX `
+ // return `
invulnerable +${2*couple} seconds post collision`
+ case 3: //negative mass
+ return `
+${(100 * (1 - 0.973 ** couple)).toFixed(1)}% defense `
+ case 4: //assembler
+ return `generate
${(0.8 * couple).toFixed(1)} energy per second`
+ case 5: //plasma
+ return `
+${(1.5 * couple).toFixed(1)}% damage `
+ case 6: //time dilation
+ return `
+${(5 * couple).toFixed(0)}% longer
stopped time ` //
movement ,
jumping , and
+ case 7: //cloaking
+ return `
+${(3.3 * couple).toFixed(1)}% ambush
damage `
+ case 8: //pilot wave
+ return `
+${(4 * couple).toFixed(0)}% block collision
damage `
+ case 9: //wormhole
+ return `
after eating blocks +${(2 * couple).toFixed(0)} energy `
+ }
+ },
+ couplingChange(change = 0) {
+ if (change > 0 && level.onLevel !== -1) simulation.makeTextLog(`m.coupling
+= ${change}`, 60); //level.onLevel !== -1 means not on lore level
+ m.coupling += change
+ if (m.coupling < 0) {
+ //look for coupling power ups on this level and remove them to prevent exploiting tech ejections
+ for (let i = powerUp.length - 1; i > -1; i--) {
+ if (powerUp[i].name === "coupling") {
+ Matter.Composite.remove(engine.world, powerUp[i]);
+ powerUp.splice(i, 1);
+ m.coupling += 1
+ if (!(m.coupling < 0)) break
+ }
+ }
+ m.coupling = 0 //can't go negative
+ }
+ m.setMaxEnergy(false);
+ // m.setMaxHealth();
+ m.setFieldRegen()
+ mobs.setMobSpawnHealth();
+ powerUps.setPowerUpMode();
+
+ // if ((m.fieldMode === 0 || m.fieldMode === 9) && !build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.4);
+ },
+ setField(index) {
+ if (isNaN(index)) { //find index by name
+ let found = false
+ for (let i = 0; i < m.fieldUpgrades.length; i++) {
+ if (index === m.fieldUpgrades[i].name) {
+ index = i;
+ found = true;
+ break;
+ }
+ }
+ if (!found) return //if you can't find the field don't give a field to avoid game crash
+ }
+ m.fieldMode = index;
+ document.getElementById("field").innerHTML = m.fieldUpgrades[index].name
+ m.setHoldDefaults();
+ m.fieldUpgrades[index].effect();
+ simulation.makeTextLog(`
m .setField("
${m.fieldUpgrades[m.fieldMode].name} ")`);
+ },
+ fieldUpgrades: [{
+ name: "field emitter",
+ imageNumber: Math.floor(Math.random() * 23),
+ description: `
initial field use
energy to
deflect mobs and
throw blocks
+
generate
6 energy per second`, //
100 max
energy
+ effect: () => {
+ m.hold = function () {
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ m.throwBlock();
+ } else if ((input.field && m.fieldCDcycle < m.cycle)) { //not hold but field button is pressed
+ if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
+ m.grabPowerUp();
+ m.lookForPickUp();
+ if (m.energy > m.minEnergyToDeflect) {
+ m.drawField();
+ m.pushMobsFacing();
+ }
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ m.pickUp();
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ }
+ m.drawRegenEnergy()
+ }
+ }
+ },
+ //
+ //
1
+ //
2
+ //
3
+ //
4
+ //
+ {
+ name: "standing wave",
+ //
deflecting protects you in every
direction
+ description: `
3 oscillating
shields are permanently active
+
+150 max
energy
+
generate
6 energy per second`,
+ drainCD: 0,
+ effect: () => {
+ m.fieldBlockCD = 0;
+ m.blockingRecoil = 1.5 //4 is normal
+ m.fieldRange = 185
+ m.fieldShieldingScale = 1.6 * Math.pow(0.5, (tech.harmonics - 2))
+ // m.fieldHarmReduction = 0.66; //33% reduction
+
+ m.harmonic3Phase = () => { //normal standard 3 different 2-d circles
+ const fieldRange1 = (0.75 + 0.3 * Math.sin(m.cycle / 23)) * m.fieldRange * m.harmonicRadius
+ const fieldRange2 = (0.68 + 0.37 * Math.sin(m.cycle / 37)) * m.fieldRange * m.harmonicRadius
+ const fieldRange3 = (0.7 + 0.35 * Math.sin(m.cycle / 47)) * m.fieldRange * m.harmonicRadius
+ const netFieldRange = Math.max(fieldRange1, fieldRange2, fieldRange3)
+ ctx.fillStyle = "rgba(110,170,200," + Math.min(0.6, (0.04 + 0.7 * m.energy * (0.1 + 0.11 * Math.random()))) + ")";
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, fieldRange1, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, fieldRange2, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, fieldRange3, 0, 2 * Math.PI);
+ ctx.fill();
+ //360 block
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (Vector.magnitude(Vector.sub(mob[i].position, m.pos)) - mob[i].radius < netFieldRange && !mob[i].isUnblockable) { // && Matter.Query.ray(map, mob[i].position, m.pos).length === 0
+ mob[i].locatePlayer();
+ if (this.drainCD > m.cycle) {
+ m.pushMass(mob[i], 0);
+ } else {
+ m.pushMass(mob[i]);
+ this.drainCD = m.cycle + 15
+ }
+ }
+ }
+ }
+ m.harmonicRadius = 1 //for smoothing function when player holds mouse (for harmonicAtomic)
+ m.harmonicAtomic = () => { //several ellipses spinning about different axises
+ const rotation = simulation.cycle * 0.0031
+ const phase = simulation.cycle * 0.023
+ const radius = m.fieldRange * m.harmonicRadius
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = "rgba(110,170,200,0.8)"
+ ctx.fillStyle = "rgba(110,170,200," + Math.min(0.6, 0.7 * m.energy * (0.11 + 0.1 * Math.random()) * (3 / tech.harmonics)) + ")";
+ // ctx.fillStyle = "rgba(110,170,200," + Math.min(0.7, m.energy * (0.22 - 0.01 * tech.harmonics) * (0.5 + 0.5 * Math.random())) + ")";
+ for (let i = 0; i < tech.harmonics; i++) {
+ ctx.beginPath();
+ ctx.ellipse(m.pos.x, m.pos.y, radius * Math.abs(Math.sin(phase + i / tech.harmonics * Math.PI)), radius, rotation + i / tech.harmonics * Math.PI, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.stroke();
+ }
+ //360 block
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (Vector.magnitude(Vector.sub(mob[i].position, m.pos)) - mob[i].radius < radius && !mob[i].isUnblockable) { // && Matter.Query.ray(map, mob[i].position, m.pos).length === 0
+ mob[i].locatePlayer();
+ if (this.drainCD > m.cycle) {
+ m.pushMass(mob[i], 0);
+ } else {
+ m.pushMass(mob[i]);
+ this.drainCD = m.cycle + 15
+ }
+ }
+ }
+ }
+ if (tech.harmonics === 2) {
+ m.harmonicShield = m.harmonic3Phase
+ } else {
+ m.harmonicShield = m.harmonicAtomic
+ }
+ m.hold = function () {
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ m.throwBlock();
+ } else if ((input.field) && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
+ if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
+ m.grabPowerUp();
+ m.lookForPickUp();
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ m.pickUp();
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ }
+ if (m.energy > m.minEnergyToDeflect && m.fieldCDcycle < m.cycle) {
+ if (tech.isStandingWaveExpand) {
+ if (input.field) {
+ // const oldHarmonicRadius = m.harmonicRadius
+ m.harmonicRadius = 0.99 * m.harmonicRadius + 0.01 * 4
+ // m.energy -= 0.1 * (m.harmonicRadius - oldHarmonicRadius)
+ } else {
+ m.harmonicRadius = 0.994 * m.harmonicRadius + 0.006
+ }
+ }
+ if (!simulation.isTimeSkipping) m.harmonicShield()
+ }
+ m.drawRegenEnergy()
+ }
+ }
+ },
+ {
+ name: "perfect diamagnetism",
+ description: "
deflecting does not drain
energy maintains
functionality while
inactive generate
5 energy per second",
+ //
attract power ups from
far away
+ // description: "
attract power ups from
far away deflecting doesn't drain
energy thrown
blocks have",
+ // description: "gain
energy when
blocking no
recoil when
blocking ",
+ effect: () => {
+ m.fieldMeterColor = "#48f" //"#0c5"
+ m.eyeFillColor = m.fieldMeterColor
+
+ m.fieldShieldingScale = 0;
+ m.fieldBlockCD = 3;
+ m.grabPowerUpRange2 = 10000000
+ m.fieldPosition = {
+ x: m.pos.x,
+ y: m.pos.y
+ }
+ m.fieldAngle = m.angle
+ m.perfectPush = (isFree = false) => {
+ if (m.fieldCDcycle < m.cycle) {
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (
+ Vector.magnitude(Vector.sub(mob[i].position, m.fieldPosition)) - mob[i].radius < m.fieldRange &&
+ !mob[i].isUnblockable &&
+ Vector.dot({
+ x: Math.cos(m.fieldAngle),
+ y: Math.sin(m.fieldAngle)
+ }, Vector.normalise(Vector.sub(mob[i].position, m.fieldPosition))) > m.fieldThreshold &&
+ Matter.Query.ray(map, mob[i].position, m.fieldPosition).length === 0
+ ) {
+ mob[i].locatePlayer();
+ const unit = Vector.normalise(Vector.sub(m.fieldPosition, mob[i].position))
+ m.fieldCDcycle = m.cycle + m.fieldBlockCD + (mob[i].isShielded ? 10 : 0);
+ if (!mob[i].isInvulnerable && bullet.length < 250) {
+ for (let i = 0; i < m.coupling; i++) {
+ if (0.1 * m.coupling - i > Math.random()) {
+ const angle = m.fieldAngle + 4 * m.fieldArc * (Math.random() - 0.5)
+ const radius = m.fieldRange * (0.6 + 0.3 * Math.random())
+ b.iceIX(6 + 6 * Math.random(), angle, Vector.add(m.fieldPosition, {
+ x: radius * Math.cos(angle),
+ y: radius * Math.sin(angle)
+ }))
+ }
+ }
+ }
+ if (tech.blockDmg) { //electricity
+ Matter.Body.setVelocity(mob[i], {
+ x: 0.5 * mob[i].velocity.x,
+ y: 0.5 * mob[i].velocity.y
+ });
+
+ if (mob[i].isShielded) {
+ for (let j = 0, len = mob.length; j < len; j++) {
+ if (mob[j].id === mob[i].shieldID) mob[j].damage(tech.blockDmg * m.dmgScale * (tech.isBlockRadiation ? 6 : 2), true)
+ }
+ } else if (tech.isBlockRadiation) {
+ if (mob[i].isMobBullet) {
+ mob[i].damage(tech.blockDmg * m.dmgScale * 3, true)
+ } else {
+ mobs.statusDoT(mob[i], tech.blockDmg * m.dmgScale * 0.42, 180) //200% increase -> x (1+2) //over 7s -> 360/30 = 12 half seconds -> 3/12
+ }
+ } else {
+ mob[i].damage(tech.blockDmg * m.dmgScale, true)
+ }
+ // if (mob[i].isShielded) {
+ // for (let j = 0, len = mob.length; j < len; j++) {
+ // if (mob[j].id === mob[i].shieldID) mob[j].damage(tech.blockDmg * m.dmgScale * (tech.isBlockRadiation ? 3 : 1), true)
+ // }
+ // } else {
+ // if (tech.isBlockRadiation && !mob[i].isMobBullet) {
+ // mobs.statusDoT(mob[i], tech.blockDmg * m.dmgScale * 4 / 12, 360) //200% increase -> x (1+2) //over 7s -> 360/30 = 12 half seconds -> 3/12
+ // } else {
+ // mob[i].damage(tech.blockDmg * m.dmgScale)
+ // }
+ // }
+ const step = 40
+ ctx.beginPath();
+ for (let i = 0, len = 0.5 * tech.blockDmg; i < len; i++) {
+ let x = m.fieldPosition.x - 20 * unit.x;
+ let y = m.fieldPosition.y - 20 * unit.y;
+ ctx.moveTo(x, y);
+ for (let i = 0; i < 8; i++) {
+ x += step * (-unit.x + 1.5 * (Math.random() - 0.5))
+ y += step * (-unit.y + 1.5 * (Math.random() - 0.5))
+ ctx.lineTo(x, y);
+ }
+ }
+ ctx.lineWidth = 3;
+ ctx.strokeStyle = "#f0f";
+ ctx.stroke();
+ } else if (isFree) {
+ ctx.lineWidth = 2; //when blocking draw this graphic
+ ctx.fillStyle = `rgba(110,150,220, ${0.2 + 0.4 * Math.random()})`
+ ctx.strokeStyle = "#000";
+ const len = mob[i].vertices.length - 1;
+ const mag = mob[i].radius
+ ctx.beginPath();
+ ctx.moveTo(mob[i].vertices[len].x + mag * (Math.random() - 0.5), mob[i].vertices[len].y + mag * (Math.random() - 0.5))
+ for (let j = 0; j < len; j++) {
+ ctx.lineTo(mob[i].vertices[j].x + mag * (Math.random() - 0.5), mob[i].vertices[j].y + mag * (Math.random() - 0.5));
+ }
+ ctx.lineTo(mob[i].vertices[len].x + mag * (Math.random() - 0.5), mob[i].vertices[len].y + mag * (Math.random() - 0.5))
+ ctx.fill();
+ ctx.stroke();
+ } else {
+
+ const eye = 15; //when blocking draw this graphic
+ const len = mob[i].vertices.length - 1;
+ ctx.lineWidth = 1;
+ ctx.fillStyle = `rgba(110,150,220, ${0.2 + 0.4 * Math.random()})`
+ ctx.strokeStyle = "#000";
+ ctx.beginPath();
+ ctx.moveTo(m.fieldPosition.x + eye * Math.cos(m.fieldAngle), m.fieldPosition.y + eye * Math.sin(m.fieldAngle));
+ ctx.lineTo(mob[i].vertices[len].x, mob[i].vertices[len].y);
+ ctx.lineTo(mob[i].vertices[0].x, mob[i].vertices[0].y);
+ ctx.fill();
+ ctx.stroke();
+ for (let j = 0; j < len; j++) {
+ ctx.beginPath();
+ ctx.moveTo(m.fieldPosition.x + eye * Math.cos(m.fieldAngle), m.fieldPosition.y + eye * Math.sin(m.fieldAngle));
+ ctx.lineTo(mob[i].vertices[j].x, mob[i].vertices[j].y);
+ ctx.lineTo(mob[i].vertices[j + 1].x, mob[i].vertices[j + 1].y);
+ ctx.fill();
+ ctx.stroke();
+ }
+ }
+ if (tech.isStunField) mobs.statusStun(mob[i], tech.isStunField)
+ //mob knock backs
+ const massRoot = Math.sqrt(Math.max(1, mob[i].mass));
+ Matter.Body.setVelocity(mob[i], {
+ x: player.velocity.x - (30 * unit.x) / massRoot,
+ y: player.velocity.y - (30 * unit.y) / massRoot
+ });
+ if (mob[i].isUnstable) {
+ if (m.fieldCDcycle < m.cycle + 10) m.fieldCDcycle = m.cycle + 6
+ mob[i].death();
+ }
+ if (!isFree) { //player knock backs
+ if (mob[i].isDropPowerUp && player.speed < 12) {
+ const massRootCap = Math.sqrt(Math.min(10, Math.max(0.2, mob[i].mass)));
+ Matter.Body.setVelocity(player, {
+ x: 0.9 * player.velocity.x + 0.6 * unit.x * massRootCap,
+ y: 0.9 * player.velocity.y + 0.6 * unit.y * massRootCap
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+ m.hold = function () {
+ const wave = Math.sin(m.cycle * 0.022);
+ m.fieldRange = 180 + 12 * wave + 100 * tech.isBigField
+ m.fieldArc = 0.35 + 0.045 * wave + 0.065 * tech.isBigField //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob)
+ m.calculateFieldThreshold();
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ m.throwBlock();
+ } else if (input.field) { //not hold but field button is pressed
+ //float while field is on
+ const angleReduction = 0.5 + 0.7 * (Math.PI / 2 - Math.min(Math.PI / 2, Math.abs(m.angle + Math.PI / 2)))
+ // console.log(angleReduction)
+ if (player.velocity.y > 1) {
+ player.force.y -= angleReduction * (tech.isBigField ? 0.95 : 0.5) * player.mass * simulation.g;
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: 0.98 * player.velocity.y
+ }); //set velocity to cap, but keep the direction
+ }
+
+ // go invulnerable while field is active, but also drain energy
+ // if (true && m.energy > 2 * m.fieldRegen && m.immuneCycle < m.cycle + tech.cyclicImmunity) {
+ // m.immuneCycle = m.cycle + 1; //player is immune to damage for 60 cycles
+ // m.energy -= 2 * m.fieldRegen
+ // if (m.energy < m.fieldRegen) m.fieldCDcycle = m.cycle + 90;
+ // }
+
+
+ if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
+ m.grabPowerUp();
+ m.lookForPickUp();
+ m.fieldPosition = { x: m.pos.x, y: m.pos.y }
+ m.fieldAngle = m.angle
+ //draw field attached to player
+ if (m.holdingTarget) {
+ ctx.fillStyle = `rgba(110,150,220, ${0.06 + 0.03 * Math.random()})`
+ ctx.strokeStyle = `rgba(110,150,220, ${0.35 + 0.05 * Math.random()})`
+ } else {
+ ctx.fillStyle = `rgba(110,150,220, ${0.27 + 0.2 * Math.random() - 0.1 * wave})`
+ ctx.strokeStyle = `rgba(110,150,220, ${0.4 + 0.5 * Math.random()})`
+ }
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, m.fieldRange, m.angle - Math.PI * m.fieldArc, m.angle + Math.PI * m.fieldArc, false);
+ ctx.lineWidth = 2.5 - 1.5 * wave;
+ ctx.stroke();
+ const curve = 0.57 + 0.04 * wave
+ const aMag = (1 - curve * 1.2) * Math.PI * m.fieldArc
+ let a = m.angle + aMag
+ let cp1x = m.pos.x + curve * m.fieldRange * Math.cos(a)
+ let cp1y = m.pos.y + curve * m.fieldRange * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, m.pos.x + 30 * Math.cos(m.angle), m.pos.y + 30 * Math.sin(m.angle))
+ a = m.angle - aMag
+ cp1x = m.pos.x + curve * m.fieldRange * Math.cos(a)
+ cp1y = m.pos.y + curve * m.fieldRange * Math.sin(a)
+ ctx.quadraticCurveTo(cp1x, cp1y, m.pos.x + 1 * m.fieldRange * Math.cos(m.angle - Math.PI * m.fieldArc), m.pos.y + 1 * m.fieldRange * Math.sin(m.angle - Math.PI * m.fieldArc))
+ ctx.fill();
+ m.perfectPush();
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ m.pickUp();
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ if (!input.field) { //&& tech.isFieldFree
+ //draw field free of player
+ ctx.fillStyle = `rgba(110,150,220, ${0.27 + 0.2 * Math.random() - 0.1 * wave})`
+ ctx.strokeStyle = `rgba(110,180,255, ${0.4 + 0.5 * Math.random()})`
+ ctx.beginPath();
+ ctx.arc(m.fieldPosition.x, m.fieldPosition.y, m.fieldRange, m.fieldAngle - Math.PI * m.fieldArc, m.fieldAngle + Math.PI * m.fieldArc, false);
+ ctx.lineWidth = 2.5 - 1.5 * wave;
+ ctx.stroke();
+ const curve = 0.8 + 0.06 * wave
+ const aMag = (1 - curve * 1.2) * Math.PI * m.fieldArc
+ let a = m.fieldAngle + aMag
+ ctx.quadraticCurveTo(m.fieldPosition.x + curve * m.fieldRange * Math.cos(a), m.fieldPosition.y + curve * m.fieldRange * Math.sin(a), m.fieldPosition.x + 1 * m.fieldRange * Math.cos(m.fieldAngle - Math.PI * m.fieldArc), m.fieldPosition.y + 1 * m.fieldRange * Math.sin(m.fieldAngle - Math.PI * m.fieldArc))
+ ctx.fill();
+ m.perfectPush(true);
+ }
+ }
+ // m.drawRegenEnergy()
+ m.drawRegenEnergy("rgba(0,0,0,0.2)")
+ if (tech.isPerfectBrake) { //cap mob speed around player
+ const range = 200 + 140 * wave + 150 * m.energy
+ for (let i = 0; i < mob.length; i++) {
+ const distance = Vector.magnitude(Vector.sub(m.pos, mob[i].position))
+ if (distance < range) {
+ const cap = mob[i].isShielded ? 8 : 4
+ if (mob[i].speed > cap && Vector.dot(mob[i].velocity, Vector.sub(m.pos, mob[i].position)) > 0) { // if velocity is directed towards player
+ Matter.Body.setVelocity(mob[i], Vector.mult(Vector.normalise(mob[i].velocity), cap)); //set velocity to cap, but keep the direction
+ }
+ }
+ }
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, range, 0, 2 * Math.PI);
+ ctx.fillStyle = "hsla(200,50%,61%,0.08)";
+ ctx.fill();
+ }
+ }
+ }
+ },
+ {
+ name: "negative mass",
+ //
hold
blocks as if they have a lower
mass
+ description: "use
energy to nullify
gravity +55% defense generate
6 energy per second",
+ fieldDrawRadius: 0,
+ effect: () => {
+ m.fieldFire = true;
+ m.holdingMassScale = 0.01; //can hold heavier blocks with lower cost to jumping
+ m.fieldMeterColor = "#333"
+ m.eyeFillColor = m.fieldMeterColor
+ m.fieldHarmReduction = 0.45; //55% reduction
+ m.fieldDrawRadius = 0;
+
+ m.hold = function () {
+ m.airSpeedLimit = 125 //5 * player.mass * player.mass
+ m.FxAir = 0.016
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ m.throwBlock();
+ } else if (input.field && m.fieldCDcycle < m.cycle) { //push away
+ if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
+ m.grabPowerUp();
+ m.lookForPickUp();
+ const DRAIN = 0.00035
+ if (m.energy > DRAIN) {
+ if (tech.isFlyFaster) {
+ //look for nearby objects to make zero-g
+ function moveThis(who, range, mag = 1.06) {
+ for (let i = 0, len = who.length; i < len; ++i) {
+ sub = Vector.sub(who[i].position, m.pos);
+ dist = Vector.magnitude(sub);
+ if (dist < range) {
+ who[i].force.y -= who[i].mass * (simulation.g * mag); //add a bit more then standard gravity
+ if (input.left) { //blocks move horizontally with the same force as the player
+ who[i].force.x -= m.FxAir * who[i].mass / 10; // move player left / a
+ } else if (input.right) {
+ who[i].force.x += m.FxAir * who[i].mass / 10; //move player right / d
+ }
+ //loose attraction to player
+ // const sub = Vector.sub(m.pos, body[i].position)
+ // const unit = Vector.mult(Vector.normalise(sub), who[i].mass * 0.0000002 * Vector.magnitude(sub))
+ // body[i].force.x += unit.x
+ // body[i].force.y += unit.y
+ }
+ }
+ }
+ //control horizontal acceleration
+ m.airSpeedLimit = 1000 // 7* player.mass * player.mass
+ m.FxAir = 0.01
+ //control vertical acceleration
+ if (input.down) { //down
+ player.force.y += 0.5 * player.mass * simulation.g;
+ this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 500 * 0.03;
+ moveThis(powerUp, this.fieldDrawRadius, 0);
+ moveThis(body, this.fieldDrawRadius, 0);
+ } else if (input.up) { //up
+ m.energy -= 5 * DRAIN;
+ this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 1100 * 0.03;
+ player.force.y -= 2.25 * player.mass * simulation.g;
+ moveThis(powerUp, this.fieldDrawRadius, 1.8);
+ moveThis(body, this.fieldDrawRadius, 1.8);
+ } else {
+ m.energy -= DRAIN;
+ this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 800 * 0.03;
+ player.force.y -= 1.07 * player.mass * simulation.g; // slow upward drift
+ moveThis(powerUp, this.fieldDrawRadius);
+ moveThis(body, this.fieldDrawRadius);
+ }
+ } else {
+ //look for nearby objects to make zero-g
+ function verticalForce(who, range, mag = 1.06) {
+ for (let i = 0, len = who.length; i < len; ++i) {
+ sub = Vector.sub(who[i].position, m.pos);
+ dist = Vector.magnitude(sub);
+ if (dist < range) who[i].force.y -= who[i].mass * (simulation.g * mag);
+ }
+ }
+ //control horizontal acceleration
+ m.airSpeedLimit = 400 // 7* player.mass * player.mass
+ m.FxAir = 0.005
+ //control vertical acceleration
+ if (input.down) { //down
+ player.force.y -= 0.5 * player.mass * simulation.g;
+ this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 400 * 0.03;
+ verticalForce(powerUp, this.fieldDrawRadius, 0.7);
+ verticalForce(body, this.fieldDrawRadius, 0.7);
+ } else if (input.up) { //up
+ m.energy -= 5 * DRAIN;
+ this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 850 * 0.03;
+ player.force.y -= 1.45 * player.mass * simulation.g;
+ verticalForce(powerUp, this.fieldDrawRadius, 1.38);
+ verticalForce(body, this.fieldDrawRadius, 1.38);
+ } else {
+ m.energy -= DRAIN;
+ this.fieldDrawRadius = this.fieldDrawRadius * 0.97 + 650 * 0.03;
+ player.force.y -= 1.07 * player.mass * simulation.g; // slow upward drift
+ verticalForce(powerUp, this.fieldDrawRadius);
+ verticalForce(body, this.fieldDrawRadius);
+ }
+ }
+
+ if (m.energy < 0.001) {
+ m.fieldCDcycle = m.cycle + 120;
+ m.energy = 0;
+ }
+ //add extra friction for horizontal motion
+ if (input.down || input.up || input.left || input.right) {
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x * 0.99,
+ y: player.velocity.y * 0.98
+ });
+ } else { //slow rise and fall
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x * 0.99,
+ y: player.velocity.y * 0.98
+ });
+ }
+ // if (tech.isFreezeMobs) {
+ // const ICE_DRAIN = 0.0005
+ // for (let i = 0, len = mob.length; i < len; i++) {
+ // if (!mob[i].isMobBullet && !mob[i].shield && !mob[i].isShielded && ((mob[i].distanceToPlayer() + mob[i].radius) < this.fieldDrawRadius)) {
+ // if (m.energy > ICE_DRAIN * 2) {
+ // m.energy -= ICE_DRAIN;
+ // this.fieldDrawRadius -= 2;
+ // mobs.statusSlow(mob[i], 60)
+ // } else {
+ // break;
+ // }
+ // }
+ // }
+ // }
+ //draw zero-G range
+ if (!simulation.isTimeSkipping) {
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, this.fieldDrawRadius, 0, 2 * Math.PI);
+ ctx.fillStyle = "#f5f5ff";
+ ctx.globalCompositeOperation = "difference";
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over";
+ }
+ }
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ m.pickUp();
+ this.fieldDrawRadius = 0
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ this.fieldDrawRadius = 0
+ }
+ m.drawRegenEnergy("rgba(0,0,0,0.2)")
+
+
+ // if (tech.isHealAttract) {
+ // for (let i = 0; i < powerUp.length; i++) {
+ // if (powerUp[i].name === "heal") {
+ // //&& Vector.magnitudeSquared(Vector.sub(powerUp[i].position, m.pos)) < 500000
+ // let attract = Vector.mult(Vector.normalise(Vector.sub(m.pos, powerUp[i].position)), 0.01 * powerUp[i].mass)
+ // powerUp[i].force.x += attract.x;
+ // powerUp[i].force.y += attract.y - powerUp[i].mass * simulation.g; //negate gravity
+ // Matter.Body.setVelocity(powerUp[i], Vector.mult(powerUp[i].velocity, 0.7));
+ // }
+ // }
+ // }
+
+
+ // powerUp[i].force.x += 0.05 * (dxP / Math.sqrt(dist2)) * powerUp[i].mass;
+ // powerUp[i].force.y += 0.05 * (dyP / Math.sqrt(dist2)) * powerUp[i].mass - powerUp[i].mass * simulation.g; //negate gravity
+ // //extra friction
+ // Matter.Body.setVelocity(powerUp[i], {
+ // x: powerUp[i].velocity.x * 0.11,
+ // y: powerUp[i].velocity.y * 0.11
+ // });
+
+ }
+ }
+ },
+ {
+ name: "molecular assembler",
+ description: `excess
energy used to print ${simulation.molecularMode === 0 ? "
spores" : simulation.molecularMode === 1 ? "missiles" : simulation.molecularMode === 2 ? "ice IX" : "drones"} use energy to deflect mobs generate 12 energy per second`,
+ // simulation.molecularMode: Math.floor(4 * Math.random()), //0 spores, 1 missile, 2 ice IX, 3 drones
+ setDescription() {
+ return `excess energy used to print ${simulation.molecularMode === 0 ? "spores" : simulation.molecularMode === 1 ? "missiles" : simulation.molecularMode === 2 ? "ice IX" : "drones"} use energy to deflect mobs generate 12 energy per second`
+ },
+ effect: () => {
+ m.fieldMeterColor = "#ff0"
+ m.eyeFillColor = m.fieldMeterColor
+ m.hold = function () {
+ if (m.energy > m.maxEnergy - 0.02 && m.fieldCDcycle < m.cycle && !input.field && bullet.length < 300 && (m.cycle % 2)) {
+ if (simulation.molecularMode === 0) {
+ if (tech.isSporeFlea) {
+ const drain = 0.18 + (Math.max(bullet.length, 130) - 130) * 0.02
+ if (m.energy > drain) {
+ m.energy -= drain
+ const speed = m.crouch ? 20 + 8 * Math.random() : 10 + 3 * Math.random()
+ b.flea({
+ x: m.pos.x + 35 * Math.cos(m.angle),
+ y: m.pos.y + 35 * Math.sin(m.angle)
+ }, {
+ x: speed * Math.cos(m.angle),
+ y: speed * Math.sin(m.angle)
+ })
+ }
+ } else if (tech.isSporeWorm) {
+ const drain = 0.18 + (Math.max(bullet.length, 130) - 130) * 0.02
+ if (m.energy > drain) {
+ m.energy -= drain
+ b.worm({
+ x: m.pos.x + 35 * Math.cos(m.angle),
+ y: m.pos.y + 35 * Math.sin(m.angle)
+ })
+ const SPEED = 2 + 1 * Math.random();
+ Matter.Body.setVelocity(bullet[bullet.length - 1], {
+ x: SPEED * Math.cos(m.angle),
+ y: SPEED * Math.sin(m.angle)
+ });
+ }
+ } else {
+ const drain = 0.095 + (Math.max(bullet.length, 130) - 130) * 0.01
+ for (let i = 0, len = Math.random() * 20; i < len; i++) {
+ if (m.energy > 3 * drain) {
+ m.energy -= drain
+ b.spore(m.pos)
+ } else {
+ break
+ }
+ }
+ }
+ } else if (simulation.molecularMode === 1) {
+ m.energy -= 0.33;
+ const direction = {
+ x: Math.cos(m.angle),
+ y: Math.sin(m.angle)
+ }
+ const push = Vector.mult(Vector.perp(direction), 0.08)
+ b.missile({
+ x: m.pos.x + 30 * direction.x,
+ y: m.pos.y + 30 * direction.y
+ }, m.angle, -15)
+ bullet[bullet.length - 1].force.x += push.x * (Math.random() - 0.5)
+ bullet[bullet.length - 1].force.y += 0.005 + push.y * (Math.random() - 0.5)
+ // b.missile({ x: m.pos.x, y: m.pos.y - 40 }, -Math.PI / 2 + 0.5 * (Math.random() - 0.5), 0, 1)
+ } else if (simulation.molecularMode === 2) {
+ m.energy -= 0.045;
+ b.iceIX(1)
+ } else if (simulation.molecularMode === 3) {
+ if (tech.isDroneRadioactive) {
+ const drain = 0.8 + (Math.max(bullet.length, 50) - 50) * 0.01
+ if (m.energy > drain) {
+ m.energy -= drain
+ b.droneRadioactive({
+ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5),
+ y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5)
+ }, 25)
+ }
+ } else {
+ //every bullet above 100 adds 0.005 to the energy cost per drone
+ //at 200 bullets the energy cost is 0.45 + 100*0.006 = 1.05
+ const drain = (0.45 + (Math.max(bullet.length, 100) - 100) * 0.006) * tech.droneEnergyReduction
+ if (m.energy > drain) {
+ m.energy -= drain
+ b.drone()
+ }
+ }
+ }
+ }
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ if (tech.isPrinter && m.holdingTarget.isPrinted && input.field) {
+ // if (Math.random() < 0.004 && m.holdingTarget.vertices.length < 12) m.holdingTarget.vertices.push({ x: 0, y: 0 }) //small chance to increase the number of vertices
+ m.holdingTarget.radius += Math.min(1.1, 1.3 / m.holdingTarget.mass) //grow up to a limit
+ const r1 = m.holdingTarget.radius * (1 + 0.12 * Math.sin(m.cycle * 0.11))
+ const r2 = m.holdingTarget.radius * (1 + 0.12 * Math.cos(m.cycle * 0.11))
+ let angle = (m.cycle * 0.01) % (2 * Math.PI) //rotate the object
+ let vertices = []
+ for (let i = 0, len = m.holdingTarget.vertices.length; i < len; i++) {
+ angle += 2 * Math.PI / len
+ vertices.push({ x: m.holdingTarget.position.x + r1 * Math.cos(angle), y: m.holdingTarget.position.y + r2 * Math.sin(angle) })
+ }
+ Matter.Body.setVertices(m.holdingTarget, vertices)
+ m.definePlayerMass(m.defaultMass + m.holdingTarget.mass * m.holdingMassScale)
+ }
+ m.throwBlock();
+ } else if ((input.field && m.fieldCDcycle < m.cycle)) { //not hold but field button is pressed
+ if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
+ m.grabPowerUp();
+ m.lookForPickUp();
+ if (tech.isPrinter && input.down) {
+ m.printBlock();
+ } else if (m.energy > m.minEnergyToDeflect) {
+ m.drawField();
+ m.pushMobsFacing();
+ }
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ m.pickUp();
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ }
+ m.drawRegenEnergy()
+ }
+ }
+ },
+ {
+ name: "plasma torch",
+ description: "use energy to emit short range plasma damages and pushes mobs away generate 10 energy per second",
+ set() {
+ b.isExtruderOn = false
+ // m.fieldCDcycleAlternate = 0
+
+ if (m.plasmaBall) {
+ m.plasmaBall.reset()
+ Matter.Composite.remove(engine.world, m.plasmaBall);
+ }
+ if (tech.isPlasmaBall) {
+ const circleRadiusScale = 2
+ m.plasmaBall = Bodies.circle(m.pos.x + 10 * Math.cos(m.angle), m.pos.y + 10 * Math.sin(m.angle), 1, {
+ // collisionFilter: {
+ // group: 0,
+ // category: 0,
+ // mask: 0 //cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield
+ // },
+ isSensor: true,
+ frictionAir: 0,
+ alpha: 0.7,
+ isPopping: false,
+ isAttached: false,
+ isOn: false,
+ drain: 0.0017,
+ radiusLimit: 10,
+ damage: 0.8,
+ setPositionToNose() {
+ const nose = {
+ x: m.pos.x + 10 * Math.cos(m.angle),
+ y: m.pos.y + 10 * Math.sin(m.angle)
+ }
+ Matter.Body.setPosition(this, Vector.add(nose, Vector.mult(Vector.normalise(Vector.sub(nose, m.pos)), circleRadiusScale * this.circleRadius)));
+ },
+ fire() {
+ this.isAttached = false;
+ const speed = 10 //scale with mass?
+ Matter.Body.setVelocity(this, {
+ x: player.velocity.x * 0.4 + speed * Math.cos(m.angle),
+ y: speed * Math.sin(m.angle)
+ });
+ m.plasmaBall.setPositionToNose()
+ if (this.circleRadius < 10) this.isPopping = true
+ },
+ scale(scale) {
+ Matter.Body.scale(m.plasmaBall, scale, scale); //shrink fast
+ if (this.circleRadius < this.radiusLimit) this.reset()
+ },
+ reset() {
+ // console.log(this.circleRadius)
+ const scale = 1 / m.plasmaBall.circleRadius
+ Matter.Body.scale(m.plasmaBall, scale, scale); //grow
+ // console.log(this.circleRadius)
+ // this.circleRadius = 0
+ this.alpha = 0.7
+ this.isOn = false
+ this.isPopping = false
+ // this.isAttached = true;
+ },
+ do() {
+ if (this.isOn) {
+ //collisions with map
+ if (Matter.Query.collides(this, map).length > 0) {
+ if (this.isAttached) {
+ this.scale(Math.max(0.9, 0.998 - 0.1 / m.plasmaBall.circleRadius))
+ } else {
+ this.isPopping = true
+ }
+ }
+ if (this.isPopping) {
+ this.alpha -= 0.03
+ if (this.alpha < 0.1) {
+ this.reset()
+ } else {
+ const scale = 1.04 + 4 / Math.max(1, m.plasmaBall.circleRadius)
+ Matter.Body.scale(m.plasmaBall, scale, scale); //grow
+ }
+ // if (this.speed > 2.5) {
+ // const slow = 0.9
+ // Matter.Body.setVelocity(this, {
+ // x: slow * this.velocity.x,
+ // y: slow * this.velocity.y
+ // });
+ // }
+ }
+ //collisions with mobs
+ // const whom = Matter.Query.collides(this, mob)
+ // const dmg = this.damage * m.dmgScale
+ // for (let i = 0, len = whom.length; i < len; i++) {
+ // const mobHit = (who) => {
+ // if (who.alive) {
+ // if (!this.isAttached && !who.isMobBullet) this.isPopping = true
+ // who.damage(dmg);
+ // // if (who.shield) this.scale(Math.max(0.9, 0.99 - 0.5 / m.plasmaBall.circleRadius))
+ // if (who.speed > 5) {
+ // Matter.Body.setVelocity(who, { //friction
+ // x: who.velocity.x * 0.6,
+ // y: who.velocity.y * 0.6
+ // });
+ // } else {
+ // Matter.Body.setVelocity(who, { //friction
+ // x: who.velocity.x * 0.93,
+ // y: who.velocity.y * 0.93
+ // });
+ // }
+ // }
+ // }
+ // mobHit(whom[i].bodyA)
+ // mobHit(whom[i].bodyB)
+ // }
+
+ //damage nearby mobs
+ const dmg = this.damage * m.dmgScale
+ const arcList = []
+ const damageRadius = circleRadiusScale * this.circleRadius
+ const dischargeRange = 150 + 1600 * tech.plasmaDischarge + 1.3 * damageRadius
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].alive && (!mob[i].isBadTarget || mob[i].isMobBullet) && !mob[i].isInvulnerable) {
+ const sub = Vector.magnitude(Vector.sub(this.position, mob[i].position))
+ if (sub < damageRadius + mob[i].radius) {
+ // if (!this.isAttached && !mob[i].isMobBullet) this.isPopping = true
+ mob[i].damage(dmg);
+ if (mob[i].speed > 5) {
+ Matter.Body.setVelocity(mob[i], { //friction
+ x: mob[i].velocity.x * 0.6,
+ y: mob[i].velocity.y * 0.6
+ });
+ } else {
+ Matter.Body.setVelocity(mob[i], { //friction
+ x: mob[i].velocity.x * 0.93,
+ y: mob[i].velocity.y * 0.93
+ });
+ }
+ } else if (sub < dischargeRange + mob[i].radius && Matter.Query.ray(map, mob[i].position, this.position).length === 0) {
+ arcList.push(mob[i]) //populate electrical arc list
+ }
+ }
+ }
+ for (let i = 0; i < arcList.length; i++) {
+ if (tech.plasmaDischarge > Math.random()) {
+ const who = arcList[Math.floor(Math.random() * arcList.length)]
+ who.damage(dmg * 4);
+ //draw arcs
+ const sub = Vector.sub(who.position, this.position)
+ const unit = Vector.normalise(sub)
+ let len = 12
+ const step = Vector.magnitude(sub) / (len + 2)
+ let x = this.position.x
+ let y = this.position.y
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ for (let i = 0; i < len; i++) {
+ x += step * (unit.x + (Math.random() - 0.5))
+ y += step * (unit.y + (Math.random() - 0.5))
+ ctx.lineTo(x, y);
+ }
+ ctx.lineTo(who.position.x, who.position.y);
+ ctx.strokeStyle = "#88f";
+ ctx.lineWidth = 4 + 3 * Math.random();
+ ctx.stroke();
+ if (who.damageReduction) {
+ simulation.drawList.push({
+ x: who.position.x,
+ y: who.position.y,
+ radius: 15,
+ color: "rgba(150,150,255,0.4)",
+ time: 15
+ });
+ }
+ }
+ }
+
+
+ //slowly slow down if too fast
+ if (this.speed > 10) {
+ const scale = 0.998
+ Matter.Body.setVelocity(this, {
+ x: scale * this.velocity.x,
+ y: scale * this.velocity.y
+ });
+ }
+
+ //graphics
+ const radius = circleRadiusScale * this.circleRadius * (0.99 + 0.02 * Math.random()) + 3 * Math.random()
+ const gradient = ctx.createRadialGradient(this.position.x, this.position.y, 0, this.position.x, this.position.y, radius);
+ const alpha = this.alpha + 0.1 * Math.random()
+ gradient.addColorStop(0, `rgba(255,255,255,${alpha})`);
+ gradient.addColorStop(0.35 + 0.1 * Math.random(), `rgba(255,150,255,${alpha})`);
+ gradient.addColorStop(1, `rgba(255,0,255,${alpha})`);
+ // gradient.addColorStop(1, `rgba(255,150,255,${alpha})`);
+ ctx.fillStyle = gradient
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, radius, 0, 2 * Math.PI);
+ ctx.fill();
+ //draw arcs
+ const unit = Vector.rotate({
+ x: 1,
+ y: 0
+ }, Math.random() * 6.28)
+ let len = 8
+ const step = this.circleRadius / len
+ let x = this.position.x
+ let y = this.position.y
+ ctx.beginPath();
+ if (Math.random() < 0.5) {
+ x += step * (unit.x + 6 * (Math.random() - 0.5))
+ y += step * (unit.y + 6 * (Math.random() - 0.5))
+ len -= 2
+ }
+ if (Math.random() < 0.5) {
+ x += step * (unit.x + 6 * (Math.random() - 0.5))
+ y += step * (unit.y + 6 * (Math.random() - 0.5))
+ len -= 2
+ }
+ ctx.moveTo(x, y);
+
+ for (let i = 0; i < len; i++) {
+ x += step * (unit.x + 1.9 * (Math.random() - 0.5))
+ y += step * (unit.y + 1.9 * (Math.random() - 0.5))
+ ctx.lineTo(x, y);
+ }
+ ctx.strokeStyle = "#88f";
+ ctx.lineWidth = 2 * Math.random();
+ ctx.stroke();
+ }
+ },
+ });
+
+ Composite.add(engine.world, m.plasmaBall);
+ // m.plasmaBall.startingVertices = m.plasmaBall.vertices.slice();
+ m.hold = function () {
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ m.throwBlock();
+ } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
+ if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
+ m.grabPowerUp();
+ m.lookForPickUp();
+
+ //field is active
+ if (!m.plasmaBall.isAttached) { //return ball to player
+ if (m.plasmaBall.isOn) {
+ m.plasmaBall.isPopping = true
+ } else {
+ m.plasmaBall.isAttached = true
+ m.plasmaBall.isOn = true
+ m.plasmaBall.isPopping = false
+ m.plasmaBall.alpha = 0.7
+ m.plasmaBall.setPositionToNose()
+ // m.plasmaBall.reset()
+
+ }
+ // const scale = 0.7
+ // Matter.Body.scale(m.plasmaBall, scale, scale); //shrink fast
+ // if (m.plasmaBall.circleRadius < m.plasmaBall.radiusLimit) {
+ // m.plasmaBall.isAttached = true
+ // m.plasmaBall.isOn = true
+ // m.plasmaBall.setPositionToNose()
+ // }
+ } else if (m.energy > m.plasmaBall.drain) { //charge up when attached
+ if (tech.isCapacitor) {
+ m.energy -= m.plasmaBall.drain * 2;
+ const scale = 1 + 48 * Math.pow(Math.max(1, m.plasmaBall.circleRadius), -1.8)
+ Matter.Body.scale(m.plasmaBall, scale, scale); //grow
+ } else {
+ m.energy -= m.plasmaBall.drain;
+ const scale = 1 + 16 * Math.pow(Math.max(1, m.plasmaBall.circleRadius), -1.8)
+ Matter.Body.scale(m.plasmaBall, scale, scale); //grow
+ }
+ if (m.energy > m.maxEnergy) {
+ m.energy -= m.plasmaBall.drain * 2;
+ const scale = 1 + 16 * Math.pow(Math.max(1, m.plasmaBall.circleRadius), -1.8)
+ Matter.Body.scale(m.plasmaBall, scale, scale); //grow
+ }
+ m.plasmaBall.setPositionToNose()
+
+ //add friction for player when holding ball, more friction in vertical
+ // const floatScale = Math.sqrt(m.plasmaBall.circleRadius)
+ // const friction = 0.0002 * floatScale
+ // const slowY = (player.velocity.y > 0) ? Math.max(0.8, 1 - friction * player.velocity.y * player.velocity.y) : Math.max(0.98, 1 - friction * Math.abs(player.velocity.y)) //down : up
+ // Matter.Body.setVelocity(player, {
+ // x: Math.max(0.95, 1 - friction * Math.abs(player.velocity.x)) * player.velocity.x,
+ // y: slowY * player.velocity.y
+ // });
+
+ // if (player.velocity.y > 7) player.force.y -= 0.95 * player.mass * simulation.g //less gravity when falling fast
+ // player.force.y -= Math.min(0.95, 0.05 * floatScale) * player.mass * simulation.g; //undo some gravity on up or down
+
+ //float
+ const slowY = (player.velocity.y > 0) ? Math.max(0.8, 1 - 0.002 * player.velocity.y * player.velocity.y) : Math.max(0.98, 1 - 0.001 * Math.abs(player.velocity.y)) //down : up
+ Matter.Body.setVelocity(player, {
+ x: Math.max(0.95, 1 - 0.003 * Math.abs(player.velocity.x)) * player.velocity.x,
+ y: slowY * player.velocity.y
+ });
+ if (player.velocity.y > 5) {
+ player.force.y -= 0.9 * player.mass * simulation.g //less gravity when falling fast
+ } else {
+ player.force.y -= 0.5 * player.mass * simulation.g;
+ }
+ } else {
+ m.fieldCDcycle = m.cycle + 90;
+ m.plasmaBall.fire()
+ }
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ m.pickUp();
+ if (m.plasmaBall.isAttached) {
+ m.fieldCDcycle = m.cycle + 30;
+ m.plasmaBall.fire()
+ }
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ if (m.plasmaBall.isAttached) {
+ m.fieldCDcycle = m.cycle + 30;
+ m.plasmaBall.fire()
+ }
+ }
+ m.drawRegenEnergy("rgba(0, 0, 0, 0.2)")
+ m.plasmaBall.do()
+ }
+ } else if (tech.isExtruder) {
+ m.hold = function () {
+ b.isExtruderOn = false
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ m.throwBlock();
+ } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
+ if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
+ m.grabPowerUp();
+ m.lookForPickUp();
+ b.extruder();
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ m.pickUp();
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ }
+ m.drawRegenEnergy("rgba(0, 0, 0, 0.2)")
+ if (input.field) {
+ b.wasExtruderOn = true
+ } else {
+ b.wasExtruderOn = false
+ b.canExtruderFire = true
+ }
+ ctx.beginPath(); //draw all the wave bullets
+ for (let i = 1, len = bullet.length; i < len; i++) { //skip the first bullet (which is is oldest bullet)
+ if (bullet[i].isWave) {
+ if (bullet[i].isBranch || bullet[i - 1].isBranch) {
+ ctx.moveTo(bullet[i].position.x, bullet[i].position.y)
+ } else {
+ ctx.lineTo(bullet[i].position.x, bullet[i].position.y)
+ }
+ }
+ }
+ if (b.wasExtruderOn && b.isExtruderOn) ctx.lineTo(m.pos.x + 15 * Math.cos(m.angle), m.pos.y + 15 * Math.sin(m.angle))
+ ctx.lineWidth = 4;
+ ctx.strokeStyle = "#f07"
+ ctx.stroke();
+ ctx.lineWidth = tech.extruderRange;
+ ctx.strokeStyle = "rgba(255,0,110,0.06)"
+ ctx.stroke();
+ }
+ } else {
+ m.hold = function () {
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ m.throwBlock();
+ } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
+ if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
+ m.grabPowerUp();
+ m.lookForPickUp();
+ b.plasma();
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ m.pickUp();
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ }
+ m.drawRegenEnergy("rgba(0, 0, 0, 0.2)")
+ }
+ }
+ },
+ effect() {
+ m.fieldMeterColor = "#f0f"
+ m.eyeFillColor = m.fieldMeterColor
+ this.set();
+ }
+ },
+ {
+ name: "time dilation",
+ description: "use energy to stop time +20% movement and fire rate generate 12 energy per second",
+ set() {
+ // m.fieldMeterColor = "#0fc"
+ // m.fieldMeterColor = "#ff0"
+ m.fieldMeterColor = "#3fe"
+ m.eyeFillColor = m.fieldMeterColor
+ m.fieldFx = 1.25
+ // m.fieldJump = 1.09
+ m.setMovement();
+ b.setFireCD()
+ const timeStop = () => {
+ m.immuneCycle = m.cycle + 10; //immune to harm while time is stopped, this also disables regen
+ //draw field everywhere
+ ctx.globalCompositeOperation = "saturation"
+ ctx.fillStyle = "#ccc";
+ ctx.fillRect(-50000, -50000, 100000, 100000)
+ ctx.globalCompositeOperation = "source-over"
+ //stop time
+ m.isBodiesAsleep = true;
+
+ function sleep(who) {
+ for (let i = 0, len = who.length; i < len; ++i) {
+ if (!who[i].isSleeping) {
+ who[i].storeVelocity = who[i].velocity
+ who[i].storeAngularVelocity = who[i].angularVelocity
+ }
+ Matter.Sleeping.set(who[i], true)
+ }
+ }
+ sleep(mob);
+ sleep(body);
+ sleep(bullet);
+ simulation.cycle--; //pause all functions that depend on game cycle increasing
+ }
+ if (tech.isRewindField) {
+ this.rewindCount = 0
+ m.grabPowerUpRange2 = 300000
+ m.hold = function () {
+ // console.log(m.fieldCDcycle)
+ m.grabPowerUp();
+ // //grab power ups
+ // for (let i = 0, len = powerUp.length; i < len; ++i) {
+ // if (
+ // Vector.magnitudeSquared(Vector.sub(m.pos, powerUp[i].position)) < 100000 &&
+ // !simulation.isChoosing &&
+ // (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal)
+ // ) {
+ // powerUps.onPickUp(powerUp[i]);
+ // powerUp[i].effect();
+ // Matter.Composite.remove(engine.world, powerUp[i]);
+ // powerUp.splice(i, 1);
+ // break; //because the array order is messed up after splice
+ // }
+ // }
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ m.throwBlock();
+ m.wakeCheck();
+ } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
+ const drain = 0.0014 / (1 + 0.05 * m.coupling)
+ if (m.energy > drain) m.energy -= drain
+ m.grabPowerUp();
+ if (this.rewindCount === 0) {
+ m.lookForPickUp();
+ }
+
+ if (!m.holdingTarget) {
+ if (this.rewindCount === 0) { //large upfront energy cost to enter rewind mode
+ if (m.energy > 0.3) {
+ m.energy -= 0.3
+ } else {
+ this.rewindCount = 0;
+ m.resetHistory();
+ if (m.fireCDcycle < m.cycle + 60) m.fieldCDcycle = m.cycle + 60
+ m.immuneCycle = m.cycle //if you reach the end of the history disable harm immunity
+ }
+ }
+ this.rewindCount += 6;
+ const DRAIN = 0.003
+ let history = m.history[(m.cycle - this.rewindCount) % 600]
+ if (this.rewindCount > 599 || m.energy < DRAIN) {
+ this.rewindCount = 0;
+ m.resetHistory();
+ if (m.fireCDcycle < m.cycle + 60) m.fieldCDcycle = m.cycle + 60
+ m.immuneCycle = m.cycle //if you reach the end of the history disable harm immunity
+ } else {
+ //draw field everywhere
+ ctx.globalCompositeOperation = "saturation"
+ ctx.fillStyle = "#ccc";
+ ctx.fillRect(-100000, -100000, 200000, 200000)
+ ctx.globalCompositeOperation = "source-over"
+ // m.grabPowerUp(); //a second grab power up to make the power ups easier to grab, and they more fast which matches the time theme
+ m.energy -= DRAIN
+ if (m.immuneCycle < m.cycle + 5) m.immuneCycle = m.cycle + 5; //player is immune to damage for 5 cycles
+ Matter.Body.setPosition(player, history.position);
+ Matter.Body.setVelocity(player, {
+ x: history.velocity.x,
+ y: history.velocity.y
+ });
+ if (m.health < history.health) {
+ m.health = history.health
+ if (m.health > m.maxHealth) m.health = m.maxHealth
+ m.displayHealth();
+ }
+ m.yOff = history.yOff
+ if (m.yOff < 48) {
+ m.doCrouch()
+ } else {
+ m.undoCrouch()
+ }
+ if (tech.isRewindBot && !(this.rewindCount % 60)) {
+ for (let i = 0; i < tech.isRewindBot; i++) {
+ b.randomBot(m.pos, false, false)
+ bullet[bullet.length - 1].endCycle = simulation.cycle + 300 + Math.floor(180 * Math.random()) //8-9 seconds
+ }
+ }
+ if (tech.isRewindGrenade && !(this.rewindCount % 30)) {
+ b.grenade(m.pos, this.rewindCount) //Math.PI / 2
+ const who = bullet[bullet.length - 1]
+ who.endCycle = simulation.cycle + 120
+ }
+ }
+ }
+ m.wakeCheck();
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ m.pickUp();
+ this.rewindCount = 0;
+ m.wakeCheck();
+ } else if (tech.isTimeStop && player.speed < 1 && m.onGround && !input.fire) {
+ timeStop();
+ this.rewindCount = 0;
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ this.rewindCount = 0;
+ m.wakeCheck();
+ }
+ m.drawRegenEnergy() // this calls m.regenEnergy(); also
+ }
+ } else {
+ m.fieldFire = true;
+ m.isBodiesAsleep = false;
+ m.hold = function () {
+ if (m.isHolding) {
+ m.wakeCheck();
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ m.throwBlock();
+ } else if (input.field && m.fieldCDcycle < m.cycle) {
+ const drain = 0.0026 / (1 + 0.03 * m.coupling)
+ if (m.energy > drain) m.energy -= drain
+ m.grabPowerUp();
+ m.lookForPickUp(); //this drains energy 0.001
+ if (m.energy > drain) {
+ timeStop();
+ } else { //holding, but field button is released
+ m.fieldCDcycle = m.cycle + 120;
+ m.energy = 0;
+ m.wakeCheck();
+ m.wakeCheck();
+ }
+ } else if (tech.isTimeStop && player.speed < 1 && m.onGround && m.fireCDcycle < m.cycle && !input.fire) {
+ timeStop();
+ //makes things move at 1/5 time rate, but has an annoying flicker for mob graphics, and other minor bugs
+ // if (!(m.cycle % 4)) {
+ // // requestAnimationFrame(() => {
+ // m.wakeCheck();
+ // // simulation.timePlayerSkip(1)
+ // // }); //wrapping in animation frame prevents errors, probably
+ // ctx.globalCompositeOperation = "saturation"
+ // ctx.fillStyle = "#ccc";
+ // ctx.fillRect(-100000, -100000, 200000, 200000)
+ // ctx.globalCompositeOperation = "source-over"
+ // } else {
+ // timeStop();
+ // }
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding, but field button is released
+ m.wakeCheck();
+ m.pickUp();
+ } else {
+ m.wakeCheck();
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ }
+ m.drawRegenEnergy()
+ }
+ }
+ },
+ effect() {
+ if (tech.isTimeStop) {
+ m.fieldHarmReduction = 0.66; //33% reduction
+ } else {
+ m.fieldHarmReduction = 1;
+ }
+ this.set();
+ }
+ },
+ {
+ name: "metamaterial cloaking",
+ description: "+50% defense while cloaked after decloaking +333% damage for 2 s generate 6 energy per second",
+ effect: () => {
+ m.fieldFire = true;
+ m.fieldMeterColor = "#333";
+ m.eyeFillColor = m.fieldMeterColor
+ m.fieldPhase = 0;
+ m.isCloak = false
+ m.fieldDrawRadius = 0
+ m.isSneakAttack = true;
+ m.sneakAttackCycle = 0;
+ m.enterCloakCycle = 0;
+ m.drawCloakedM = function () {
+ m.walk_cycle -= m.flipLegs * m.Vx;
+ m.pos.x += 4
+ m.draw();
+
+ // let history = m.history[(m.cycle - 1) % 600]
+ // m.pos.x = history.position.x
+ // m.pos.y = history.position.y + m.yPosDifference - history.yOff
+
+ // m.pos.x += 4
+ // ctx.fillStyle = m.fillColor;
+ // ctx.save();
+ // ctx.translate(m.pos.x, m.pos.y);
+ // m.calcLeg(Math.PI, -3);
+ // m.drawLeg("#ccc");
+ // m.calcLeg(0, 0);
+ // m.drawLeg("#ccc");
+ // ctx.rotate(m.angle);
+ // ctx.beginPath();
+ // ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ // ctx.fillStyle = "#fff"
+ // ctx.fill();
+ // ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ // ctx.strokeStyle = "#333";
+ // ctx.lineWidth = 2;
+ // ctx.stroke();
+ // ctx.restore()
+ }
+ m.drawCloak = function () {
+ m.fieldPhase += 0.007
+ const wiggle = 0.15 * Math.sin(m.fieldPhase * 0.5)
+ ctx.beginPath();
+ ctx.ellipse(m.pos.x, m.pos.y, m.fieldDrawRadius * (1 - wiggle), m.fieldDrawRadius * (1 + wiggle), m.fieldPhase, 0, 2 * Math.PI);
+ ctx.fillStyle = "#fff"
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "#000"
+ // ctx.stroke()
+ ctx.globalCompositeOperation = "destination-in";
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over";
+ ctx.clip();
+ }
+ m.hold = function () {
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ m.throwBlock();
+ } else if (input.field && m.fieldCDcycle < m.cycle) { //not hold and field button is pressed
+ if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen
+ m.grabPowerUp();
+ m.lookForPickUp();
+ } else if (m.holdingTarget && m.fieldCDcycle < m.cycle) { //holding target exists, and field button is not pressed
+ m.pickUp();
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ }
+ //not shooting (or using field) enable cloak
+ if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle
+ if (m.fireCDcycle + 30 < m.cycle && !input.fire) { //automatically cloak if not firing
+ const drain = 0.02
+ if (!m.isCloak && m.energy > drain + 0.03) {
+ m.energy -= drain
+ m.isCloak = true //enter cloak
+ m.fieldHarmReduction = 0.5;
+ m.enterCloakCycle = m.cycle
+ if (tech.isCloakHealLastHit && m.lastHit > 0) {
+ const heal = Math.min(0.75 * m.lastHit, m.energy)
+ if (m.energy > heal) {
+ m.energy -= heal
+ m.addHealth(heal); //heal from last hit
+ m.lastHit = 0
+ simulation.drawList.push({ //add dmg to draw queue
+ x: m.pos.x,
+ y: m.pos.y,
+ radius: Math.sqrt(heal) * 200,
+ color: "rgba(0,255,200,0.6)",
+ time: 16
+ });
+ }
+ }
+ if (tech.isIntangible) {
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType && bullet[i].botType !== "orbit") bullet[i].collisionFilter.mask = cat.map | cat.bullet | cat.mobBullet | cat.mobShield
+ }
+ }
+ }
+ } else if (m.isCloak) { //exit cloak
+ m.sneakAttackCycle = m.cycle
+ m.isCloak = false
+ m.fieldHarmReduction = 1
+
+ if (tech.isIntangible) {
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType && bullet[i].botType !== "orbit") bullet[i].collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield
+ }
+ }
+ if (tech.isCloakStun) { //stun nearby mobs after exiting cloak
+ let isMobsAround = false
+ const stunRange = m.fieldDrawRadius * 1.5
+ const drain = 0.14
+ if (m.energy > drain) {
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (Vector.magnitude(Vector.sub(mob[i].position, m.pos)) < stunRange && Matter.Query.ray(map, mob[i].position, m.pos).length === 0 && !mob[i].isBadTarget) {
+ isMobsAround = true
+ mobs.statusStun(mob[i], 180)
+ }
+ }
+ if (isMobsAround) {
+ m.energy -= drain
+ simulation.drawList.push({
+ x: m.pos.x,
+ y: m.pos.y,
+ radius: stunRange,
+ color: "hsla(0,50%,100%,0.7)",
+ time: 7
+ });
+ }
+ }
+ }
+ }
+ if (m.isCloak) {
+ m.fieldRange = m.fieldRange * 0.85 + 130
+ m.fieldDrawRadius = m.fieldRange * 1.1 //* 0.88 //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
+ m.drawCloak()
+ ctx.globalCompositeOperation = "lighter";
+ m.drawCloakedM()
+ ctx.globalCompositeOperation = "source-over";
+ } else if (m.fieldRange < 4000) {
+ m.fieldRange += 90
+ m.fieldDrawRadius = m.fieldRange //* Math.min(1, 0.3 + 0.5 * Math.min(1, energy * energy));
+ m.drawCloak()
+ }
+ if (tech.isIntangible) {
+ if (m.isCloak) {
+ player.collisionFilter.mask = cat.map
+ let inPlayer = Matter.Query.region(mob, player.bounds)
+ if (inPlayer.length > 0) {
+ for (let i = 0; i < inPlayer.length; i++) {
+ if (m.energy > 0) {
+ if (!inPlayer[i].isUnblockable) m.energy -= 0.007;
+ if (inPlayer[i].shield) m.energy -= 0.025;
+ }
+ }
+ }
+ } else {
+ player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield //normal collisions
+ }
+ }
+ this.drawRegenEnergyCloaking()
+ if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) { //show sneak attack status
+ ctx.globalCompositeOperation = "multiply";
+ m.drawCloakedM()
+ ctx.globalCompositeOperation = "source-over";
+ }
+ }
+ }
+ },
+ {
+ name: "pilot wave",
+ //blocks can't collide with intangible mobs
+ //field radius decreases out of line of sight
+ //unlock tech from other fields
+ description: "use energy to guide blocks tech , fields , and guns have +2 choices generate 10 energy per second",
+ effect: () => {
+ m.fieldMeterColor = "#333"
+ m.eyeFillColor = m.fieldMeterColor
+
+ m.fieldPhase = 0;
+ m.fieldPosition = {
+ x: simulation.mouseInGame.x,
+ y: simulation.mouseInGame.y
+ }
+ m.lastFieldPosition = {
+ x: simulation.mouseInGame.x,
+ y: simulation.mouseInGame.y
+ }
+ m.fieldOn = false;
+ m.fieldRadius = 0;
+ m.drop();
+ m.hold = function () {
+ if (tech.isPrinter) {
+ //spawn blocks if field and crouch
+ if (input.field && m.fieldCDcycle < m.cycle && input.down && !m.isHolding) {
+ m.printBlock()
+ }
+ //if holding block grow it
+ if (m.isHolding) {
+ m.drawHold(m.holdingTarget);
+ m.holding();
+ if (tech.isPrinter && m.holdingTarget.isPrinted && input.field) {
+ // if (Math.random() < 0.004 && m.holdingTarget.vertices.length < 12) m.holdingTarget.vertices.push({ x: 0, y: 0 }) //small chance to increase the number of vertices
+ m.holdingTarget.radius += Math.min(1.1, 1.3 / m.holdingTarget.mass) //grow up to a limit
+ const r1 = m.holdingTarget.radius * (1 + 0.12 * Math.sin(m.cycle * 0.11))
+ const r2 = m.holdingTarget.radius * (1 + 0.12 * Math.cos(m.cycle * 0.11))
+ let angle = (m.cycle * 0.01) % (2 * Math.PI) //rotate the object
+ let vertices = []
+ for (let i = 0, len = m.holdingTarget.vertices.length; i < len; i++) {
+ angle += 2 * Math.PI / len
+ vertices.push({ x: m.holdingTarget.position.x + r1 * Math.cos(angle), y: m.holdingTarget.position.y + r2 * Math.sin(angle) })
+ }
+ Matter.Body.setVertices(m.holdingTarget, vertices)
+ m.definePlayerMass(m.defaultMass + m.holdingTarget.mass * m.holdingMassScale)
+ }
+ m.throwBlock()
+ } else {
+ m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ }
+ //if releasing field throw it
+
+ }
+ if (input.field) {
+ if (m.fieldCDcycle < m.cycle) {
+ const scale = 25
+ const bounds = {
+ min: {
+ x: m.fieldPosition.x - scale,
+ y: m.fieldPosition.y - scale
+ },
+ max: {
+ x: m.fieldPosition.x + scale,
+ y: m.fieldPosition.y + scale
+ }
+ }
+ const isInMap = Matter.Query.region(map, bounds).length
+ // const isInMap = Matter.Query.point(map, m.fieldPosition).length
+
+ if (!m.fieldOn) { // if field was off, and it starting up, teleport to new mouse location
+ m.fieldOn = true;
+ // m.fieldPosition = { //smooth the mouse position, set to starting at player
+ // x: m.pos.x,
+ // y: m.pos.y
+ // }
+ m.fieldPosition = { //smooth the mouse position, set to mouse's current location
+ x: simulation.mouseInGame.x,
+ y: simulation.mouseInGame.y
+ }
+ m.lastFieldPosition = { //used to find velocity of field changes
+ x: m.fieldPosition.x,
+ y: m.fieldPosition.y
+ }
+ } else { //when field is on it smoothly moves towards the mouse
+ m.lastFieldPosition = { //used to find velocity of field changes
+ x: m.fieldPosition.x,
+ y: m.fieldPosition.y
+ }
+ const smooth = isInMap ? 0.985 : 0.96;
+ m.fieldPosition = { //smooth the mouse position
+ x: m.fieldPosition.x * smooth + simulation.mouseInGame.x * (1 - smooth),
+ y: m.fieldPosition.y * smooth + simulation.mouseInGame.y * (1 - smooth),
+ }
+ }
+
+ //grab power ups into the field
+ for (let i = 0, len = powerUp.length; i < len; ++i) {
+ const dxP = m.fieldPosition.x - powerUp[i].position.x;
+ const dyP = m.fieldPosition.y - powerUp[i].position.y;
+ const dist2 = dxP * dxP + dyP * dyP + 200;
+ // float towards field if looking at and in range or if very close to player
+ if (
+ dist2 < m.fieldRadius * m.fieldRadius &&
+ (m.lookingAt(powerUp[i]) || dist2 < 16000)
+ ) {
+ powerUp[i].force.x += 0.05 * (dxP / Math.sqrt(dist2)) * powerUp[i].mass;
+ powerUp[i].force.y += 0.05 * (dyP / Math.sqrt(dist2)) * powerUp[i].mass - powerUp[i].mass * simulation.g; //negate gravity
+ //extra friction
+ Matter.Body.setVelocity(powerUp[i], {
+ x: powerUp[i].velocity.x * 0.11,
+ y: powerUp[i].velocity.y * 0.11
+ });
+ if (
+ dist2 < 5000 &&
+ !simulation.isChoosing &&
+ (powerUp[i].name !== "heal" || m.maxHealth - m.health > 0.01 || tech.isOverHeal)
+ // (powerUp[i].name !== "heal" || m.health < 0.94 * m.maxHealth)
+ // (powerUp[i].name !== "ammo" || b.guns[b.activeGun].ammo !== Infinity)
+ ) { //use power up if it is close enough
+ powerUps.onPickUp(powerUp[i]);
+ powerUp[i].effect();
+ Matter.Composite.remove(engine.world, powerUp[i]);
+ powerUp.splice(i, 1);
+ // m.fieldRadius += 50
+ break; //because the array order is messed up after splice
+ }
+ }
+ }
+ //grab power ups normally too
+ m.grabPowerUp();
+
+ if (m.energy > 0.01) {
+ //find mouse velocity
+ const diff = Vector.sub(m.fieldPosition, m.lastFieldPosition)
+ const speed = Vector.magnitude(diff)
+ const velocity = Vector.mult(Vector.normalise(diff), Math.min(speed, 60)) //limit velocity
+ let radius, radiusSmooth
+ if (Matter.Query.ray(map, m.fieldPosition, player.position).length) { //is there something block the player's view of the field
+ radius = 0
+ radiusSmooth = Math.max(0, isInMap ? 0.96 - 0.02 * speed : 0.995); //0.99
+ } else {
+ radius = Math.max(50, 250 - 2 * speed)
+ radiusSmooth = 0.97
+ }
+ m.fieldRadius = m.fieldRadius * radiusSmooth + radius * (1 - radiusSmooth)
+
+ for (let i = 0, len = body.length; i < len; ++i) {
+ if (Vector.magnitude(Vector.sub(body[i].position, m.fieldPosition)) < m.fieldRadius && !body[i].isNotHoldable) {
+ const DRAIN = speed * body[i].mass * 0.0000035 // * (1 + m.energy * m.energy) //drain more energy when you have more energy
+ if (m.energy > DRAIN) {
+ m.energy -= DRAIN;
+ Matter.Body.setVelocity(body[i], velocity); //give block mouse velocity
+ Matter.Body.setAngularVelocity(body[i], body[i].angularVelocity * 0.8)
+ // body[i].force.y -= body[i].mass * simulation.g; //remove gravity effects
+ //blocks drift towards center of pilot wave
+ const sub = Vector.sub(m.fieldPosition, body[i].position)
+ const push = Vector.mult(Vector.normalise(sub), 0.0001 * body[i].mass * Vector.magnitude(sub))
+ body[i].force.x += push.x
+ body[i].force.y += push.y - body[i].mass * simulation.g //remove gravity effects
+ // if (body[i].collisionFilter.category !== cat.bullet) {
+ // body[i].collisionFilter.category = cat.bullet;
+ // }
+ } else {
+ m.fieldCDcycle = m.cycle + 120;
+ m.fieldOn = false
+ m.fieldRadius = 0
+ break
+ }
+ }
+ }
+
+
+ // m.holdingTarget.collisionFilter.category = cat.bullet;
+ // m.holdingTarget.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield;
+ // //check every second to see if player is away from thrown body, and make solid
+ // const solid = function(that) {
+ // const dx = that.position.x - player.position.x;
+ // const dy = that.position.y - player.position.y;
+ // if (that.speed < 3 && dx * dx + dy * dy > 10000 && that !== m.holdingTarget) {
+ // that.collisionFilter.category = cat.body; //make solid
+ // that.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet; //can hit player now
+ // } else {
+ // setTimeout(solid, 40, that);
+ // }
+ // };
+ // setTimeout(solid, 200, m.holdingTarget);
+
+
+
+ // if (tech.isFreezeMobs) {
+ // for (let i = 0, len = mob.length; i < len; ++i) {
+ // if (!mob[i].isMobBullet && !mob[i].shield && !mob[i].isShielded && Vector.magnitude(Vector.sub(mob[i].position, m.fieldPosition)) < m.fieldRadius + mob[i].radius) {
+ // const ICE_DRAIN = 0.0005
+ // if (m.energy > ICE_DRAIN) m.energy -= ICE_DRAIN;
+ // mobs.statusSlow(mob[i], 180)
+ // }
+ // }
+ // }
+
+ ctx.beginPath();
+ const rotate = m.cycle * 0.008;
+ m.fieldPhase += 0.2 // - 0.5 * Math.sqrt(Math.min(m.energy, 1));
+ const off1 = 1 + 0.06 * Math.sin(m.fieldPhase);
+ const off2 = 1 - 0.06 * Math.sin(m.fieldPhase);
+ ctx.beginPath();
+ ctx.ellipse(m.fieldPosition.x, m.fieldPosition.y, 1.2 * m.fieldRadius * off1, 1.2 * m.fieldRadius * off2, rotate, 0, 2 * Math.PI);
+ ctx.globalCompositeOperation = "exclusion"; //"exclusion" "difference";
+ ctx.fillStyle = "#fff"; //"#eef";
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over";
+ ctx.beginPath();
+ ctx.ellipse(m.fieldPosition.x, m.fieldPosition.y, 1.2 * m.fieldRadius * off1, 1.2 * m.fieldRadius * off2, rotate, 0, 2 * Math.PI * m.energy / m.maxEnergy);
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 4;
+ ctx.stroke();
+ } else {
+ m.fieldCDcycle = m.cycle + 120;
+ m.fieldOn = false
+ m.fieldRadius = 0
+ }
+ } else {
+ m.grabPowerUp();
+ }
+ } else {
+ m.fieldOn = false
+ m.fieldRadius = 0
+ }
+ m.drawRegenEnergy("rgba(0,0,0,0.2)")
+ }
+ }
+ },
+ {
+ name: "wormhole",
+ //wormholes attract blocks and power ups
+ description: "use energy to tunnel through a wormhole +5% chance to duplicate spawned power ups generate 6 energy per second", // bullets may also traverse wormholes
+ drain: 0,
+ effect: function () {
+ m.fieldMeterColor = "#bbf" //"#0c5"
+ m.eyeFillColor = m.fieldMeterColor
+
+ m.duplicateChance = 0.05
+ m.fieldRange = 0
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+
+ m.hold = function () {
+ // m.hole = { //this is reset with each new field, but I'm leaving it here for reference
+ // isOn: false,
+ // isReady: true,
+ // pos1: {x: 0,y: 0},
+ // pos2: {x: 0,y: 0},
+ // angle: 0,
+ // unit:{x:0,y:0},
+ // }
+ if (m.hole.isOn) {
+ // draw holes
+ m.fieldRange = 0.97 * m.fieldRange + 0.03 * (50 + 10 * Math.sin(simulation.cycle * 0.025))
+ const semiMajorAxis = m.fieldRange + 30
+ const edge1a = Vector.add(Vector.mult(m.hole.unit, semiMajorAxis), m.hole.pos1)
+ const edge1b = Vector.add(Vector.mult(m.hole.unit, -semiMajorAxis), m.hole.pos1)
+ const edge2a = Vector.add(Vector.mult(m.hole.unit, semiMajorAxis), m.hole.pos2)
+ const edge2b = Vector.add(Vector.mult(m.hole.unit, -semiMajorAxis), m.hole.pos2)
+ ctx.beginPath();
+ ctx.moveTo(edge1a.x, edge1a.y)
+ ctx.bezierCurveTo(m.hole.pos1.x, m.hole.pos1.y, m.hole.pos2.x, m.hole.pos2.y, edge2a.x, edge2a.y);
+ ctx.lineTo(edge2b.x, edge2b.y)
+ ctx.bezierCurveTo(m.hole.pos2.x, m.hole.pos2.y, m.hole.pos1.x, m.hole.pos1.y, edge1b.x, edge1b.y);
+ ctx.fillStyle = `rgba(255,255,255,${200 / m.fieldRange / m.fieldRange})` //"rgba(0,0,0,0.1)"
+ ctx.fill();
+ ctx.beginPath();
+ ctx.ellipse(m.hole.pos1.x, m.hole.pos1.y, m.fieldRange, semiMajorAxis, m.hole.angle, 0, 2 * Math.PI)
+ ctx.ellipse(m.hole.pos2.x, m.hole.pos2.y, m.fieldRange, semiMajorAxis, m.hole.angle, 0, 2 * Math.PI)
+ ctx.fillStyle = `rgba(255,255,255,${32 / m.fieldRange})`
+ ctx.fill();
+
+ //suck power ups
+ for (let i = 0, len = powerUp.length; i < len; ++i) {
+ //which hole is closer
+ const dxP1 = m.hole.pos1.x - powerUp[i].position.x;
+ const dyP1 = m.hole.pos1.y - powerUp[i].position.y;
+ const dxP2 = m.hole.pos2.x - powerUp[i].position.x;
+ const dyP2 = m.hole.pos2.y - powerUp[i].position.y;
+ let dxP, dyP, dist2
+ if (dxP1 * dxP1 + dyP1 * dyP1 < dxP2 * dxP2 + dyP2 * dyP2) {
+ dxP = dxP1
+ dyP = dyP1
+ } else {
+ dxP = dxP2
+ dyP = dyP2
+ }
+ dist2 = dxP * dxP + dyP * dyP;
+ if (dist2 < 600000) { //&& !(m.health === m.maxHealth && powerUp[i].name === "heal")
+ powerUp[i].force.x += 4 * (dxP / dist2) * powerUp[i].mass; // float towards hole
+ powerUp[i].force.y += 4 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * simulation.g; //negate gravity
+ Matter.Body.setVelocity(powerUp[i], { //extra friction
+ x: powerUp[i].velocity.x * 0.05,
+ y: powerUp[i].velocity.y * 0.05
+ });
+ if (dist2 < 1000 && !simulation.isChoosing) { //use power up if it is close enough
+
+ // if (true) { //AoE radiation effect
+ // const range = 800
+
+ // for (let i = 0, len = mob.length; i < len; ++i) {
+ // if (mob[i].alive && !mob[i].isShielded) {
+ // dist = Vector.magnitude(Vector.sub(powerUp[i].position, mob[i].position)) - mob[i].radius;
+ // if (dist < range) mobs.statusDoT(mob[i], 0.5) //apply radiation damage status effect on direct hits
+ // }
+ // }
+
+ // simulation.drawList.push({
+ // x: powerUp[i].position.x,
+ // y: powerUp[i].position.y,
+ // radius: range,
+ // color: "rgba(0,150,200,0.3)",
+ // time: 4
+ // });
+ // }
+
+ m.fieldRange *= 0.8
+ powerUps.onPickUp(powerUp[i]);
+ powerUp[i].effect();
+ Matter.Composite.remove(engine.world, powerUp[i]);
+ powerUp.splice(i, 1);
+ break; //because the array order is messed up after splice
+ }
+ }
+ }
+ //suck and shrink blocks
+ const suckRange = 500
+ const shrinkRange = 100
+ const shrinkScale = 0.97;
+ const slowScale = 0.9
+ for (let i = 0, len = body.length; i < len; i++) {
+ if (!body[i].isNotHoldable) {
+ const dist1 = Vector.magnitude(Vector.sub(m.hole.pos1, body[i].position))
+ const dist2 = Vector.magnitude(Vector.sub(m.hole.pos2, body[i].position))
+ if (dist1 < dist2) {
+ if (dist1 < suckRange) {
+ const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos1, body[i].position)), 1)
+ const slow = Vector.mult(body[i].velocity, slowScale)
+ Matter.Body.setVelocity(body[i], Vector.add(slow, pull));
+ //shrink
+ if (Vector.magnitude(Vector.sub(m.hole.pos1, body[i].position)) < shrinkRange) {
+ Matter.Body.scale(body[i], shrinkScale, shrinkScale);
+ if (body[i].mass < 0.05) {
+ Matter.Composite.remove(engine.world, body[i]);
+ body.splice(i, 1);
+ m.fieldRange *= 0.8
+ if ((m.fieldMode === 0 || m.fieldMode === 9) && m.immuneCycle < m.cycle) m.energy += 0.02 * m.coupling
+ if (tech.isWormholeWorms) { //pandimensional spermia
+ b.worm(Vector.add(m.hole.pos2, Vector.rotate({ x: m.fieldRange * 0.4, y: 0 }, 2 * Math.PI * Math.random())))
+ Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), -10));
+ // for (let i = 0, len = Math.ceil(1.25 * Math.random()); i < len; i++) {
+ // }
+ }
+ break
+ }
+ }
+ }
+ } else if (dist2 < suckRange) {
+ const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos2, body[i].position)), 1)
+ const slow = Vector.mult(body[i].velocity, slowScale)
+ Matter.Body.setVelocity(body[i], Vector.add(slow, pull));
+ //shrink
+ if (Vector.magnitude(Vector.sub(m.hole.pos2, body[i].position)) < shrinkRange) {
+ Matter.Body.scale(body[i], shrinkScale, shrinkScale);
+ if (body[i].mass < 0.05) {
+ Matter.Composite.remove(engine.world, body[i]);
+ body.splice(i, 1);
+ m.fieldRange *= 0.8
+ // if (tech.isWormholeEnergy && m.energy < m.maxEnergy * 2) m.energy = m.maxEnergy * 2
+ // if (tech.isWormholeEnergy && m.immuneCycle < m.cycle) m.energy += 0.5
+ if ((m.fieldMode === 0 || m.fieldMode === 9) && m.immuneCycle < m.cycle) m.energy += 0.02 * m.coupling
+ if (m.fieldMode === 0 || m.fieldMode === 9) m.energy += 0.02 * m.coupling
+ if (tech.isWormholeWorms) { //pandimensional spermia
+ b.worm(Vector.add(m.hole.pos1, Vector.rotate({
+ x: m.fieldRange * 0.4,
+ y: 0
+ }, 2 * Math.PI * Math.random())))
+ Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), 5));
+ // for (let i = 0, len = Math.ceil(1.25 * Math.random()); i < len; i++) {
+ // }
+ }
+ break
+ }
+ }
+ }
+ }
+ }
+ if (tech.isWormHoleBullets) {
+ //teleport bullets
+ for (let i = 0, len = bullet.length; i < len; ++i) { //teleport bullets from hole1 to hole2
+ if (!bullet[i].botType && !bullet[i].isInHole) { //don't teleport bots
+ if (Vector.magnitude(Vector.sub(m.hole.pos1, bullet[i].position)) < m.fieldRange) { //find if bullet is touching hole1
+ Matter.Body.setPosition(bullet[i], Vector.add(m.hole.pos2, Vector.sub(m.hole.pos1, bullet[i].position)));
+ m.fieldRange += 5
+ bullet[i].isInHole = true
+ } else if (Vector.magnitude(Vector.sub(m.hole.pos2, bullet[i].position)) < m.fieldRange) { //find if bullet is touching hole1
+ Matter.Body.setPosition(bullet[i], Vector.add(m.hole.pos1, Vector.sub(m.hole.pos2, bullet[i].position)));
+ m.fieldRange += 5
+ bullet[i].isInHole = true
+ }
+ }
+ }
+ // mobs get pushed away
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (Vector.magnitude(Vector.sub(m.hole.pos1, mob[i].position)) < 200) {
+ const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos1, mob[i].position)), -0.07)
+ Matter.Body.setVelocity(mob[i], Vector.add(mob[i].velocity, pull));
+ }
+ if (Vector.magnitude(Vector.sub(m.hole.pos2, mob[i].position)) < 200) {
+ const pull = Vector.mult(Vector.normalise(Vector.sub(m.hole.pos2, mob[i].position)), -0.07)
+ Matter.Body.setVelocity(mob[i], Vector.add(mob[i].velocity, pull));
+ }
+ }
+ }
+ }
+
+ if (m.fieldCDcycle < m.cycle) {
+ const scale = 60
+ const justPastMouse = Vector.add(Vector.mult(Vector.normalise(Vector.sub(simulation.mouseInGame, m.pos)), 50), simulation.mouseInGame)
+ const sub = Vector.sub(simulation.mouseInGame, m.pos)
+ const mag = Vector.magnitude(sub)
+
+ if (input.field) {
+ if (tech.isWormHolePause) {
+ const drain = m.fieldRegen + 0.000035
+ if (m.energy > drain) {
+ m.energy -= drain
+ if (m.immuneCycle < m.cycle + 1) m.immuneCycle = m.cycle + 1; //player is immune to damage for 1 cycle
+ m.isBodiesAsleep = true;
+
+ function sleep(who) {
+ for (let i = 0, len = who.length; i < len; ++i) {
+ if (!who[i].isSleeping) {
+ who[i].storeVelocity = who[i].velocity
+ who[i].storeAngularVelocity = who[i].angularVelocity
+ }
+ Matter.Sleeping.set(who[i], true)
+ }
+ }
+ sleep(mob);
+ sleep(body);
+ sleep(bullet);
+ simulation.cycle--; //pause all functions that depend on game cycle increasing
+ Matter.Body.setVelocity(player, { //keep player frozen
+ x: 0,
+ y: -55 * player.mass * simulation.g //undo gravity before it is added
+ });
+ player.force.x = 0
+ player.force.y = 0
+ } else {
+ m.wakeCheck();
+ m.energy = 0;
+ }
+ }
+
+ m.grabPowerUp();
+ //draw possible wormhole
+ if (tech.isWormholeMapIgnore && Matter.Query.ray(map, m.pos, justPastMouse).length !== 0) {
+ this.drain = (0.05 + 0.005 * Math.sqrt(mag)) * 2
+ } else {
+ this.drain = tech.isFreeWormHole ? 0 : 0.05 + 0.005 * Math.sqrt(mag)
+ }
+ const unit = Vector.perp(Vector.normalise(sub))
+ const where = {
+ x: m.pos.x + 30 * Math.cos(m.angle),
+ y: m.pos.y + 30 * Math.sin(m.angle)
+ }
+ m.fieldRange = 0.97 * m.fieldRange + 0.03 * (50 + 10 * Math.sin(simulation.cycle * 0.025))
+ const edge2a = Vector.add(Vector.mult(unit, 1.5 * m.fieldRange), simulation.mouseInGame)
+ const edge2b = Vector.add(Vector.mult(unit, -1.5 * m.fieldRange), simulation.mouseInGame)
+ ctx.beginPath();
+ ctx.moveTo(where.x, where.y)
+ ctx.bezierCurveTo(where.x, where.y, simulation.mouseInGame.x, simulation.mouseInGame.y, edge2a.x, edge2a.y);
+ ctx.moveTo(where.x, where.y)
+ ctx.bezierCurveTo(where.x, where.y, simulation.mouseInGame.x, simulation.mouseInGame.y, edge2b.x, edge2b.y);
+ if (
+ mag > 250 && m.energy > this.drain &&
+ (tech.isWormholeMapIgnore || Matter.Query.ray(map, m.pos, justPastMouse).length === 0) &&
+ Matter.Query.region(map, {
+ min: {
+ x: simulation.mouseInGame.x - scale,
+ y: simulation.mouseInGame.y - scale
+ },
+ max: {
+ x: simulation.mouseInGame.x + scale,
+ y: simulation.mouseInGame.y + scale
+ }
+ }).length === 0
+ ) {
+ m.hole.isReady = true;
+ // ctx.fillStyle = "rgba(255,255,255,0.5)"
+ // ctx.fill();
+ ctx.lineWidth = 1
+ ctx.strokeStyle = "#000"
+ ctx.stroke();
+ } else {
+ m.hole.isReady = false;
+ ctx.lineWidth = 1
+ ctx.strokeStyle = "#000"
+ ctx.lineDashOffset = 30 * Math.random()
+ ctx.setLineDash([20, 40]);
+ ctx.stroke();
+ ctx.setLineDash([]);
+ }
+ } else {
+ if (tech.isWormHolePause && m.isBodiesAsleep) m.wakeCheck();
+
+ //make new wormhole
+ if (
+ m.hole.isReady && mag > 250 && m.energy > this.drain &&
+ (tech.isWormholeMapIgnore || Matter.Query.ray(map, m.pos, justPastMouse).length === 0) &&
+ Matter.Query.region(map, {
+ min: {
+ x: simulation.mouseInGame.x - scale,
+ y: simulation.mouseInGame.y - scale
+ },
+ max: {
+ x: simulation.mouseInGame.x + scale,
+ y: simulation.mouseInGame.y + scale
+ }
+ }).length === 0
+ ) {
+ m.energy -= this.drain
+ m.hole.isReady = false;
+ m.fieldRange = 0
+ Matter.Body.setPosition(player, simulation.mouseInGame);
+ m.buttonCD_jump = 0 //this might fix a bug with jumping
+ const velocity = Vector.mult(Vector.normalise(sub), 20)
+ Matter.Body.setVelocity(player, {
+ x: velocity.x,
+ y: velocity.y - 4 //an extra vertical kick so the player hangs in place longer
+ });
+ if (m.immuneCycle < m.cycle + 5) m.immuneCycle = m.cycle + 5; //player is immune to damage for 1/4 seconds
+ // move bots to player
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+
+ //set holes
+ m.hole.isOn = true;
+ m.hole.pos1.x = m.pos.x
+ m.hole.pos1.y = m.pos.y
+ m.hole.pos2.x = player.position.x
+ m.hole.pos2.y = player.position.y
+ m.hole.angle = Math.atan2(sub.y, sub.x)
+ m.hole.unit = Vector.perp(Vector.normalise(sub))
+
+ if (tech.isWormholeDamage) {
+ who = Matter.Query.ray(mob, m.pos, simulation.mouseInGame, 100)
+ for (let i = 0; i < who.length; i++) {
+ if (who[i].body.alive) {
+ mobs.statusDoT(who[i].body, 1, 420)
+ mobs.statusStun(who[i].body, 360)
+ }
+ }
+ }
+ }
+ }
+
+ // if (true && m.energy > 0.5) { //teleport away low mass mobs
+ // // && !(m.cycle % 1)
+ // const hit = Matter.Query.region(mob, {
+ // min: {
+ // x: m.pos.x - 80,
+ // y: m.pos.y - 80
+ // },
+ // max: {
+ // x: m.pos.x + 80,
+ // y: m.pos.y + 160
+ // }
+ // })
+
+ // // find incoming mob with low mass
+ // for (let i = 0; i < hit.length; i++) {
+ // if (hit[i].mass < 4 && m.energy > hit[i].mass * 0.06) {
+ // //is the mob moving towards the player?
+
+ // // console.log('found one', hit[i].mass)
+ // const unit = Vector.normalise(hit[i].velocity)
+ // const jump = Vector.mult(unit, 200)
+ // const where = Vector.add(hit[i].position, jump)
+ // if (Matter.Query.ray(map, hit[i].position, where).length === 0) { // check if space 180 from mob is clear of body and map
+ // // m.energy -= hit[i].mass * 0.06
+ // // m.fieldCDcycle = m.cycle + 30;
+ // simulation.drawList.push({ x: hit[i].position.x, y: hit[i].position.y, radius: 20, color: "#fff", time: 16 });
+ // Matter.Body.setPosition(hit[i], where);
+ // simulation.drawList.push({ x: hit[i].position.x, y: hit[i].position.y, radius: 20, color: "#fff", time: 16 });
+ // }
+ // // break
+ // }
+ // }
+ // }
+ }
+ // if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
+ // const justPastMouse = Vector.add(Vector.mult(Vector.normalise(Vector.sub(simulation.mouseInGame, m.pos)), 50), simulation.mouseInGame)
+ // const scale = 60
+ // const sub = Vector.sub(simulation.mouseInGame, m.pos)
+ // const mag = Vector.magnitude(sub)
+ // const drain = tech.isFreeWormHole ? 0 : 0.06 + 0.006 * Math.sqrt(mag)
+ // if (m.hole.isReady && mag > 250 && m.energy > drain) {
+ // if (
+ // Matter.Query.region(map, {
+ // min: {
+ // x: simulation.mouseInGame.x - scale,
+ // y: simulation.mouseInGame.y - scale
+ // },
+ // max: {
+ // x: simulation.mouseInGame.x + scale,
+ // y: simulation.mouseInGame.y + scale
+ // }
+ // }).length === 0 &&
+ // Matter.Query.ray(map, m.pos, justPastMouse).length === 0
+ // // Matter.Query.ray(map, m.pos, simulation.mouseInGame).length === 0 &&
+ // // Matter.Query.ray(map, player.position, simulation.mouseInGame).length === 0 &&
+ // // Matter.Query.ray(map, player.position, justPastMouse).length === 0
+ // ) {
+ // m.energy -= drain
+ // m.hole.isReady = false;
+ // m.fieldRange = 0
+ // Matter.Body.setPosition(player, simulation.mouseInGame);
+ // m.buttonCD_jump = 0 //this might fix a bug with jumping
+ // const velocity = Vector.mult(Vector.normalise(sub), 20)
+ // Matter.Body.setVelocity(player, {
+ // x: velocity.x,
+ // y: velocity.y - 4 //an extra vertical kick so the player hangs in place longer
+ // });
+ // if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 15; //player is immune to damage for 1/4 seconds
+ // // move bots to player
+ // for (let i = 0; i < bullet.length; i++) {
+ // if (bullet[i].botType) {
+ // Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ // x: 250 * (Math.random() - 0.5),
+ // y: 250 * (Math.random() - 0.5)
+ // }));
+ // Matter.Body.setVelocity(bullet[i], {
+ // x: 0,
+ // y: 0
+ // });
+ // }
+ // }
+
+ // //set holes
+ // m.hole.isOn = true;
+ // m.hole.pos1.x = m.pos.x
+ // m.hole.pos1.y = m.pos.y
+ // m.hole.pos2.x = player.position.x
+ // m.hole.pos2.y = player.position.y
+ // m.hole.angle = Math.atan2(sub.y, sub.x)
+ // m.hole.unit = Vector.perp(Vector.normalise(sub))
+
+ // if (tech.isWormholeDamage) {
+ // who = Matter.Query.ray(mob, m.pos, simulation.mouseInGame, 100)
+ // for (let i = 0; i < who.length; i++) {
+ // if (who[i].body.alive) {
+ // mobs.statusDoT(who[i].body, 1, 420)
+ // mobs.statusStun(who[i].body, 360)
+ // }
+ // }
+ // }
+ // } else {
+ // //draw failed wormhole
+ // const unit = Vector.perp(Vector.normalise(Vector.sub(simulation.mouseInGame, m.pos)))
+ // const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle), }
+ // m.fieldRange = 0.97 * m.fieldRange + 0.03 * (50 + 10 * Math.sin(simulation.cycle * 0.025))
+ // const edge2a = Vector.add(Vector.mult(unit, 1.5 * m.fieldRange), simulation.mouseInGame)
+ // const edge2b = Vector.add(Vector.mult(unit, -1.5 * m.fieldRange), simulation.mouseInGame)
+ // ctx.beginPath();
+ // ctx.moveTo(where.x, where.y)
+ // ctx.bezierCurveTo(where.x, where.y, simulation.mouseInGame.x, simulation.mouseInGame.y, edge2a.x, edge2a.y);
+ // ctx.lineTo(edge2b.x, edge2b.y)
+ // ctx.bezierCurveTo(simulation.mouseInGame.x, simulation.mouseInGame.y, where.x, where.y, where.x, where.y);
+ // // ctx.fillStyle = "rgba(255,255,255,0.5)"
+ // // ctx.fill();
+ // ctx.lineWidth = 1
+ // ctx.strokeStyle = "#000"
+ // ctx.lineDashOffset = 30 * Math.random()
+ // ctx.setLineDash([20, 40]);
+ // ctx.stroke();
+ // ctx.setLineDash([]);
+ // }
+ // }
+ // m.grabPowerUp();
+ // } else {
+ // m.hole.isReady = true;
+ // }
+ m.drawRegenEnergy()
+ }
+ },
+
+ // rewind: function() {
+ // if (input.down) {
+ // if (input.field && m.fieldCDcycle < m.cycle) { //not hold but field button is pressed
+ // const DRAIN = 0.01
+ // if (this.rewindCount < 289 && m.energy > DRAIN) {
+ // m.energy -= DRAIN
+
+
+ // if (this.rewindCount === 0) {
+ // const shortPause = function() {
+ // if (m.defaultFPSCycle < m.cycle) { //back to default values
+ // simulation.fpsCap = simulation.fpsCapDefault
+ // simulation.fpsInterval = 1000 / simulation.fpsCap;
+ // // document.getElementById("dmg").style.transition = "opacity 1s";
+ // // document.getElementById("dmg").style.opacity = "0";
+ // } else {
+ // requestAnimationFrame(shortPause);
+ // }
+ // };
+ // if (m.defaultFPSCycle < m.cycle) requestAnimationFrame(shortPause);
+ // simulation.fpsCap = 4 //1 is longest pause, 4 is standard
+ // simulation.fpsInterval = 1000 / simulation.fpsCap;
+ // m.defaultFPSCycle = m.cycle
+ // }
+
+
+ // this.rewindCount += 10;
+ // simulation.wipe = function() { //set wipe to have trails
+ // // ctx.fillStyle = "rgba(255,255,255,0)";
+ // ctx.fillStyle = `rgba(221,221,221,${0.004})`;
+ // ctx.fillRect(0, 0, canvas.width, canvas.height);
+ // }
+ // let history = m.history[(m.cycle - this.rewindCount) % 300]
+ // Matter.Body.setPosition(player, history.position);
+ // Matter.Body.setVelocity(player, { x: history.velocity.x, y: history.velocity.y });
+ // if (history.health > m.health) {
+ // m.health = history.health
+ // m.displayHealth();
+ // }
+ // //grab power ups
+ // for (let i = 0, len = powerUp.length; i < len; ++i) {
+ // const dxP = player.position.x - powerUp[i].position.x;
+ // const dyP = player.position.y - powerUp[i].position.y;
+ // if (dxP * dxP + dyP * dyP < 50000 && !simulation.isChoosing && !(m.health === m.maxHealth && powerUp[i].name === "heal")) {
+ // powerUps.onPickUp(player.position);
+ // powerUp[i].effect();
+ // Matter.Composite.remove(engine.world, powerUp[i]);
+ // powerUp.splice(i, 1);
+ // const shortPause = function() {
+ // if (m.defaultFPSCycle < m.cycle) { //back to default values
+ // simulation.fpsCap = simulation.fpsCapDefault
+ // simulation.fpsInterval = 1000 / simulation.fpsCap;
+ // // document.getElementById("dmg").style.transition = "opacity 1s";
+ // // document.getElementById("dmg").style.opacity = "0";
+ // } else {
+ // requestAnimationFrame(shortPause);
+ // }
+ // };
+ // if (m.defaultFPSCycle < m.cycle) requestAnimationFrame(shortPause);
+ // simulation.fpsCap = 3 //1 is longest pause, 4 is standard
+ // simulation.fpsInterval = 1000 / simulation.fpsCap;
+ // m.defaultFPSCycle = m.cycle
+ // break; //because the array order is messed up after splice
+ // }
+ // }
+ // m.immuneCycle = m.cycle + 5; //player is immune to damage for 30 cycles
+ // } else {
+ // m.fieldCDcycle = m.cycle + 30;
+ // // m.resetHistory();
+ // }
+ // } else {
+ // if (this.rewindCount !== 0) {
+ // m.fieldCDcycle = m.cycle + 30;
+ // m.resetHistory();
+ // this.rewindCount = 0;
+ // simulation.wipe = function() { //set wipe to normal
+ // ctx.clearRect(0, 0, canvas.width, canvas.height);
+ // }
+ // }
+ // m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
+ // }
+ // }
+ // m.drawRegenEnergy()
+ // },
+ },
+ ],
+ //************************************************************************************
+ //************************************************************************************
+ //************************************* SHIP ***************************************
+ //************************************************************************************
+ //************************************************************************************
+ isShipMode: false,
+ shipMode(thrust = 0.03, drag = 0.99, torque = 1.15, rotationDrag = 0.92) { // m.shipMode() //thrust = 0.03, drag = 0.99, torque = 1.15, rotationDrag = 0.92
+ if (!m.isShipMode) {
+ //if wires remove them
+ for (let i = 0; i < mob.length; i++) {
+ if (!mob[i].freeOfWires) mob[i].freeOfWires = true
+ }
+ m.isShipMode = true
+ // simulation.isCheating = true
+ const points = [{
+ x: 29.979168754143455,
+ y: 4.748337243898336
+ },
+ {
+ x: 27.04503734408824,
+ y: 13.7801138209198
+ },
+ {
+ x: 21.462582474874278,
+ y: 21.462582475257523
+ },
+ {
+ x: 13.780113820536943,
+ y: 27.045037344471485
+ },
+ {
+ x: 4.74833724351507,
+ y: 29.979168754526473
+ },
+ {
+ x: -4.748337245049098,
+ y: 29.979168754526473
+ },
+ {
+ x: -13.780113822071026,
+ y: 27.045037344471485
+ },
+ {
+ x: -21.46258247640829,
+ y: 21.462582475257523
+ },
+ {
+ x: -27.045037345621797,
+ y: 13.7801138209198
+ },
+ {
+ x: -29.979168755677012,
+ y: 4.748337243898336
+ },
+ {
+ x: -29.979168755677012,
+ y: -4.7483372446656045
+ },
+ {
+ x: -27.045037345621797,
+ y: -13.78011382168726
+ },
+ {
+ x: -21.46258247640829,
+ y: -21.462582476024817
+ },
+ {
+ x: -13.780113822071026,
+ y: -27.045037345239006
+ },
+ {
+ x: -4.748337245049098,
+ y: -29.97916875529422
+ },
+ {
+ x: 4.74833724351507,
+ y: -29.97916875529422
+ },
+ {
+ x: 13.780113820536943,
+ y: -27.045037345239006
+ },
+ {
+ x: 21.462582474874278,
+ y: -21.462582476024817
+ },
+ {
+ x: 27.04503734408824,
+ y: -13.78011382168726
+ },
+ {
+ x: 29.979168754143455,
+ y: -4.7483372446656045
+ }
+ ]
+ //
+ Matter.Body.setVertices(player, Matter.Vertices.create(points, player))
+ player.parts.pop()
+ player.parts.pop()
+ player.parts.pop()
+ player.parts.pop()
+ // Matter.Body.setDensity(player, 0.01); //extra dense //normal is 0.001 //makes effective life much larger
+ m.defaultMass = 30
+ Matter.Body.setMass(player, m.defaultMass);
+ player.friction = 0.01
+ player.restitution = 0.2
+ // player.frictionStatic = 0.1
+ // Matter.Body.setInertia(player, Infinity); //disable rotation
+
+ // const circle = Bodies.polygon(player.position.x, player.position.x, 30, 30)
+ // player.parts[0] = circle
+ // Matter.Body.setVertices(player.parts[0], Matter.Vertices.create(points, player.parts[0]))
+ m.spin = 0
+ // m.groundControl = () => {} //disable entering ground
+ m.onGround = false
+ m.lastOnGroundCycle = 0
+ // playerOnGroundCheck = () => {}
+ m.airControl = () => { //tank controls
+ player.force.y -= player.mass * simulation.g; //undo gravity
+ Matter.Body.setVelocity(player, {
+ x: drag * player.velocity.x,
+ y: drag * player.velocity.y
+ });
+ if (input.up) { //forward thrust
+ player.force.x += thrust * Math.cos(m.angle) * tech.squirrelJump
+ player.force.y += thrust * Math.sin(m.angle) * tech.squirrelJump
+ } else if (input.down) {
+ player.force.x -= 0.6 * thrust * Math.cos(m.angle)
+ player.force.y -= 0.6 * thrust * Math.sin(m.angle)
+ }
+ //rotation
+ Matter.Body.setAngularVelocity(player, player.angularVelocity * rotationDrag)
+ if (input.right) {
+ player.torque += torque
+ } else if (input.left) {
+ player.torque -= torque
+ }
+ m.angle += m.spin
+ m.angle = player.angle
+ }
+
+
+
+
+
+ // level.exit.drawAndCheck = () => { //fix this
+ // if (
+ // player.position.x > level.exit.x &&
+ // player.position.x < level.exit.x + 100 &&
+ // player.position.y > level.exit.y - 150 &&
+ // player.position.y < level.exit.y + 40
+ // ) {
+ // level.nextLevel()
+ // }
+ // }
+ m.move = () => {
+ m.pos.x = player.position.x;
+ m.pos.y = player.position.y;
+ m.Vx = player.velocity.x;
+ m.Vy = player.velocity.y;
+
+ //tracks the last 10s of player information
+ m.history.splice(m.cycle % 600, 1, {
+ position: {
+ x: player.position.x,
+ y: player.position.y,
+ },
+ velocity: {
+ x: player.velocity.x,
+ y: player.velocity.y
+ },
+ yOff: m.yOff,
+ angle: m.angle,
+ health: m.health,
+ energy: m.energy,
+ activeGun: b.activeGun
+ });
+ }
+
+ m.look = () => { //disable mouse aiming
+ const scale = 0.8;
+ m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+
+ m.transX += (m.transSmoothX - m.transX) * 0.07;
+ m.transY += (m.transSmoothY - m.transY) * 0.07;
+ }
+
+ simulation.camera = () => {
+ const dx = simulation.mouse.x / window.innerWidth - 0.5 //x distance from mouse to window center scaled by window width
+ const dy = simulation.mouse.y / window.innerHeight - 0.5 //y distance from mouse to window center scaled by window height
+ const d = Math.max(dx * dx, dy * dy)
+ simulation.edgeZoomOutSmooth = (1 + 4 * d * d) * 0.04 + simulation.edgeZoomOutSmooth * 0.96
+
+ ctx.save();
+ ctx.translate(canvas.width2, canvas.height2); //center
+ ctx.scale(simulation.zoom / simulation.edgeZoomOutSmooth, simulation.zoom / simulation.edgeZoomOutSmooth); //zoom in once centered
+ ctx.translate(-canvas.width2 + m.transX, -canvas.height2 + m.transY); //translate
+ //calculate in game mouse position by undoing the zoom and translations
+ simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX;
+ simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY;
+ }
+
+ m.draw = () => { //just draw the circle
+ ctx.save();
+ ctx.globalAlpha = (m.immuneCycle < m.cycle) ? 1 : 0.5
+ ctx.translate(player.position.x, player.position.y);
+ ctx.rotate(player.angle);
+
+ //thrust
+ if (input.up) {
+ var grd2 = ctx.createLinearGradient(0, 0, -150, 0);
+ // grd2.addColorStop(0, 'rgba(255, 255, 155, 0.8)');
+ // grd2.addColorStop(1, 'rgba(255, 200, 0, 0.1)');
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(-18, -25);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(-18, 25);
+ ctx.lineTo(-50 - 100 * Math.random(), 0);
+ ctx.fill();
+ } else if (input.down) {
+ var grd2 = ctx.createLinearGradient(0, 0, 80, 0);
+ grd2.addColorStop(0, 'rgba(150, 200, 255, 0.7)');
+ grd2.addColorStop(1, 'rgba(150, 200, 255, 0)');
+ ctx.fillStyle = grd2;
+ ctx.beginPath();
+ ctx.moveTo(20, -16);
+ //10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5)
+ ctx.lineTo(20, 16);
+ ctx.lineTo(35 + 43 * Math.random(), 0);
+ ctx.fill();
+ }
+
+ //body
+ ctx.beginPath();
+ ctx.arc(0, 0, 30, 0, 2 * Math.PI);
+ ctx.fillStyle = m.bodyGradient
+ ctx.fill();
+ ctx.arc(15, 0, 4, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#333";
+ ctx.lineWidth = 2;
+ ctx.stroke();
+
+ ctx.restore();
+ }
+
+ //fix collisions
+ collisionChecks = function (event) {
+ const pairs = event.pairs;
+ for (let i = 0, j = pairs.length; i != j; i++) {
+ //mob + (player,bullet,body) collisions
+ for (let k = 0; k < mob.length; k++) {
+ if (mob[k].alive && m.alive) {
+ if (pairs[i].bodyA === mob[k]) {
+ collideMob(pairs[i].bodyB);
+ break;
+ } else if (pairs[i].bodyB === mob[k]) {
+ collideMob(pairs[i].bodyA);
+ break;
+ }
+
+ function collideMob(obj) {
+ //player + mob collision
+ if (
+ m.immuneCycle < m.cycle &&
+ // (obj === playerBody || obj === playerHead) &&
+ (obj === player) &&
+ !mob[k].isSlowed && !mob[k].isStunned
+ ) {
+ mob[k].foundPlayer();
+ let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * simulation.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0
+ if (tech.isRewindAvoidDeath && (m.energy + 0.05) > Math.min(0.95, m.maxEnergy) && dmg > 0.01) { //CPT reversal runs in m.damage, but it stops the rest of the collision code here too
+ m.damage(dmg);
+ return
+ }
+ m.damage(dmg);
+ if (tech.isPiezo) m.energy += 20.48;
+ if (tech.isStimulatedEmission) powerUps.ejectTech()
+ if (mob[k].onHit) mob[k].onHit();
+ if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ //extra kick between player and mob //this section would be better with forces but they don't work...
+ let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x);
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x + 8 * Math.cos(angle),
+ y: player.velocity.y + 8 * Math.sin(angle)
+ });
+ Matter.Body.setVelocity(mob[k], {
+ x: mob[k].velocity.x - 8 * Math.cos(angle),
+ y: mob[k].velocity.y - 8 * Math.sin(angle)
+ });
+
+ if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.34 * m.maxEnergy) {
+ m.energy -= 0.33 * Math.max(m.maxEnergy, m.energy)
+ m.immuneCycle = 0; //player doesn't go immune to collision damage
+ mob[k].death();
+ simulation.drawList.push({ //add dmg to draw queue
+ x: pairs[i].activeContacts[0].vertex.x,
+ y: pairs[i].activeContacts[0].vertex.y,
+ radius: dmg * 2000,
+ color: "rgba(255,0,255,0.2)",
+ time: simulation.drawTime
+ });
+ } else {
+ simulation.drawList.push({ //add dmg to draw queue
+ x: pairs[i].activeContacts[0].vertex.x,
+ y: pairs[i].activeContacts[0].vertex.y,
+ radius: dmg * 500,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ }
+ return;
+ // }
+ }
+ //mob + bullet collisions
+ if (obj.classType === "bullet" && obj.speed > obj.minDmgSpeed) {
+ obj.beforeDmg(mob[k]); //some bullets do actions when they hits things, like despawn //forces don't seem to work here
+ let dmg = m.dmgScale * (obj.dmg + 0.15 * obj.mass * Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity)))
+ if (tech.isCrit && mob[k].isStunned) dmg *= 4
+ mob[k].damage(dmg);
+ if (mob[k].alive) mob[k].foundPlayer();
+ if (mob[k].damageReduction) {
+ simulation.drawList.push({ //add dmg to draw queue
+ x: pairs[i].activeContacts[0].vertex.x,
+ y: pairs[i].activeContacts[0].vertex.y,
+ radius: Math.log(dmg + 1.1) * 40 * mob[k].damageReduction + 3,
+ color: simulation.playerDmgColor,
+ time: simulation.drawTime
+ });
+ }
+ return;
+ }
+ //mob + body collisions
+ if (obj.classType === "body" && obj.speed > 6) {
+ const v = Vector.magnitude(Vector.sub(mob[k].velocity, obj.velocity));
+ if (v > 9) {
+ let dmg = tech.blockDamage * m.dmgScale * v * obj.mass * (tech.isMobBlockFling ? 2 : 1);
+ if (mob[k].isShielded) dmg *= 0.7
+ mob[k].damage(dmg, true);
+ if (tech.isBlockPowerUps && !mob[k].alive && mob[k].isDropPowerUp && m.throwCycle > m.cycle) {
+ let type = tech.isEnergyNoAmmo ? "heal" : "ammo"
+ if (Math.random() < 0.4) {
+ type = "heal"
+ } else if (Math.random() < 0.4 && !tech.isSuperDeterminism) {
+ type = "research"
+ }
+ powerUps.spawn(mob[k].position.x, mob[k].position.y, type);
+ // for (let i = 0, len = Math.ceil(2 * Math.random()); i < len; i++) {}
+ }
+
+ const stunTime = dmg / Math.sqrt(obj.mass)
+ if (stunTime > 0.5) mobs.statusStun(mob[k], 30 + 60 * Math.sqrt(stunTime))
+ if (mob[k].alive && mob[k].distanceToPlayer2() < 1000000 && !m.isCloak) mob[k].foundPlayer();
+ if (tech.fragments && obj.speed > 10 && !obj.hasFragmented) {
+ obj.hasFragmented = true;
+ b.targetedNail(obj.position, tech.fragments * 4)
+ }
+ if (mob[k].damageReduction) {
+ simulation.drawList.push({
+ x: pairs[i].activeContacts[0].vertex.x,
+ y: pairs[i].activeContacts[0].vertex.y,
+ radius: Math.log(dmg + 1.1) * 40 * mob[k].damageReduction + 3,
+ color: simulation.playerDmgColor,
+ time: simulation.drawTime
+ });
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+};
\ No newline at end of file
diff --git a/ngon/js/powerup.js b/ngon/js/powerup.js
new file mode 100644
index 00000000..cbc9b4da
--- /dev/null
+++ b/ngon/js/powerup.js
@@ -0,0 +1,1595 @@
+let powerUp = [];
+
+const powerUps = {
+ ejectGraphic(color = "68, 102, 119") {
+ simulation.drawList.push({
+ x: m.pos.x,
+ y: m.pos.y,
+ radius: 100,
+ color: `rgba(${color}, 0.8)`,
+ time: 4
+ });
+ simulation.drawList.push({
+ x: m.pos.x,
+ y: m.pos.y,
+ radius: 75,
+ color: `rgba(${color}, 0.6)`,
+ time: 8
+ });
+ simulation.drawList.push({
+ x: m.pos.x,
+ y: m.pos.y,
+ radius: 50,
+ color: `rgba(${color}, 0.3)`,
+ time: 12
+ });
+ simulation.drawList.push({
+ x: m.pos.x,
+ y: m.pos.y,
+ radius: 25,
+ color: `rgba(${color}, 0.15)`,
+ time: 16
+ });
+ },
+ healGiveMaxEnergy: false, //for tech 1st ionization energy
+ orb: {
+ research(num = 1) {
+ switch (num) {
+ case 1:
+ return `
`
+ case 2:
+ return `
+
+
+ `
+ case 3:
+ return `
+
+
+
+ `
+ case 4:
+ return `
+
+
+
+
+ `
+ case 5:
+ return `
+
+
+
+
+
+ `
+ case 6:
+ return `
+
+
+
+
+
+
+ `
+ }
+ let text = ''
+ for (let i = 0; i < num; i++) {
+ text += `
`
+ }
+ text += ' '
+ for (let i = 0; i < num; i++) {
+ text += ' '
+ }
+ return text
+ },
+ ammo(num = 1) {
+ switch (num) {
+ case 1:
+ return `
`
+ }
+ let text = ''
+ for (let i = 0; i < num; i++) {
+ text += `
`
+ }
+ text += ' '
+ for (let i = 0; i < num; i++) {
+ text += ' '
+ }
+ return text
+ },
+ heal(num = 1) {
+ if (powerUps.healGiveMaxEnergy) {
+ switch (num) {
+ case 1:
+ return `
`
+ }
+ let text = ''
+ for (let i = 0; i < num; i++) {
+ text += `
`
+ }
+ text += ' '
+ for (let i = 0; i < num; i++) {
+ text += ' '
+ }
+ return text
+ } else {
+ switch (num) {
+ case 1:
+ return `
`
+ }
+ let text = ''
+ for (let i = 0; i < num; i++) {
+ text += `
`
+ }
+ text += ' '
+ for (let i = 0; i < num; i++) {
+ text += ' '
+ }
+ return text
+ }
+ },
+ tech(num = 1) {
+ return `
`
+ },
+ coupling(num = 1) {
+ switch (num) {
+ case 1:
+ return `
`
+ }
+ let text = ''
+ for (let i = 0; i < num; i++) {
+ text += `
`
+ }
+ text += ' '
+ for (let i = 0; i < num; i++) {
+ text += ' '
+ }
+ return text
+ },
+ boost(num = 1) {
+ switch (num) {
+ case 1:
+ return `
`
+ }
+ let text = ''
+ for (let i = 0; i < num; i++) {
+ text += `
`
+ }
+ text += ' '
+ for (let i = 0; i < num; i++) {
+ text += ' '
+ }
+ return text
+ },
+ },
+ totalPowerUps: 0, //used for tech that count power ups at the end of a level
+ do() { },
+ setPowerUpMode() {
+ if (tech.duplicationChance() > 0 || tech.isAnthropicTech) {
+ powerUps.draw = powerUps.drawDup
+ if (tech.isPowerUpsVanish) {
+ if (tech.isHealAttract) {
+ powerUps.do = () => {
+ powerUps.dupExplode();
+ powerUps.draw();
+ powerUps.attractHeal();
+ }
+ } else {
+ powerUps.do = () => {
+ powerUps.dupExplode();
+ powerUps.draw();
+ }
+ }
+ } else if (tech.isHealAttract) {
+ powerUps.do = () => {
+ powerUps.draw();
+ powerUps.attractHeal();
+ }
+ } else {
+ powerUps.do = () => powerUps.draw();
+ }
+ tech.maxDuplicationEvent() //check to see if hitting 100% duplication
+ } else {
+ powerUps.draw = powerUps.drawCircle
+ if (tech.isHealAttract) {
+ powerUps.do = () => {
+ powerUps.draw();
+ powerUps.attractHeal();
+ }
+ } else {
+ powerUps.do = powerUps.draw
+ }
+ }
+ },
+ draw() { },
+ drawCircle() {
+ ctx.globalAlpha = 0.4 * Math.sin(simulation.cycle * 0.15) + 0.6;
+ for (let i = 0, len = powerUp.length; i < len; ++i) {
+ ctx.beginPath();
+ ctx.arc(powerUp[i].position.x, powerUp[i].position.y, powerUp[i].size, 0, 2 * Math.PI);
+ ctx.fillStyle = powerUp[i].color;
+ ctx.fill();
+ }
+ ctx.globalAlpha = 1;
+ },
+ drawDup() {
+ ctx.globalAlpha = 0.4 * Math.sin(simulation.cycle * 0.15) + 0.6;
+ for (let i = 0, len = powerUp.length; i < len; ++i) {
+ ctx.beginPath();
+ if (powerUp[i].isDuplicated) {
+ let vertices = powerUp[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ } else {
+ ctx.arc(powerUp[i].position.x, powerUp[i].position.y, powerUp[i].size, 0, 2 * Math.PI);
+ }
+ ctx.fillStyle = powerUp[i].color;
+ ctx.fill();
+ }
+ ctx.globalAlpha = 1;
+ },
+ attractHeal() {
+ for (let i = 0; i < powerUp.length; i++) { //attract heal power ups to player
+ if (powerUp[i].name === "heal") {
+ let attract = Vector.mult(Vector.normalise(Vector.sub(m.pos, powerUp[i].position)), 0.015 * powerUp[i].mass)
+ powerUp[i].force.x += attract.x;
+ powerUp[i].force.y += attract.y - powerUp[i].mass * simulation.g; //negate gravity
+ Matter.Body.setVelocity(powerUp[i], Vector.mult(powerUp[i].velocity, 0.7));
+ }
+ }
+ },
+ dupExplode() {
+ for (let i = 0, len = powerUp.length; i < len; ++i) {
+ if (powerUp[i].isDuplicated) {
+ if (Math.random() < 0.003) { // (1-0.003)^240 = chance to be removed after 4 seconds, 240 = 4 seconds * 60 cycles per second
+ b.explosion(powerUp[i].position, 175 + (11 + 3 * Math.random()) * powerUp[i].size);
+ Matter.Composite.remove(engine.world, powerUp[i]);
+ powerUp.splice(i, 1);
+ break
+ }
+ if (Math.random() < 0.3) { //draw electricity
+ const mag = 4 + powerUp[i].size / 5
+ let unit = Vector.rotate({ x: mag, y: mag }, 2 * Math.PI * Math.random())
+ let path = { x: powerUp[i].position.x + unit.x, y: powerUp[i].position.y + unit.y }
+ ctx.beginPath();
+ ctx.moveTo(path.x, path.y);
+ for (let i = 0; i < 6; i++) {
+ unit = Vector.rotate(unit, 4 * (Math.random() - 0.5))
+ path = Vector.add(path, unit)
+ ctx.lineTo(path.x, path.y);
+ }
+ ctx.lineWidth = 0.5 + 2 * Math.random();
+ ctx.strokeStyle = "#000"
+ ctx.stroke();
+ }
+ }
+ }
+ },
+ choose(type, index) {
+ if (type === "gun") {
+ b.giveGuns(index)
+ let text = `b.giveGuns("${b.guns[index].name} ")`
+ if (b.inventory.length === 1) text += ` input.key.gun: ["MouseLeft "]`
+ if (b.inventory.length === 2) text += `
+ input.key.nextGun: ["${input.key.nextGun} ","MouseWheel "]
+ input.key.previousGun: ["${input.key.previousGun} ","MouseWheel "]`
+ simulation.makeTextLog(text);
+ } else if (type === "field") {
+ m.setField(index)
+ } else if (type === "tech") {
+ // if (tech.isBanish && tech.tech[index].isBanished) tech.tech[index].isBanished = false
+ simulation.makeTextLog(`tech .giveTech("${tech.tech[index].name} ")`);
+ tech.giveTech(index)
+ }
+ powerUps.endDraft(type);
+ },
+ showDraft() {
+ //disable clicking for 1/2 a second to prevent mistake clicks
+ document.getElementById("choose-grid").style.pointerEvents = "none";
+ document.body.style.cursor = "none";
+ setTimeout(() => {
+ // if (!tech.isNoDraftPause)
+ document.body.style.cursor = "auto";
+ document.getElementById("choose-grid").style.pointerEvents = "auto";
+ document.getElementById("choose-grid").style.transitionDuration = "0s";
+ }, 400);
+ simulation.isChoosing = true; //stops p from un pausing on key down
+
+ if (!simulation.paused) {
+ if (tech.isNoDraftPause) {
+ document.getElementById("choose-grid").style.opacity = "1"
+ } else {
+ simulation.paused = true;
+ document.getElementById("choose-grid").style.opacity = "1"
+ }
+ document.getElementById("choose-grid").style.transitionDuration = "0.5s"; //how long is the fade in on
+ document.getElementById("choose-grid").style.visibility = "visible"
+
+ requestAnimationFrame(() => {
+ ctx.fillStyle = `rgba(150,150,150,0.9)`; //`rgba(221,221,221,0.6)`;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ });
+ // document.getElementById("pause-grid-right").style.opacity = "0.7"
+ // document.getElementById("pause-grid-left").style.opacity = "0.7"
+ }
+ // build.pauseGrid()
+ },
+ endDraft(type, isCanceled = false) { //type should be a gun, tech, or field
+ if (isCanceled) {
+ if (tech.isCancelTech && Math.random() < 0.85 && type !== "entanglement") {
+ // powerUps.research.use('tech')
+ powerUps[type].effect();
+ return
+ }
+ if (tech.isCancelDuplication) {
+ tech.duplication += 0.041
+ tech.maxDuplicationEvent()
+ simulation.makeTextLog(`tech.duplicationChance() += ${0.043}`)
+ simulation.circleFlare(0.043);
+ }
+ if (tech.isCancelRerolls) {
+ for (let i = 0, len = 5 + 5 * Math.random(); i < len; i++) {
+ let spawnType
+ if (Math.random() < 0.4 && !tech.isEnergyNoAmmo) {
+ spawnType = "ammo"
+ } else if (Math.random() < 0.33 && !tech.isSuperDeterminism) {
+ spawnType = "research"
+ } else {
+ spawnType = "heal"
+ }
+ powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), spawnType, false);
+ }
+ }
+ if (tech.isCancelCouple) powerUps.spawnDelay("coupling", 5)
+ // if (tech.isCancelTech && Math.random() < 0.3) {
+ // powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "tech", false);
+ // simulation.makeTextLog(`options exchange : returns 1 tech `)
+ // }
+ // if (tech.isBanish && type === 'tech') { // banish researched tech by adding them to the list of banished tech
+ // const banishLength = tech.isDeterminism ? 1 : 3 + tech.extraChoices * 2
+ // for (let i = 0; i < banishLength; i++) {
+ // const index = powerUps.tech.choiceLog.length - i - 1
+ // if (powerUps.tech.choiceLog[index] && tech.tech[powerUps.tech.choiceLog[index]]) {
+ // tech.tech[powerUps.tech.choiceLog[index]].isBanished = true
+ // }
+ // }
+ // simulation.makeTextLog(`powerUps.tech.length: ${Math.max(0,powerUps.tech.lastTotalChoices - banishLength)}`)
+ // }
+ }
+ if (tech.isAnsatz && powerUps.research.count < 1) {
+ for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
+ }
+ // document.getElementById("choose-grid").style.display = "none"
+ document.getElementById("choose-grid").style.visibility = "hidden"
+ document.getElementById("choose-grid").style.opacity = "0"
+
+ document.body.style.cursor = "none";
+ // document.body.style.overflow = "hidden"
+ // if (m.alive){}
+ if (simulation.paused) requestAnimationFrame(cycle);
+ if (m.alive) simulation.paused = false;
+ simulation.isChoosing = false; //stops p from un pausing on key down
+ build.unPauseGrid()
+ if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 15; //player is immune to damage for 30 cycles
+ if (m.holdingTarget) m.drop();
+ },
+ coupling: {
+ name: "coupling",
+ color: "#0ae", //"#0cf",
+ size() {
+ return 13;
+ },
+ effect() {
+ m.couplingChange(1)
+ },
+ // spawnDelay(num) {
+ // let count = num
+ // let respawnDrones = () => {
+ // if (count > 0) {
+ // requestAnimationFrame(respawnDrones);
+ // if (!simulation.paused && !simulation.isChoosing) { //&& !(simulation.cycle % 2)
+ // count--
+ // const where = { x: m.pos.x + 50 * (Math.random() - 0.5), y: m.pos.y + 50 * (Math.random() - 0.5) }
+ // powerUps.spawn(where.x, where.y, "coupling");
+ // }
+ // }
+ // }
+ // requestAnimationFrame(respawnDrones);
+ // }
+ },
+ boost: {
+ name: "boost",
+ color: "#f55", //"#0cf",
+ size() {
+ return 11;
+ },
+ endCycle: 0,
+ duration: null, //set by "tech: band gap"
+ damage: null, //set by "tech: band gap"
+ effect() {
+ powerUps.boost.endCycle = m.cycle + Math.floor(Math.max(0, powerUps.boost.endCycle - m.cycle) * 0.6) + powerUps.boost.duration //duration+seconds plus 2/3 of current time left
+ },
+ draw() {
+ // console.log(this.endCycle)
+ if (powerUps.boost.endCycle > m.cycle) {
+ ctx.strokeStyle = "rgba(255,0,0,0.8)" //m.fieldMeterColor; //"rgba(255,255,0,0.2)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})`
+ ctx.beginPath();
+ const arc = (powerUps.boost.endCycle - m.cycle) / powerUps.boost.duration
+ ctx.arc(m.pos.x, m.pos.y, 28, m.angle - Math.PI * arc, m.angle + Math.PI * arc); //- Math.PI / 2
+ ctx.lineWidth = 4
+ ctx.stroke();
+ }
+ },
+ },
+ research: {
+ count: 0,
+ name: "research",
+ color: "#f7b",
+ size() {
+ return 20;
+ },
+ effect() {
+ powerUps.research.changeRerolls(1)
+ },
+ isMakingBots: false, //to prevent bot fabrication from running 2 sessions at once
+ changeRerolls(amount) {
+ if (amount !== 0) powerUps.research.count += amount
+ if (tech.isRerollBots && !this.isMakingBots) {
+ let cycle = () => {
+ const cost = 2 + Math.floor(0.2 * b.totalBots())
+ if (m.alive && powerUps.research.count >= cost) {
+ requestAnimationFrame(cycle);
+ this.isMakingBots = true
+ } else {
+ this.isMakingBots = false
+ }
+ if (!simulation.paused && !simulation.isChoosing && !(simulation.cycle % 60)) {
+ powerUps.research.count -= cost
+ b.randomBot()
+ if (tech.renormalization) {
+ for (let i = 0; i < cost; i++) {
+ if (Math.random() < 0.46) {
+ m.fieldCDcycle = m.cycle + 20;
+ powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
+ }
+ }
+ }
+ }
+ }
+ requestAnimationFrame(cycle);
+ }
+ if (tech.isDeathAvoid && document.getElementById("tech-anthropic")) {
+ document.getElementById("tech-anthropic").innerHTML = `-${powerUps.research.count}`
+ }
+ if (tech.renormalization && Math.random() < 0.46 && amount < 0) {
+ for (let i = 0, len = -amount; i < len; i++) powerUps.spawn(m.pos.x, m.pos.y, "research");
+ }
+ if (tech.isRerollHaste) {
+ if (powerUps.research.count === 0) {
+ tech.researchHaste = 0.66;
+ b.setFireCD();
+ } else {
+ tech.researchHaste = 1;
+ b.setFireCD();
+ }
+ }
+ },
+ currentRerollCount: 0,
+ use(type) { //runs when you actually research a list of selections, type can be field, gun, or tech
+ if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) {
+ tech.addJunkTechToPool(tech.junkResearchNumber * 0.01)
+ } else {
+ powerUps.research.changeRerolls(-1)
+ }
+ powerUps.research.currentRerollCount++
+ // if (tech.isBanish && type === 'tech') { // banish researched tech
+ // const banishLength = tech.isDeterminism ? 1 : 3 + tech.extraChoices * 2
+ // for (let i = 0; i < banishLength; i++) {
+ // const index = powerUps.tech.choiceLog.length - i - 1
+ // if (powerUps.tech.choiceLog[index] && tech.tech[powerUps.tech.choiceLog[index]]) tech.tech[powerUps.tech.choiceLog[index]].isBanished = true
+ // }
+ // simulation.makeTextLog(`powerUps.tech.length: ${Math.max(0,powerUps.tech.lastTotalChoices - banishLength)}`)
+ // }
+ if (tech.isResearchReality) {
+ m.switchWorlds()
+ simulation.trails()
+ simulation.makeTextLog(`simulation.amplitude = ${Math.random()}`);
+ }
+ powerUps[type].effect();
+ },
+ },
+ heal: {
+ name: "heal",
+ color: "#0eb",
+ size() {
+ return Math.sqrt(0.1 + 0.25) * 40 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals * (tech.isHalfHeals ? 0.5 : 1)) * (tech.isFlipFlopOn && tech.isFlipFlopHealth ? Math.sqrt(2) : 1); //(simulation.healScale ** 0.25) gives a smaller radius as heal scale goes down
+ },
+ effect() {
+ if (!tech.isEnergyHealth && m.alive) {
+ let heal = (this.size / 40 / (simulation.healScale ** 0.25)) ** 2 //simulation.healScale is undone here because heal scale is already properly affected on m.addHealth()
+ // console.log("size = " + this.size, "heal = " + heal)
+ if (heal > 0) {
+ const overHeal = m.health + heal * simulation.healScale - m.maxHealth //used with tech.isOverHeal
+ const healOutput = Math.min(m.maxHealth - m.health, heal) * simulation.healScale
+ m.addHealth(heal);
+ if (healOutput > 0) simulation.makeTextLog(`m .health += ${(healOutput).toFixed(3)}`) // ${m.health.toFixed(3)}
+ if (tech.isOverHeal && overHeal > 0) { //tech quenching
+ const scaledOverHeal = overHeal // * 0.9
+ m.damage(scaledOverHeal);
+ simulation.makeTextLog(`m .health -= ${(scaledOverHeal).toFixed(3)}`) // ${m.health.toFixed(3)}
+ simulation.drawList.push({ //add dmg to draw queue
+ x: m.pos.x,
+ y: m.pos.y,
+ radius: scaledOverHeal * 500 * simulation.healScale,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ tech.extraMaxHealth += scaledOverHeal * simulation.healScale //increase max health
+ m.setMaxHealth();
+ } else if (overHeal > 0.1) {
+ requestAnimationFrame(() => {
+ powerUps.directSpawn(this.position.x, this.position.y, "heal", true, null, overHeal * 40 * (simulation.healScale ** 0.25))// directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) {
+ });
+ }
+ if (tech.isHealBrake) {
+ const totalTime = 900
+ //check if you already have this effect
+ let foundActiveEffect = false
+ for (let i = 0; i < simulation.ephemera.length; i++) {
+ if (simulation.ephemera[i].name === "healPush") {
+ foundActiveEffect = true
+ simulation.ephemera[i].count = 0.5 * simulation.ephemera[i].count + totalTime //add time
+ simulation.ephemera[i].scale = 0.5 * (simulation.ephemera[i].scale + Math.min(Math.max(0.6, heal * 6), 2.3)) //take average of scale
+ }
+ }
+ if (!foundActiveEffect) {
+ simulation.ephemera.push({
+ name: "healPush",
+ count: totalTime, //cycles before it self removes
+ range: 0,
+ scale: Math.min(Math.max(0.7, heal * 4), 2.2), //typically heal is 0.35
+ do() {
+ this.count--
+ if (this.count < 0) simulation.removeEphemera(this.name)
+ this.range = this.range * 0.99 + 0.01 * (300 * this.scale + 100 * Math.sin(m.cycle * 0.022))
+ if (this.count < 120) this.range -= 5 * this.scale
+ this.range = Math.max(this.range, 1) //don't go negative
+ // const range = 300 + 100 * Math.sin(m.cycle * 0.022)
+ for (let i = 0; i < mob.length; i++) {
+ const distance = Vector.magnitude(Vector.sub(m.pos, mob[i].position))
+ if (distance < this.range) {
+ const cap = mob[i].isShielded ? 3 : 1
+ if (mob[i].speed > cap && Vector.dot(mob[i].velocity, Vector.sub(m.pos, mob[i].position)) > 0) { // if velocity is directed towards player
+ Matter.Body.setVelocity(mob[i], Vector.mult(Vector.normalise(mob[i].velocity), cap)); //set velocity to cap, but keep the direction
+ }
+ }
+ }
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, this.range, 0, 2 * Math.PI);
+ ctx.fillStyle = "hsla(200,50%,61%,0.18)";
+ ctx.fill();
+ },
+ })
+ }
+ }
+ }
+ }
+ if (powerUps.healGiveMaxEnergy) {
+ tech.healMaxEnergyBonus += 0.08 * tech.largerHeals * (tech.isHalfHeals ? 0.5 : 1)
+ m.setMaxEnergy();
+ }
+ },
+ spawn(x, y, size) { //used to spawn a heal with a specific size / heal amount, not normally used
+ powerUps.directSpawn(x, y, "heal", false, null, size)
+ if (Math.random() < tech.duplicationChance()) {
+ powerUps.directSpawn(x, y, "heal", false, null, size)
+ powerUp[powerUp.length - 1].isDuplicated = true
+ }
+ }
+ },
+ ammo: {
+ name: "ammo",
+ color: "#467",
+ size() {
+ return 17;
+ },
+ effect() {
+ if (b.inventory.length > 0) {
+ if (tech.isAmmoForGun && b.activeGun !== null) { //give extra ammo to one gun only with tech logistics
+ const target = b.guns[b.activeGun]
+ if (target.ammo !== Infinity) {
+ if (tech.ammoCap) {
+ const ammoAdded = Math.ceil(target.ammoPack * 0.7 * tech.ammoCap * 0.8) //0.7 is average
+ target.ammo = ammoAdded
+ // simulation.makeTextLog(`${target.name}.ammo = ${ammoAdded}`)
+ } else {
+ const ammoAdded = Math.ceil((0.7 * Math.random() + 0.7 * Math.random()) * target.ammoPack * 0.8)
+ target.ammo += ammoAdded
+ // simulation.makeTextLog(`${target.name}.ammo += ${ammoAdded}`)
+ }
+ }
+ } else { //give ammo to all guns in inventory
+ // let textLog = ""
+ for (let i = 0, len = b.inventory.length; i < len; i++) {
+ const target = b.guns[b.inventory[i]]
+ if (target.ammo !== Infinity) {
+ if (tech.ammoCap) {
+ const ammoAdded = Math.ceil(target.ammoPack * 0.45 * tech.ammoCap) //0.45 is average
+ target.ammo = ammoAdded
+ // textLog += `${target.name}.ammo = ${ammoAdded} `
+ } else {
+ const ammoAdded = Math.ceil((0.45 * Math.random() + 0.45 * Math.random()) * target.ammoPack) //Math.ceil(Math.random() * target.ammoPack)
+ target.ammo += ammoAdded
+ // textLog += `${target.name}.ammo += ${ammoAdded} `
+ }
+ }
+ }
+ // simulation.makeTextLog(textLog)
+ }
+ // } else { //give ammo to all guns in inventory
+ // for (let i = 0, len = b.inventory.length; i < len; i++) {
+ // const target = b.guns[b.inventory[i]]
+ // if (target.ammo !== Infinity) {
+ // if (tech.ammoCap) {
+ // const ammoAdded = Math.ceil(target.ammoPack * 0.45 * tech.ammoCap) //0.45 is average
+ // target.ammo = ammoAdded
+ // simulation.makeTextLog(`${target.name}.ammo = ${ammoAdded}`)
+ // } else {
+ // const ammoAdded = Math.ceil((0.45 * Math.random() + 0.45 * Math.random()) * target.ammoPack) //Math.ceil(Math.random() * target.ammoPack)
+ // target.ammo += ammoAdded
+ // simulation.makeTextLog(`${target.name}.ammo += ${ammoAdded}`)
+ // }
+ // }
+ // }
+ // }
+ simulation.updateGunHUD();
+ }
+ }
+ },
+ cancelText(type) {
+ // if (localSettings.isHideImages) { }
+
+ if (tech.isSuperDeterminism) {
+ return `
`
+ } else if (tech.isCancelTech) {
+ return `randomize
`
+ } else {
+ return `cancel
`
+ }
+ },
+ researchText(type) {
+ let text = ""
+ if (type === "entanglement") {
+ text += `entanglement
`
+ } else if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) {
+ text += `` // style = "margin-left: 192px; margin-right: -192px;"
+ tech.junkResearchNumber = Math.ceil(4 * Math.random())
+ text += `
`
+ for (let i = 0; i < tech.junkResearchNumber; i++) {
+ text += `
`
+ }
+ text += ` pseudoscience `
+ } else if (powerUps.research.count > 0) {
+ text += `` // style = "margin-left: 192px; margin-right: -192px;"
+ text += `
`
+ for (let i = 0, len = Math.min(powerUps.research.count, 30); i < len; i++) text += `
`
+ text += ` ${tech.isResearchReality ? "alternate reality " : "research"} `
+ } else {
+ text += `
`
+ }
+ return text
+ },
+ researchAndCancelText(type) {
+ let text = ``
+ if (type === "entanglement") {
+ text += `
entanglement ` //
+ } else if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) {
+ text += `
` // style = "margin-left: 192px; margin-right: -192px;"
+ tech.junkResearchNumber = Math.ceil(4 * Math.random())
+ text += ``
+ for (let i = 0, len = tech.junkResearchNumber; i < len; i++) {
+ text += `
`
+ }
+ text += ` ${tech.isResearchReality ? "alternate reality " : "research"} `
+ } else if (powerUps.research.count > 0) {
+ text += `
` // style = "margin-left: 192px; margin-right: -192px;"
+ text += ``
+ let researchCap = 18
+ if (tech.isCancelTech) researchCap -= 2
+ if (canvas.width < 1951) researchCap -= 3
+ if (canvas.width < 1711) researchCap -= 4
+ for (let i = 0, len = Math.min(powerUps.research.count, researchCap); i < len; i++) {
+ text += `
`
+ }
+ text += ` ${tech.isResearchReality ? "alternate reality " : "research"} `
+ } else {
+ text += `
research ` //
+ }
+ if (tech.isSuperDeterminism) {
+ text += `
cancel `
+ } else if (tech.isCancelTech) {
+ text += `
randomize `
+ } else {
+ text += `
cancel `
+ }
+
+ return text + "
"
+ },
+ buildColumns(totalChoices, type) {
+ let width
+ if (canvas.width < 1710) {
+ width = "285px"
+ } else if (canvas.width < 1950) {
+ width = "340px"
+ } else {
+ width = "384px"
+ }
+
+ let text = ""
+ if (localSettings.isHideImages) {
+ document.getElementById("choose-grid").style.gridTemplateColumns = width
+ text += powerUps.researchAndCancelText(type)
+ } else if (totalChoices === 1 || canvas.width < 1200) {
+ document.getElementById("choose-grid").style.gridTemplateColumns = width
+ text += powerUps.researchAndCancelText(type)
+ // console.log('hi')
+ // text += powerUps.cancelText(type)
+ // text += powerUps.researchText(type)
+ } else if (totalChoices === 2) {
+ document.getElementById("choose-grid").style.gridTemplateColumns = `repeat(2, ${width})`
+ text += powerUps.researchText(type)
+ text += powerUps.cancelText(type)
+ } else {
+ document.getElementById("choose-grid").style.gridTemplateColumns = `repeat(3, ${width})`
+ text += "
"
+ text += powerUps.researchText(type)
+ text += powerUps.cancelText(type)
+ }
+ return text
+ },
+ // researchAndCancelText(type) {
+ // let text = ""
+ // if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) {
+ // text += `
` // style = "margin-left: 192px; margin-right: -192px;"
+ // tech.junkResearchNumber = Math.ceil(4 * Math.random())
+ // text += `
`
+ // for (let i = 0; i < tech.junkResearchNumber; i++) text += `
`
+ // text += ` pseudoscience `
+ // } else if (powerUps.research.count > 0) {
+ // text += `
` // style = "margin-left: 192px; margin-right: -192px;"
+ // text += `
`
+ // for (let i = 0, len = Math.min(powerUps.research.count, 30); i < len; i++) text += `
`
+ // text += ` ${tech.isResearchReality?"alternate reality ": "research"} `
+ // } else {
+ // text += `
`
+ // }
+ // return text + '
'
+ // },
+ hideStyle: `style="height:auto; border: none; background-color: transparent;"`,
+ gunText(choose, click) {
+ const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/gun/${b.guns[choose].name}.webp');"`
+ return `
+
+
+ ${b.guns[choose].description}
`
+ },
+ fieldText(choose, click) {
+ const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/field/${m.fieldUpgrades[choose].name}${choose === 0 ? Math.floor(Math.random() * 10) : ""}.webp');"`
+ return `
+
+
${m.fieldUpgrades[choose].name}
+ ${m.fieldUpgrades[choose].description}
`
+ },
+ techText(choose, click) {
+ const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
+ const style = localSettings.isHideImages || tech.tech[choose].isLore ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
+ return `
+
+
${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ },
+ skinTechText(choose, click) {
+ const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
+ const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
+ return `
+
+
+
+
+
+
+ ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ },
+ fieldTechText(choose, click) {
+ const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
+ const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
+ return `
+
+
+
+
+
+
+ ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ },
+ gunTechText(choose, click) {
+ const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
+ const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
+ return `
+
+
+
+
+
+
+ ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ },
+ junkTechText(choose, click) {
+ const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
+ const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-size: contain;background-repeat: no-repeat;background-image: url('img/junk.webp');"`
+ if (!localSettings.isHideImages) {
+ setTimeout(() => { //delay so that the html element exists
+ if (tech.tech[choose].url === undefined) { //if on url has been set yet
+ const url = "https://images.search.yahoo.com/search/images?p=" + tech.tech[choose].name;
+ fetch(url, { signal: AbortSignal.timeout(1000) }) //give up if it takes over 1 second
+ .then((response) => response.text())
+ .then((html) => {
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(html, "text/html");
+ const elements = doc.getElementsByClassName("ld");
+ // console.log(i, elements[i].getAttribute("data"), JSON.parse(elements[i].getAttribute("data")).iurl)
+ const index = Math.floor(Math.random() * 4) //randomly choose from the first 4 images
+ if (parseInt(JSON.parse(elements[index].getAttribute("data")).s.slice(0, -2)) < 500) { //make sure it isn't too big
+ tech.tech[choose].url = JSON.parse(elements[index].getAttribute("data")).iurl //store the url
+ document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')` //make the url the background image
+ } else if (parseInt(JSON.parse(elements[index + 1].getAttribute("data")).s.slice(0, -2)) < 500) { //try a different images and see if it is smaller
+ tech.tech[choose].url = JSON.parse(elements[index + 1].getAttribute("data")).iurl
+ document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')`
+ } else if (parseInt(JSON.parse(elements[index + 2].getAttribute("data")).s.slice(0, -2)) < 500) { //try a different images and see if it is smaller
+ tech.tech[choose].url = JSON.parse(elements[index + 2].getAttribute("data")).iurl
+ document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')`
+ }
+ });
+ } else {
+ document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')`
+ }
+ }, 1);
+ }
+ return `
+
+
${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ },
+ incoherentTechText(choose, click) {
+ // text += `${tech.tech[choose].name} - incoherent
`
+ const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
+ return ``
+ },
+ gun: {
+ name: "gun",
+ color: "#26a",
+ size() {
+ return 35;
+ },
+ effect() {
+ if (m.alive) {
+ let options = [];
+ for (let i = 0; i < b.guns.length; i++) {
+ if (!b.guns[i].have) options.push(i);
+ }
+ let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2 + tech.extraChoices + 2 * (m.fieldMode === 8)))
+ if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
+ function removeOption(index) {
+ for (let i = 0; i < options.length; i++) {
+ if (options[i] === index) {
+ options.splice(i, 1) //remove a previous choice from option pool
+ return
+ }
+ }
+ }
+ //check for guns that were a choice last time and remove them
+ for (let i = 0; i < b.guns.length; i++) {
+ if (options.length - 1 < totalChoices) break //you have to repeat choices if there are not enough choices left to display
+ if (b.guns[i].isRecentlyShown) removeOption(i)
+ }
+ for (let i = 0; i < b.guns.length; i++) b.guns[i].isRecentlyShown = false //reset recently shown back to zero
+ if (options.length > 0) {
+ let text = powerUps.buildColumns(totalChoices, "gun")
+ for (let i = 0; i < totalChoices; i++) {
+ const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
+ // text += ` ${b.guns[choose].description}
`
+ text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`)
+
+ b.guns[choose].isRecentlyShown = true
+ removeOption(choose)
+ if (options.length < 1) break
+ }
+ if (tech.isExtraBotOption) {
+ const botTech = [] //make an array of bot options
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i)
+ }
+ if (botTech.length > 0) { //pick random bot tech
+ // const choose = botTech[Math.floor(Math.random() * botTech.length)];
+ // const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : "";
+ // text += ` ⭓▸●■ ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ const choose = botTech[Math.floor(Math.random() * botTech.length)];
+ const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
+ const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
+ text += `
+
+
⭓▸●■ ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ }
+ }
+ if (tech.isOneGun && b.inventory.length > 0) text += `replaces your current gun
`
+ document.getElementById("choose-grid").innerHTML = text
+ powerUps.showDraft();
+ }
+ }
+ },
+ },
+ field: {
+ name: "field",
+ color: "#0cf",
+ size() {
+ return 45;
+ },
+ effect() {
+ if (m.alive) {
+ let options = [];
+ for (let i = 1; i < m.fieldUpgrades.length; i++) { //skip field emitter
+ if (i !== m.fieldMode) options.push(i);
+ }
+ let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2 + tech.extraChoices + 2 * (m.fieldMode === 8)))
+ if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
+
+ function removeOption(index) {
+ for (let i = 0; i < options.length; i++) {
+ if (options[i] === index) {
+ options.splice(i, 1) //remove a previous choice from option pool
+ return
+ }
+ }
+ }
+ //check for fields that were a choice last time and remove them
+ for (let i = 0; i < m.fieldUpgrades.length; i++) {
+ if (options.length - 1 < totalChoices) break //you have to repeat choices if there are not enough choices left to display
+ if (m.fieldUpgrades[i].isRecentlyShown) removeOption(i)
+ }
+ for (let i = 0; i < m.fieldUpgrades.length; i++) m.fieldUpgrades[i].isRecentlyShown = false //reset recently shown back to zero
+
+ if (options.length > 0 || tech.isExtraBotOption) {
+ let text = powerUps.buildColumns(totalChoices, "field")
+ for (let i = 0; i < totalChoices; i++) {
+ const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
+ //text += `
${m.fieldUpgrades[choose].name}
${m.fieldUpgrades[choose].description}
` //default
+ text += powerUps.fieldText(choose, `powerUps.choose('field',${choose})`)
+ m.fieldUpgrades[choose].isRecentlyShown = true
+ removeOption(choose)
+ if (options.length < 1) break
+ }
+ if (tech.isExtraBotOption) {
+ const botTech = [] //make an array of bot options
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i)
+ }
+ if (botTech.length > 0) { //pick random bot tech
+ // const choose = botTech[Math.floor(Math.random() * botTech.length)];
+ // const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : "";
+ // text += ` ⭓▸●■ ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ const choose = botTech[Math.floor(Math.random() * botTech.length)];
+ const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
+ const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
+ text += `
+
+
⭓▸●■ ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ }
+ }
+ document.getElementById("choose-grid").innerHTML = text
+ powerUps.showDraft();
+ }
+ }
+ },
+ },
+ tech: {
+ name: "tech",
+ color: "hsl(246,100%,77%)", //"#a8f",
+ size() {
+ return 42;
+ },
+ effect() {
+ if (m.alive) {
+ let junkCount = 0 //used for junk estimation
+ let totalCount = 0 //used for junk estimation
+ let options = []; //generate all options
+ optionLengthNoDuplicates = 0
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isBanished) {
+ totalCount += tech.tech[i].frequency
+ if (tech.tech[i].isJunk) junkCount += tech.tech[i].frequency
+ if (tech.tech[i].frequency > 0) optionLengthNoDuplicates++
+ for (let j = 0, len = tech.tech[i].frequency; j < len; j++) options.push(i);
+ }
+ }
+ function removeOption(index) {
+ for (let i = options.length - 1; i > -1; i--) {
+ if (index === options[i]) {
+ options.splice(i, 1) //remove all copies of that option form the options array (some tech are in the options array multiple times because of frequency)
+ optionLengthNoDuplicates--
+ }
+ if (options.length < 1) return;
+ }
+ }
+ //set total choices
+ let totalChoices = (tech.isDeterminism ? 1 : 3 + tech.extraChoices + 2 * (m.fieldMode === 8))
+ if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
+ if (optionLengthNoDuplicates < totalChoices + 1) { //if not enough options for all the choices
+ totalChoices = optionLengthNoDuplicates
+ if (tech.isBanish) { //when you run out of options eject banish
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].name === "decoherence") powerUps.ejectTech(i, true)
+ }
+ simulation.makeTextLog(`decoherence tech ejected`)
+ simulation.makeTextLog(`options reset`)
+ }
+ }
+ if (tech.tooManyTechChoices) {
+ tech.tooManyTechChoices = false
+ totalChoices = optionLengthNoDuplicates
+ }
+ if (optionLengthNoDuplicates > totalChoices) { //check for tech that were a choice last time and remove them
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (optionLengthNoDuplicates > totalChoices) {
+ if (tech.tech[i].isRecentlyShown) removeOption(i)
+ } else {
+ break //you have to repeat choices if there are not enough choices left to display
+ }
+
+ }
+ }
+ for (let i = 0; i < tech.tech.length; i++) tech.tech[i].isRecentlyShown = false //reset recently shown back to zero
+ if (options.length > 0) {
+ let text = powerUps.buildColumns(totalChoices, "tech")
+ for (let i = 0; i < totalChoices; i++) {
+ if (options.length < 1) break
+ const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
+ if (tech.isBanish) {
+ tech.tech[choose].isBanished = true
+ if (i === 0) simulation.makeTextLog(`options.length = ${optionLengthNoDuplicates}`)
+ }
+ removeOption(choose) //move from future options pool to avoid repeats on this selection
+ tech.tech[choose].isRecentlyShown = true //this flag prevents this option from being shown the next time you pick up a tech power up
+ const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
+ if (tech.tech[choose].isFieldTech) {
+ text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`)
+ } else if (tech.tech[choose].isGunTech) {
+ text += powerUps.gunTechText(choose, `powerUps.choose('tech',${choose})`)
+ } else if (tech.tech[choose].isJunk) {
+ text += powerUps.junkTechText(choose, `powerUps.choose('tech',${choose})`)
+ } else if (tech.tech[choose].isSkin) {
+ text += powerUps.skinTechText(choose, `powerUps.choose('tech',${choose})`)
+ } else { //normal tech
+ text += powerUps.techText(choose, `powerUps.choose('tech',${choose})`)
+ }
+ if (options.length < 1) break
+ }
+ if (tech.isExtraBotOption) {
+ const botTech = [] //make an array of bot options
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isRecentlyShown) botTech.push(i)
+ }
+ if (botTech.length > 0) { //pick random bot tech
+ // const choose = botTech[Math.floor(Math.random() * botTech.length)];
+ // const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : "";
+ // text += ` ⭓▸●■ ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ const choose = botTech[Math.floor(Math.random() * botTech.length)];
+ const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
+ const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
+ text += `
+
+
⭓▸●■ ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ }
+ }
+ if (tech.isMassProduction) {
+ // const techOptions = [] //make an array of bot options
+ // for (let i = 0, len = tech.tech.length; i < len; i++) {
+ // if (tech.tech[i].isMassProduction) techOptions.push(i)
+ // }
+ // if (techOptions.length > 0) { //pick random bot tech
+ // const choose = techOptions[Math.floor(Math.random() * techOptions.length)];
+ // const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
+ // text += `
+ //
+ //
${tech.tech[choose].name}
+ // ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ // }
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isMassProduction) {
+ const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[i].name}.webp');"`
+ text += `
+
+
${tech.tech[i].name}
+ ${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() : tech.tech[i].description}
`
+ }
+ }
+ }
+ if (tech.isExtraGunField) {
+ if (Math.random() > 0.5 && b.inventory.length < b.guns.length) {
+ let gunOptions = [];
+ for (let i = 0; i < b.guns.length; i++) {
+ if (!b.guns[i].have) gunOptions.push(i);
+ }
+ const pick = gunOptions[Math.floor(Math.seededRandom(0, gunOptions.length))] //pick an element from the array of options
+ // text += ` ${b.guns[pick].description}
`
+ text += powerUps.gunText(pick, `powerUps.choose('gun',${pick})`)
+ } else {
+ let fieldOptions = [];
+ for (let i = 1; i < m.fieldUpgrades.length; i++) { //skip field emitter
+ if (i !== m.fieldMode) fieldOptions.push(i);
+ }
+ const pick = fieldOptions[Math.floor(Math.seededRandom(0, fieldOptions.length))] //pick an element from the array of options
+ // text += `
${m.fieldUpgrades[pick].name}
${m.fieldUpgrades[pick].description}
`
+ text += powerUps.fieldText(pick, `powerUps.choose('field',${pick})`)
+ }
+ }
+ // if (tech.isMicroTransactions && powerUps.research.count > 0) {
+ // const skins = [] //find skins
+ // for (let i = 0; i < tech.tech.length; i++) {
+ // if (tech.tech[i].isSkin) skins.push(i)
+ // }
+ // const choose = skins[Math.floor(Math.seededRandom(0, skins.length))] //pick an element from the array of options
+
+ // text += `
microtransaction: ${tech.tech[choose].name}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ // }
+ if (tech.isBrainstorm && !tech.isBrainstormActive && !simulation.isChoosing) {
+ tech.isBrainstormActive = true
+
+ let count = 1
+ let timeStart = performance.now()
+ const cycle = (timestamp) => {
+ // if (timeStart === undefined) timeStart = timestamp
+ // console.log(timestamp, timeStart)
+ if (timestamp - timeStart > tech.brainStormDelay * count && simulation.isChoosing) {
+ count++
+ powerUps.tech.effect();
+ document.getElementById("choose-grid").style.pointerEvents = "auto"; //turn off the normal 500ms delay
+ document.body.style.cursor = "auto";
+ document.getElementById("choose-grid").style.transitionDuration = "0s";
+ }
+ if (count < 5 && simulation.isChoosing) {
+ requestAnimationFrame(cycle);
+ } else {
+ tech.isBrainstormActive = false
+ }
+ }
+ requestAnimationFrame(cycle);
+
+ // count++
+ // if (count < tech.brainStormDelay * 5 && simulation.isChoosing) {
+ // if (!(count % tech.brainStormDelay)) {
+ // powerUps.tech.effect();
+ // document.getElementById("choose-grid").style.pointerEvents = "auto"; //turn off the normal 500ms delay
+ // document.body.style.cursor = "auto";
+ // document.getElementById("choose-grid").style.transitionDuration = "0s";
+ // }
+ // requestAnimationFrame(cycle);
+ // } else {
+ // tech.isBrainstormActive = false
+ // }
+ }
+ // if (localSettings.isHideImages) text += powerUps.researchText('tech')
+ document.getElementById("choose-grid").innerHTML = text
+ powerUps.showDraft();
+
+ //fade in all circles
+ // requestAnimationFrame(() => {
+ // var elements = document.getElementsByClassName('circle-grid');
+ // for (var i in elements) {
+ // if (elements.hasOwnProperty(i)) {
+ // elements[i].style.opacity = '1';
+ // }
+ // }
+ // });
+ }
+ }
+ },
+ },
+ entanglement: {
+ name: "entanglement",
+ color: "#fff", //"hsl(248,100%,65%)",
+ size() {
+ return 40
+ },
+ effect() {
+ if (m.alive && localSettings.entanglement) {
+ // let text = ""
+ // document.getElementById("choose-grid").style.gridTemplateColumns = "384px 384px 384px"
+ let text = powerUps.buildColumns(3, "entanglement")
+
+ // text += powerUps.researchText('tech')
+ // text += "
"
+ // text += "entanglement
"
+ // text += `cancel
` //powerUps.cancelText('tech')
+ if (localSettings.entanglement.fieldIndex && localSettings.entanglement.fieldIndex !== m.fieldMode) {
+ const choose = localSettings.entanglement.fieldIndex //add field
+ text += powerUps.fieldText(choose, `powerUps.choose('field',${choose})`)
+ }
+ for (let i = 0; i < localSettings.entanglement.gunIndexes.length; i++) { //add guns
+ const choose = localSettings.entanglement.gunIndexes[i]
+ //check if you always have this gun
+ let alreadyHasGun = false
+ for (let j = 0; j < b.inventory.length; j++) {
+ if (b.inventory[j] === choose) alreadyHasGun = true
+ }
+ // text += ` ${b.guns[gun].description}
`
+ if (!alreadyHasGun) text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`)
+ }
+ for (let i = 0; i < localSettings.entanglement.techIndexes.length; i++) { //add tech
+ let choose = localSettings.entanglement.techIndexes[i]
+ const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
+
+ if (choose === null || tech.tech[choose].count + 1 > tech.tech[choose].maxCount || !tech.tech[choose].allowed()) {
+ // text += `${tech.tech[choose].name} - incoherent
`
+ text += powerUps.incoherentTechText(choose)
+ } else {
+ if (tech.tech[choose].isFieldTech) {
+ text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`)
+ } else if (tech.tech[choose].isGunTech) {
+ text += powerUps.gunTechText(choose, `powerUps.choose('tech',${choose})`)
+ } else if (tech.tech[choose].isLore) {
+ text += `
${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
`
+ } else if (tech.tech[choose].isJunk) {
+ text += powerUps.junkTechText(choose, `powerUps.choose('tech',${choose})`)
+ } else if (tech.tech[choose].isSkin) {
+ text += powerUps.skinTechText(choose, `powerUps.choose('tech',${choose})`)
+ } else { //normal tech
+ text += powerUps.techText(choose, `powerUps.choose('tech',${choose})`)
+ }
+ }
+ }
+ // document.getElementById("choose-grid").classList.add("flipX");
+ document.getElementById("choose-grid").innerHTML = text
+ powerUps.showDraft();
+ localSettings.entanglement = undefined
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ }
+ },
+ },
+ spawnDelay(type, num) {
+ let count = num
+ let cycle = () => {
+ if (count > 0) {
+ if (m.alive) requestAnimationFrame(cycle);
+ if (!simulation.paused && !simulation.isChoosing) { //&& !(simulation.cycle % 2)
+ count--
+ const where = {
+ x: m.pos.x + 50 * (Math.random() - 0.5),
+ y: m.pos.y + 50 * (Math.random() - 0.5)
+ }
+ powerUps.spawn(where.x, where.y, type);
+ }
+ }
+ }
+ requestAnimationFrame(cycle);
+ },
+ onPickUp(who) {
+ powerUps.research.currentRerollCount = 0
+ if (tech.isTechDamage && who.name === "tech") m.damage(0.1)
+ if (tech.isMassEnergy) m.energy += 2;
+ if (tech.isMineDrop && bullet.length < 150 && Math.random() < 0.5) {
+ if (tech.isLaserMine && input.down) {
+ b.laserMine(who.position)
+ } else {
+ b.mine(who.position, { x: 0, y: 0 }, 0)
+ }
+ }
+ if (tech.isRelay) {
+ if (tech.isFlipFlopOn) {
+ tech.isFlipFlopOn = false
+ if (document.getElementById("tech-switch")) document.getElementById("tech-switch").innerHTML = ` = OFF `
+ m.eyeFillColor = 'transparent'
+ } else {
+ tech.isFlipFlopOn = true //immune to damage this hit, lose immunity for next hit
+ if (document.getElementById("tech-switch")) document.getElementById("tech-switch").innerHTML = ` = ON `
+ m.eyeFillColor = m.fieldMeterColor //'#0cf'
+ }
+ if (tech.isRelayEnergy) m.setMaxEnergy();
+ }
+ },
+ spawnRandomPowerUp(x, y) { //mostly used after mob dies, doesn't always return a power up
+ if (!tech.isEnergyHealth && (Math.random() * Math.random() - 0.3 > Math.sqrt(m.health)) || Math.random() < 0.04) { //spawn heal chance is higher at low health
+ powerUps.spawn(x, y, "heal");
+ return;
+ }
+ if (Math.random() < 0.15 && b.inventory.length > 0) {
+ powerUps.spawn(x, y, "ammo");
+ return;
+ }
+ if (Math.random() < 0.0007 * (3 - b.inventory.length)) { //a new gun has a low chance for each not acquired gun up to 3
+ powerUps.spawn(x, y, "gun");
+ return;
+ }
+ // if (Math.random() < 0.0027 * (22 - tech.totalCount)) { //a new tech has a low chance for each not acquired tech up to 25
+ if (Math.random() < 0.005 * (10 - level.levelsCleared)) { //a new tech has a low chance that decreases in later levels
+ powerUps.spawn(x, y, "tech");
+ return;
+ }
+ if (Math.random() < 0.0015) {
+ powerUps.spawn(x, y, "field");
+ return;
+ }
+ if (tech.isCouplingPowerUps && Math.random() < 0.17) {
+ powerUps.spawn(x, y, "coupling");
+ return;
+ }
+ if (tech.isBoostPowerUps && Math.random() < 0.14) {
+ powerUps.spawn(x, y, "boost");
+ return;
+ }
+ // if (Math.random() < 0.01) {
+ // powerUps.spawn(x, y, "research");
+ // return;
+ // }
+ },
+ randomPowerUpCounter: 0,
+ isFieldSpawned: false, //makes it so a field spawns once but not more times
+ spawnBossPowerUp(x, y) { //boss spawns field and gun tech upgrades
+ if (level.levels[level.onLevel] !== "final") {
+ // if (level.levelsCleared === 1) powerUps.spawn(x, y, "field")
+ // if (m.fieldMode === 0 && !m.coupling) {
+ if (!powerUps.isFieldSpawned) {
+ powerUps.isFieldSpawned = true
+ powerUps.spawn(x, y, "field")
+ } else {
+ powerUps.randomPowerUpCounter++;
+ powerUpChance(Math.max(level.levelsCleared, 10) * 0.1)
+ }
+ if (!(simulation.difficulty > spawn.secondaryBossThreshold)) {
+ powerUps.randomPowerUpCounter += 0.6;
+ powerUpChance(Math.max(level.levelsCleared, 6) * 0.1)
+ }
+
+ function powerUpChance(chanceToFail) {
+ if (Math.random() * chanceToFail < powerUps.randomPowerUpCounter) {
+ powerUps.randomPowerUpCounter = 0;
+ if (Math.random() < 0.97) {
+ powerUps.spawn(x, y, "tech")
+ } else {
+ powerUps.spawn(x, y, "gun")
+ }
+ } else {
+ if (m.health < 0.65 && !tech.isEnergyHealth) {
+ powerUps.spawn(x, y, "heal");
+ powerUps.spawn(x, y, "heal");
+ } else {
+ powerUps.spawn(x, y, "ammo");
+ powerUps.spawn(x, y, "ammo");
+ }
+ }
+ }
+ }
+ },
+ chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris
+ if (Math.random() < 0.5) {
+ powerUps.spawn(x, y, "heal", false);
+ } else {
+ powerUps.spawn(x, y, "ammo", false);
+ }
+ },
+ addResearchToLevel() { //add a random power up to a location that has a mob, mostly used to give each level one randomly placed research
+ if (mob.length && Math.random() < 0.45 - 0.3 * (simulation.difficultyMode > 5)) { //lower chance on why difficulty
+ const index = Math.floor(Math.random() * mob.length)
+ powerUps.spawn(mob[index].position.x, mob[index].position.y, "research");
+ }
+ },
+ spawnStartingPowerUps(x, y) { //used for map specific power ups, mostly to give player a starting gun
+ if (level.levelsCleared < 4) { //runs on first 4 levels on all difficulties
+ if (level.levelsCleared > 1) powerUps.spawn(x, y, "tech")
+ if (b.inventory.length === 0) {
+ powerUps.spawn(x, y, "gun", false); //first gun
+ } else if (tech.totalCount === 0) { //first tech
+ powerUps.spawn(x, y, "tech", false);
+ } else if (b.inventory.length === 1) { //second gun or extra ammo
+ if (Math.random() < 0.4) {
+ powerUps.spawn(x, y, "gun", false);
+ } else {
+ for (let i = 0; i < 5; i++) powerUps.spawn(x, y, "ammo", false);
+ }
+ } else {
+ for (let i = 0; i < 4; i++) powerUps.spawnRandomPowerUp(x, y);
+ }
+ } else { //after the first 4 levels just spawn a random power up
+ for (let i = 0; i < 3; i++) powerUps.spawnRandomPowerUp(x, y);
+ }
+ },
+ ejectTech(choose = 'random', isOverride = false) {
+ if (!simulation.isChoosing || isOverride) {
+ // console.log(tech.tech[choose].name, tech.tech[choose].count, tech.tech[choose].isNonRefundable)
+ //find which tech you have
+ if (choose === 'random') {
+ const have = []
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].count > 0 && !tech.tech[i].isNonRefundable) have.push(i)
+ }
+ // if (have.length === 0) {
+ // for (let i = 0; i < tech.tech.length; i++) {
+ // if (tech.tech[i].count > 0) have.push(i)
+ // }
+ // }
+
+ if (have.length) {
+ choose = have[Math.floor(Math.random() * have.length)]
+ simulation.makeTextLog(`tech .remove("${tech.tech[choose].name} ")`)
+
+ for (let i = 0; i < tech.tech[choose].count; i++) {
+ powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
+ // powerUp[powerUp.length - 1].isDuplicated = true
+ }
+ // remove a random tech from the list of tech you have
+ tech.tech[choose].remove();
+ tech.tech[choose].count = 0;
+ tech.tech[choose].isLost = true;
+ simulation.updateTechHUD();
+ m.fieldCDcycle = m.cycle + 30; //disable field so you can't pick up the ejected tech
+ return true
+ } else {
+ return false
+ }
+ } else if (tech.tech[choose].count && !tech.tech[choose].isNonRefundable) {
+ simulation.makeTextLog(`tech .remove("${tech.tech[choose].name} ")`)
+
+ for (let i = 0; i < tech.tech[choose].count; i++) {
+ powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
+ powerUp[powerUp.length - 1].isDuplicated = true
+ }
+ // remove a random tech from the list of tech you have
+ tech.tech[choose].remove();
+ tech.tech[choose].count = 0;
+ tech.tech[choose].isLost = true;
+ simulation.updateTechHUD();
+ m.fieldCDcycle = m.cycle + 30; //disable field so you can't pick up the ejected tech
+ return true
+ } else {
+ return false
+ }
+ }
+ },
+ pauseEjectTech(index) {
+ if ((tech.isPauseEjectTech || simulation.testing) && !simulation.isChoosing && !tech.tech[index].isNonRefundable) {
+ if (Math.random() < 0.2 || tech.tech[index].isFromAppliedScience || (tech.tech[index].bonusResearch !== undefined && tech.tech[index].bonusResearch > powerUps.research.count)) {
+ tech.removeTech(index)
+ // powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
+ } else {
+ powerUps.ejectTech(index)
+ }
+ document.getElementById(`${index}-pause-tech`).style.textDecoration = "line-through"
+ document.getElementById(`${index}-pause-tech`).style.animation = ""
+ document.getElementById(`${index}-pause-tech`).onclick = null
+ }
+ },
+ // removeRandomTech() {
+ // const have = [] //find which tech you have
+ // for (let i = 0; i < tech.tech.length; i++) {
+ // if (tech.tech[i].count > 0) have.push(i)
+ // }
+ // if (have.length) {
+ // const choose = have[Math.floor(Math.random() * have.length)]
+ // simulation.makeTextLog(`tech .removeTech("${tech.tech[choose].name} ")`)
+ // const totalRemoved = tech.tech[choose].count
+ // tech.tech[choose].count = 0;
+ // tech.tech[choose].remove(); // remove a random tech form the list of tech you have
+ // tech.tech[choose].isLost = true
+ // simulation.updateTechHUD();
+ // return totalRemoved
+ // }
+ // return 0
+ // },
+ randomize(where) { //makes a random power up convert into a random different power up
+ //put 10 power ups close together
+ const len = Math.min(10, powerUp.length)
+ for (let i = 0; i < len; i++) { //collide the first 10 power ups
+ const unit = Vector.rotate({ x: 1, y: 0 }, 6.28 * Math.random())
+ Matter.Body.setPosition(powerUp[i], Vector.add(where, Vector.mult(unit, 20 + 25 * Math.random())));
+ Matter.Body.setVelocity(powerUp[i], Vector.mult(unit, 20));
+ }
+
+ //count big power ups and small power ups
+ let options = ["heal", "research", "ammo"]
+ if (m.coupling) options.push("coupling")
+ if (tech.isBoostPowerUps) options.push("boost")
+ let bigIndexes = []
+ let smallIndexes = []
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "tech" || powerUp[i].name === "gun" || powerUp[i].name === "field") {
+ bigIndexes.push(i)
+ } else {
+ smallIndexes.push(i)
+ }
+ }
+ if (bigIndexes.length > 0) {
+ // console.log("at least 1 big will always spilt")
+ const index = bigIndexes[Math.floor(Math.random() * bigIndexes.length)]
+ for (let i = 0; i < 3; i++) powerUps.directSpawn(where.x, where.y, options[Math.floor(Math.random() * options.length)], false)
+
+ Matter.Composite.remove(engine.world, powerUp[index]);
+ powerUp.splice(index, 1);
+ } else if (smallIndexes.length > 2 && Math.random() < 0.33) {
+ // console.log("no big, at least 3 small can combine")
+ for (let j = 0; j < 3; j++) {
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal" || powerUp[i].name === "research" || powerUp[i].name === "ammo" || powerUp[i].name === "coupling" || powerUp[i].name === "boost") {
+ Matter.Composite.remove(engine.world, powerUp[i]);
+ powerUp.splice(i, 1);
+ break
+ }
+ }
+ }
+
+ options = ["tech", "gun", "field"]
+ powerUps.directSpawn(where.x, where.y, options[Math.floor(Math.random() * options.length)], false)
+ } else if (smallIndexes.length > 0) {
+ // console.log("no big, at least 1 small will swap flavors")
+ const index = Math.floor(Math.random() * powerUp.length)
+ options = options.filter(e => e !== powerUp[index].name); //don't repeat the current power up type
+ powerUps.directSpawn(where.x, where.y, options[Math.floor(Math.random() * options.length)], false)
+ Matter.Composite.remove(engine.world, powerUp[index]);
+ powerUp.splice(index, 1);
+ }
+ },
+ directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size(), isDuplicated = false) {
+ let index = powerUp.length;
+ let properties = {
+ density: 0.001,
+ frictionAir: 0.03,
+ restitution: 0.85,
+ collisionFilter: {
+ group: 0,
+ category: cat.powerUp,
+ mask: cat.map | cat.powerUp
+ },
+ color: powerUps[target].color,
+ effect: powerUps[target].effect,
+ name: powerUps[target].name,
+ size: size
+ }
+ let polygonSides
+ if (isDuplicated) {
+ polygonSides = tech.isPowerUpsVanish ? 3 : Math.floor(4 + 2 * Math.random())
+ properties.isDuplicated = true
+ } else {
+ properties.inertia = Infinity //prevents rotation for circles only
+ polygonSides = 0
+ }
+ powerUp[index] = Matter.Bodies.polygon(x, y, polygonSides, size, properties);
+ if (mode) powerUp[index].mode = mode
+ if (moving) Matter.Body.setVelocity(powerUp[index], { x: (Math.random() - 0.5) * 15, y: Math.random() * -9 - 3 });
+ Composite.add(engine.world, powerUp[index]);
+ },
+ spawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) {
+ if (
+ (!tech.isSuperDeterminism || (target !== 'research')) &&
+ !(tech.isEnergyNoAmmo && target === 'ammo')
+ ) {
+ if (tech.isBoostReplaceAmmo && target === 'ammo') target = 'boost'
+ powerUps.directSpawn(x, y, target, moving, mode, size)
+ if (Math.random() < tech.duplicationChance()) {
+ powerUps.directSpawn(x, y, target, moving, mode, size, true)
+ powerUp[powerUp.length - 1].isDuplicated = true
+ // if (tech.isPowerUpsVanish) powerUp[powerUp.length - 1].endCycle = simulation.cycle + 300
+ }
+ }
+ },
+};
\ No newline at end of file
diff --git a/ngon/js/simulation.js b/ngon/js/simulation.js
new file mode 100644
index 00000000..a89422e6
--- /dev/null
+++ b/ngon/js/simulation.js
@@ -0,0 +1,1937 @@
+// game Object ********************************************************
+//*********************************************************************
+const simulation = {
+ loop() { }, //main game loop, gets set to normal or testing loop
+ normalLoop() {
+ simulation.gravity();
+ Engine.update(engine, simulation.delta);
+ simulation.wipe();
+ simulation.textLog();
+ if (m.onGround) {
+ m.groundControl()
+ } else {
+ m.airControl()
+ }
+ m.move();
+ m.look();
+ simulation.camera();
+ level.custom();
+ powerUps.do();
+ mobs.draw();
+ simulation.draw.cons();
+ simulation.draw.body();
+ if (!m.isBodiesAsleep) mobs.loop();
+ mobs.healthBar();
+ m.draw();
+ m.hold();
+ // v.draw(); //working on visibility work in progress
+ level.customTopLayer();
+ simulation.draw.drawMapPath();
+ b.fire();
+ b.bulletRemove();
+ b.bulletDraw();
+ if (!m.isBodiesAsleep) b.bulletDo();
+ simulation.drawCircle();
+ simulation.runEphemera();
+ // simulation.clip();
+ ctx.restore();
+ simulation.drawCursor();
+ // simulation.pixelGraphics();
+ },
+ testingLoop() {
+ simulation.gravity();
+ Engine.update(engine, simulation.delta);
+ simulation.wipe();
+ simulation.textLog();
+ if (m.onGround) {
+ m.groundControl()
+ } else {
+ m.airControl()
+ }
+ m.move();
+ m.look();
+ simulation.camera();
+ level.custom();
+ m.draw();
+ m.hold();
+ level.customTopLayer();
+ simulation.draw.wireFrame();
+ if (input.fire && m.fireCDcycle < m.cycle) {
+ m.fireCDcycle = m.cycle + 15; //fire cooldown
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (Vector.magnitudeSquared(Vector.sub(mob[i].position, simulation.mouseInGame)) < mob[i].radius * mob[i].radius) {
+ console.log(mob[i])
+ }
+ }
+ }
+ simulation.draw.cons();
+ simulation.draw.testing();
+ simulation.drawCircle();
+ simulation.runEphemera();
+ simulation.constructCycle()
+ ctx.restore();
+ simulation.testingOutput();
+ simulation.drawCursor();
+ },
+ isTimeSkipping: false,
+ timeSkip(cycles = 60) {
+ simulation.isTimeSkipping = true;
+ for (let i = 0; i < cycles; i++) {
+ simulation.cycle++;
+ m.cycle++;
+ simulation.gravity();
+ Engine.update(engine, simulation.delta);
+ if (m.onGround) {
+ m.groundControl()
+ } else {
+ m.airControl()
+ }
+ m.move();
+ level.custom();
+ mobs.loop();
+ m.walk_cycle += m.flipLegs * m.Vx;
+ m.hold();
+ level.customTopLayer();
+ b.fire();
+ b.bulletRemove();
+ b.bulletDo();
+ simulation.runEphemera();
+ }
+ simulation.isTimeSkipping = false;
+ },
+ timePlayerSkip(cycles = 60) {
+ simulation.isTimeSkipping = true;
+ for (let i = 0; i < cycles; i++) {
+ simulation.cycle++;
+ // m.walk_cycle += (m.flipLegs * m.Vx) * 0.5; //makes the legs look like they are moving fast this is just gonna run for each method call since it needs some tweaking
+ simulation.gravity();
+ Engine.update(engine, simulation.delta);
+ // level.custom();
+ // level.customTopLayer();
+ if (!m.isBodiesAsleep) mobs.loop();
+ if (m.fieldMode !== 7) m.hold();
+ b.bulletRemove();
+ if (!m.isBodiesAsleep) b.bulletDo();
+ simulation.runEphemera();
+ }
+ simulation.isTimeSkipping = false;
+ },
+ ephemera: [], //array that is used to store ephemera objects
+ removeEphemera: function (name) {
+ for (let i = 0, len = simulation.ephemera.length; i < len; i++) {
+ if (simulation.ephemera[i].name === name) {
+ simulation.ephemera.splice(i, 1);
+ break;
+ }
+ }
+ },
+ runEphemera() {
+ for (let i = 0; i < simulation.ephemera.length; i++) {
+ simulation.ephemera[i].do();
+ }
+ },
+ // timeMobSkip() {
+ // simulation.gravity();
+ // Engine.update(engine, simulation.delta);
+ // simulation.wipe();
+ // simulation.textLog();
+ // if (m.onGround) {
+ // m.groundControl()
+ // } else {
+ // m.airControl()
+ // }
+ // m.move();
+ // m.look();
+ // simulation.camera();
+ // level.custom();
+ // powerUps.do();
+ // mobs.draw();
+ // simulation.draw.cons();
+ // simulation.draw.body();
+ // if (!m.isBodiesAsleep) {
+ // // mobs.loop();
+ // }
+ // mobs.healthBar();
+ // m.draw();
+ // m.hold();
+ // // v.draw(); //working on visibility work in progress
+ // level.customTopLayer();
+ // simulation.draw.drawMapPath();
+ // b.fire();
+ // b.bulletRemove();
+ // b.bulletDraw();
+ // if (!m.isBodiesAsleep) b.bulletDo();
+ // simulation.drawCircle();
+ // // simulation.clip();
+ // ctx.restore();
+ // simulation.drawCursor();
+ // // simulation.pixelGraphics();
+ // },
+ mouse: {
+ x: canvas.width / 2,
+ y: canvas.height / 2
+ },
+ mouseInGame: {
+ x: 0,
+ y: 0
+ },
+ g: 0.0024, // applies to player, bodies, and power ups (not mobs)
+ onTitlePage: true,
+ isCheating: false,
+ isTraining: false,
+ paused: false,
+ isChoosing: false,
+ testing: false, //testing mode: shows wire frame and some variables
+ cycle: 0, //total cycles, 60 per second
+ fpsCap: null, //limits frames per second to 144/2=72, on most monitors the fps is capped at 60fps by the hardware
+ fpsCapDefault: 72, //use to change fpsCap back to normal after a hit from a mob
+ isCommunityMaps: false,
+ cyclePaused: 0,
+ fallHeight: 6000, //below this y position the player dies
+ lastTimeStamp: 0, //tracks time stamps for measuring delta
+ delta: 1000 / 60, //speed of game engine //looks like it has to be 16.6666 to match player input
+ buttonCD: 0,
+ isHorizontalFlipped: false, //makes some maps flipped horizontally
+ levelsCleared: 0,
+ difficultyMode: 2, //normal difficulty is 2
+ difficulty: 0,
+ dmgScale: null, //set in levels.setDifficulty
+ healScale: 1,
+ accelScale: null, //set in levels.setDifficulty
+ CDScale: null, //set in levels.setDifficulty
+ molecularMode: Math.floor(4 * Math.random()), //0 spores, 1 missile, 2 ice IX, 3 drones //randomize molecular assembler field type
+ // dropFPS(cap = 40, time = 15) {
+ // simulation.fpsCap = cap
+ // simulation.fpsInterval = 1000 / simulation.fpsCap;
+ // simulation.defaultFPSCycle = simulation.cycle + time
+ // const normalFPS = function () {
+ // if (simulation.defaultFPSCycle < simulation.cycle) {
+ // simulation.fpsCap = 72
+ // simulation.fpsInterval = 1000 / simulation.fpsCap;
+ // } else {
+ // requestAnimationFrame(normalFPS);
+ // }
+ // };
+ // requestAnimationFrame(normalFPS);
+ // },
+ // clip() {
+
+ // },
+ pixelGraphics() {
+ //copy current canvas pixel data
+ let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ let data = imgData.data;
+ //change pixel data
+
+
+ // const off = 4 * Math.floor(x) + 4 * canvas.width * Math.floor(y);
+ // multiple windows
+ for (let i = data.length / 2; i < data.length; i += 4) {
+ index = i % (canvas.width * canvas.height * 2) // + canvas.width*4*canvas.height
+
+ data[i + 0] = data[index + 0]; // red
+ data[i + 1] = data[index + 1]; // red
+ data[i + 2] = data[index + 2]; // red
+ data[i + 3] = data[index + 3]; // red
+ }
+
+ for (let x = 0; x < len; x++) {
+
+ }
+
+
+
+ // const startX = 2 * canvas.width + 2 * canvas.width * canvas.height
+ // const endX = 4 * canvas.width + 4 * canvas.width * canvas.height
+ // const startY = 2 * canvas.width + 2 * canvas.width * canvas.height
+ // const endY = 4 * canvas.width + 4 * canvas.width * canvas.height
+ // for (let x = startX; x < endX; x++) {
+ // for (let y = startY; y < endY; y++) {
+
+ // }
+ // }
+
+
+
+
+ //strange draw offset
+ // const off = canvas.height * canvas.width * 4 / 2
+ // for (let index = 0; index < data.length; index += 4) {
+ // data[index + 0] = data[index + 0 + off]; // red
+ // data[index + 1] = data[index + 1 + off]; // red
+ // data[index + 2] = data[index + 2 + off]; // red
+ // data[index + 3] = data[index + 3 + off]; // red
+ // }
+
+ //change all pixels
+ // for (let index = 0; index < data.length; index += 4) {
+ // data[index + 0] = 255; // red
+ // data[index + 1] = 255; // green
+ // data[index + 2] = 255; // blue
+ // data[index + 3] = 255; // alpha
+ // }
+
+ //change random pixels
+ // for (let i = 0, len = Math.floor(data.length / 10); i < len; ++i) {
+ // const index = Math.floor((Math.random() * data.length) / 4) * 4;
+ // data[index + 0] = 255; // red
+ // data[index + 1] = 0; // green
+ // data[index + 2] = 0; // blue
+ // data[index + 3] = 255 //Math.floor(Math.random() * Math.random() * 255); // alpha
+ // }
+
+ // //change random pixels
+ // for (let i = 0, len = Math.floor(data.length / 1000); i < len; ++i) {
+ // const index = Math.floor((Math.random() * data.length) / 4) * 4;
+ // // data[index] = data[index] ^ 255; // Invert Red
+ // // data[index + 1] = data[index + 1] ^ 255; // Invert Green
+ // // data[index + 2] = data[index + 2] ^ 255; // Invert Blue
+ // data[index + 0] = 0; // red
+ // data[index + 1] = 0; // green
+ // data[index + 2] = 0; // blue
+ // // data[index + 3] = 255 //Math.floor(Math.random() * Math.random() * 255); // alpha
+ // }
+
+ //draw new pixel data to canvas
+ ctx.putImageData(imgData, 0, 0);
+ },
+ drawCursor() {
+ const size = 10;
+ ctx.beginPath();
+ ctx.moveTo(simulation.mouse.x - size, simulation.mouse.y);
+ ctx.lineTo(simulation.mouse.x + size, simulation.mouse.y);
+ ctx.moveTo(simulation.mouse.x, simulation.mouse.y - size);
+ ctx.lineTo(simulation.mouse.x, simulation.mouse.y + size);
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "#000"; //'rgba(0,0,0,0.4)'
+ ctx.stroke(); // Draw it
+ },
+ drawCursorBasic() {
+ const size = 10;
+ ctx.beginPath();
+ ctx.moveTo(simulation.mouse.x - size, simulation.mouse.y);
+ ctx.lineTo(simulation.mouse.x + size, simulation.mouse.y);
+ ctx.moveTo(simulation.mouse.x, simulation.mouse.y - size);
+ ctx.lineTo(simulation.mouse.x, simulation.mouse.y + size);
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "#000"; //'rgba(0,0,0,0.4)'
+ ctx.stroke(); // Draw it
+ },
+ drawCursorCoolDown() {
+ const size = 10;
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "#000"; //'rgba(0,0,0,0.4)'
+ ctx.beginPath();
+ if (m.fireCDcycle > m.cycle) {
+ ctx.strokeStyle = "#000"; //'rgba(0,0,0,0.4)'
+ ctx.arc(simulation.mouse.x, simulation.mouse.y, size + 1, 0, 2 * Math.PI);
+ } else {
+ ctx.strokeStyle = "#000"; //'rgba(0,0,0,0.4)'
+ }
+ ctx.moveTo(simulation.mouse.x - size, simulation.mouse.y);
+ ctx.lineTo(simulation.mouse.x + size, simulation.mouse.y);
+ ctx.moveTo(simulation.mouse.x, simulation.mouse.y - size);
+ ctx.lineTo(simulation.mouse.x, simulation.mouse.y + size);
+ ctx.stroke(); // Draw it
+ },
+ drawList: [], //so you can draw a first frame of explosions.. I know this is bad
+ drawTime: 8, //how long circles are drawn. use to push into drawlist.time
+ mobDmgColor: "rgba(255,0,0,0.7)", //color when a mob damages the player // set by mass-energy tech
+ playerDmgColor: "rgba(0,0,0,0.7)", //color when the player damages a mob
+ drawCircle() {
+ //draws a circle for two cycles, used for showing damage mostly
+ let i = simulation.drawList.length;
+ while (i--) {
+ ctx.beginPath(); //draw circle
+ ctx.arc(simulation.drawList[i].x, simulation.drawList[i].y, simulation.drawList[i].radius, 0, 2 * Math.PI);
+ ctx.fillStyle = simulation.drawList[i].color;
+ ctx.fill();
+ if (simulation.drawList[i].time) {
+ simulation.drawList[i].time--;
+ } else {
+ if (!m.isBodiesAsleep) simulation.drawList.splice(i, 1); //remove when timer runs out
+ }
+ }
+ },
+ circleFlare(dup, loops = 100) {
+ boltNum = dup * 300
+ const bolts = []
+ colors = [powerUps.research.color, powerUps.ammo.color, powerUps.heal.color, powerUps.tech.color, powerUps.field.color, powerUps.gun.color]
+ for (let i = 0; i < boltNum; ++i) {
+ const mag = 6 + 20 * Math.random()
+ const angle = 2 * Math.PI * Math.random()
+ bolts.push({
+ x: m.pos.x,
+ y: m.pos.y,
+ Vx: mag * Math.cos(angle),
+ Vy: mag * Math.sin(angle),
+ color: colors[Math.floor(Math.random() * colors.length)]
+ })
+ }
+ let count = 0
+ loop = () => { //draw electricity
+ if (count++ < loops) requestAnimationFrame(loop)
+ for (let i = 0, len = bolts.length; i < len; ++i) {
+ bolts[i].x += bolts[i].Vx
+ bolts[i].y += bolts[i].Vy
+ if (Math.random() < 0.2) {
+ simulation.drawList.push({
+ x: bolts[i].x,
+ y: bolts[i].y,
+ radius: 1.5 + 5 * Math.random(),
+ // color: "rgba(0,155,155,0.7)",
+ color: bolts[i].color,
+ time: Math.floor(9 + 25 * Math.random() * Math.random())
+ });
+ }
+ }
+ }
+ requestAnimationFrame(loop)
+ },
+ boldActiveGunHUD() {
+ if (b.inventory.length > 0) {
+ for (let i = 0, len = b.inventory.length; i < len; ++i) {
+ if (b.inventory[i] === b.activeGun && document.getElementById(b.activeGun)) {
+ document.getElementById(b.inventory[i]).style.opacity = "1";
+ } else {
+ document.getElementById(b.inventory[i]).style.opacity = "0.3";
+ }
+ }
+ }
+ },
+ updateGunHUD() {
+ for (let i = 0, len = b.inventory.length; i < len; ++i) {
+ document.getElementById(b.inventory[i]).innerHTML = `${b.guns[b.inventory[i]].name} - ${b.guns[b.inventory[i]].ammo}`
+ }
+ },
+ makeGunHUD() {
+ //remove all nodes
+ const myNode = document.getElementById("guns");
+ while (myNode.firstChild) {
+ myNode.removeChild(myNode.firstChild);
+ }
+ //add nodes
+ for (let i = 0, len = b.inventory.length; i < len; ++i) {
+ const node = document.createElement("div");
+ node.setAttribute("id", b.inventory[i]);
+ const textNode = document.createTextNode(`${b.guns[b.inventory[i]].name} - ${b.guns[b.inventory[i]].ammo}`); //b.guns[b.inventory[i]].name + " - " + b.guns[b.inventory[i]].ammo);
+ node.appendChild(textNode);
+ document.getElementById("guns").appendChild(node);
+ }
+ simulation.boldActiveGunHUD();
+ },
+ updateTechHUD() {
+ let text = ""
+ for (let i = 0, len = tech.tech.length; i < len; i++) { //add tech
+ if (tech.tech[i].isLost) {
+ if (text) text += " " //add a new line, but not on the first line
+ text += `${tech.tech[i].name} `
+ } else if (tech.tech[i].count > 0 && !tech.tech[i].isNonRefundable) {
+ if (text) text += " " //add a new line, but not on the first line
+ text += tech.tech[i].name
+ if (tech.tech[i].nameInfo) {
+ text += tech.tech[i].nameInfo
+ tech.tech[i].addNameInfo();
+ }
+ if (tech.tech[i].count > 1) text += ` (${tech.tech[i].count}x)`
+ }
+ }
+ document.getElementById("tech").innerHTML = text
+ },
+ lastLogTime: 0,
+ isTextLogOpen: true,
+ //
+ // SVGleftMouse: ' ',
+ // SVGrightMouse: ' ',
+ makeTextLog(text, time = 240) {
+ if (!localSettings.isHideHUD && simulation.isTextLogOpen && !build.isExperimentSelection) {
+ if (simulation.lastLogTime > m.cycle) { //if there is an older message
+ document.getElementById("text-log").innerHTML = document.getElementById("text-log").innerHTML + ' ' + text;
+ simulation.lastLogTime = m.cycle + time;
+ } else {
+ document.getElementById("text-log").innerHTML = text;
+ document.getElementById("text-log").style.display = "inline";
+ simulation.lastLogTime = m.cycle + time;
+ }
+ }
+ },
+ textLog() {
+ if (simulation.lastLogTime && simulation.lastLogTime < m.cycle) {
+ simulation.lastLogTime = 0;
+ // document.getElementById("text-log").innerHTML = " ";
+ document.getElementById("text-log").style.display = "none";
+ }
+ },
+ nextGun() {
+ if (b.inventory.length > 1 && !tech.isGunCycle) {
+ b.inventoryGun++;
+ if (b.inventoryGun > b.inventory.length - 1) b.inventoryGun = 0;
+ simulation.switchGun();
+ }
+ },
+ previousGun() {
+ if (b.inventory.length > 1 && !tech.isGunCycle) {
+ b.inventoryGun--;
+ if (b.inventoryGun < 0) b.inventoryGun = b.inventory.length - 1;
+ simulation.switchGun();
+ }
+ },
+ switchToGunInInventory(num) {
+ if (b.inventory[num] !== undefined && b.inventoryGun !== num) {
+ b.inventoryGun = num
+ simulation.switchGun();
+ }
+ },
+ switchGun() {
+ if (tech.isLongitudinal && b.activeGun === 3) b.guns[3].waves = []; //empty array of wave bullets
+ if (tech.crouchAmmoCount) tech.crouchAmmoCount = 1 //this prevents hacking the tech by switching guns
+ if (b.inventory.length > 0) b.activeGun = b.inventory[b.inventoryGun];
+ b.guns[8].charge = 0; // foam charge to 0
+ simulation.updateGunHUD();
+ simulation.boldActiveGunHUD();
+ //set crosshairs
+ if (b.activeGun === 1) {
+ simulation.drawCursor = simulation.drawCursorCoolDown
+ } else {
+ simulation.drawCursor = simulation.drawCursorBasic
+ }
+ },
+ zoom: null,
+ zoomScale: 1000,
+ isAutoZoom: true,
+ setZoom(zoomScale = simulation.zoomScale) { //use in window resize in index.js
+ simulation.zoomScale = zoomScale
+ simulation.zoom = canvas.height / zoomScale; //sets starting zoom scale
+ },
+ zoomTransition(newZoomScale, step = 2) {
+ if (simulation.isAutoZoom) {
+ const isBigger = (newZoomScale - simulation.zoomScale > 0) ? true : false;
+ requestAnimationFrame(zLoop);
+ const currentLevel = level.onLevel
+
+ function zLoop() {
+ if (currentLevel !== level.onLevel || simulation.isAutoZoom === false) return //stop the zoom if player goes to a new level
+
+ if (isBigger) {
+ simulation.zoomScale += step
+ if (simulation.zoomScale >= newZoomScale) {
+ simulation.setZoom(newZoomScale);
+ return
+ }
+ } else {
+ simulation.zoomScale -= step
+ if (simulation.zoomScale <= newZoomScale) {
+ simulation.setZoom(newZoomScale);
+ return
+ }
+ }
+
+ simulation.setZoom();
+ requestAnimationFrame(zLoop);
+ }
+ }
+ },
+ zoomInFactor: 0,
+ startZoomIn(time = 180) {
+ simulation.zoom = 0;
+ let count = 0;
+ requestAnimationFrame(zLoop);
+
+ function zLoop() {
+ simulation.zoom += canvas.height / simulation.zoomScale / time;
+ count++;
+ if (count < time) {
+ requestAnimationFrame(zLoop);
+ } else {
+ simulation.setZoom();
+ }
+ }
+ },
+ noCameraScroll() { //makes the camera not scroll after changing locations
+ //only works if velocity is zero
+ m.pos.x = player.position.x;
+ m.pos.y = playerBody.position.y - m.yOff;
+ const scale = 0.8;
+ m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+ m.transX += (m.transSmoothX - m.transX) * 1;
+ m.transY += (m.transSmoothY - m.transY) * 1;
+ },
+ edgeZoomOutSmooth: 1,
+ camera() {
+ //zoom out when mouse gets near the edge of the window
+ const dx = simulation.mouse.x / window.innerWidth - 0.5 //x distance from mouse to window center scaled by window width
+ const dy = simulation.mouse.y / window.innerHeight - 0.5 //y distance from mouse to window center scaled by window height
+ const d = Math.max(dx * dx, dy * dy)
+ simulation.edgeZoomOutSmooth = (1 + 4 * d * d) * 0.04 + simulation.edgeZoomOutSmooth * 0.96
+
+ ctx.save();
+ ctx.translate(canvas.width2, canvas.height2); //center
+ ctx.scale(simulation.zoom / simulation.edgeZoomOutSmooth, simulation.zoom / simulation.edgeZoomOutSmooth); //zoom in once centered
+ ctx.translate(-canvas.width2 + m.transX, -canvas.height2 + m.transY); //translate
+ //calculate in game mouse position by undoing the zoom and translations
+ simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX;
+ simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY;
+ },
+ cameraNoLook() {
+ ctx.save();
+ ctx.translate(canvas.width2, canvas.height2); //center
+ // ctx.scale(simulation.zoom / simulation.edgeZoomOutSmooth, simulation.zoom / simulation.edgeZoomOutSmooth); //zoom in once centered
+ ctx.translate(-canvas.width2 + m.transX, -canvas.height2 + m.transY); //translate
+ //calculate in game mouse position by undoing the zoom and translations
+ simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX;
+ simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY;
+ },
+ restoreCamera() {
+ ctx.restore();
+ },
+ trails() {
+ const swapPeriod = 150
+ const len = 30
+ for (let i = 0; i < len; i++) {
+ setTimeout(function () {
+ simulation.wipe = function () { //set wipe to have trails
+ ctx.fillStyle = `rgba(221,221,221,${i * i * 0.0005 + 0.0025})`;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ }
+ }, (i) * swapPeriod);
+ }
+
+ setTimeout(function () {
+ simulation.wipe = function () { //set wipe to normal
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ }
+ }, len * swapPeriod);
+ },
+ // warp(translation = 5, skew = 0.05, scale = 0.05) {
+ // if (simulation.cycle % 2) { //have to alternate frames or else successive rumbles over write the effects of the previous rumble
+ // requestAnimationFrame(() => { ctx.setTransform(1, 0, 0, 1, 0, 0); }) //reset
+ // requestAnimationFrame(() => {
+ // if (!simulation.paused && m.alive) {
+ // ctx.transform(1 - scale * (Math.random() - 0.5), skew * (Math.random() - 0.5), skew * (Math.random() - 0.5), 1 - scale * (Math.random() - 0.5), translation * (Math.random() - 0.5), translation * (Math.random() - 0.5)); //ctx.transform(Horizontal scaling. A value of 1 results in no scaling, Vertical skewing, Horizontal skewing, Vertical scaling. A value of 1 results in no scaling, Horizontal translation (moving), Vertical translation (moving)) //https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setTransform
+ // }
+ // })
+
+ //reset
+ // ctx.transform(1, 0, 0, 1, 0, 0); //ctx.transform(Horizontal scaling. A value of 1 results in no scaling, Vertical skewing, Horizontal skewing, Vertical scaling. A value of 1 results in no scaling, Horizontal translation (moving), Vertical translation (moving)) //https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setTransform
+
+ // }
+ // const loop = () => {
+ // if (!simulation.paused && m.alive) {
+ // ctx.save();
+ // ctx.transform(1 - scale * (Math.random() - 0.5), skew * (Math.random() - 0.5), skew * (Math.random() - 0.5), 1 - scale * (Math.random() - 0.5), translation * (Math.random() - 0.5), translation * (Math.random() - 0.5)); //ctx.transform(Horizontal scaling. A value of 1 results in no scaling, Vertical skewing, Horizontal skewing, Vertical scaling. A value of 1 results in no scaling, Horizontal translation (moving), Vertical translation (moving))
+ // requestAnimationFrame(() => { ctx.restore(); })
+ // }
+ // }
+ // requestAnimationFrame(loop);
+
+ // function loop() {
+ // if (!simulation.paused && m.alive) {
+ // ctx.save();
+ // ctx.transform(1 - scale * (Math.random() - 0.5), skew * (Math.random() - 0.5), skew * (Math.random() - 0.5), 1 - scale * (Math.random() - 0.5), translation * (Math.random() - 0.5), translation * (Math.random() - 0.5)); //ctx.transform(Horizontal scaling. A value of 1 results in no scaling, Vertical skewing, Horizontal skewing, Vertical scaling. A value of 1 results in no scaling, Horizontal translation (moving), Vertical translation (moving))
+ // requestAnimationFrame(() => { ctx.restore(); })
+ // }
+ // requestAnimationFrame(loop);
+ // }
+ // requestAnimationFrame(loop);
+ // },
+ wipe() { }, //set in simulation.startGame
+ gravity() {
+ function addGravity(bodies, magnitude) {
+ for (var i = 0; i < bodies.length; i++) {
+ bodies[i].force.y += bodies[i].mass * magnitude;
+ }
+ }
+ if (!m.isBodiesAsleep) {
+ addGravity(powerUp, simulation.g);
+ addGravity(body, simulation.g);
+ }
+ player.force.y += player.mass * simulation.g;
+ },
+ firstRun: true,
+ splashReturn() {
+ document.getElementById("previous-seed").innerHTML = `previous seed: ${Math.initialSeed} `
+ document.getElementById("seed").value = Math.initialSeed = Math.seed //randomize initial seed
+
+ //String(document.getElementById("seed").value)
+ // Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it
+
+
+ simulation.clearTimeouts();
+ simulation.onTitlePage = true;
+ document.getElementById("splash").onclick = function () {
+ simulation.startGame();
+ };
+ document.getElementById("choose-grid").style.visibility = "hidden"
+ document.getElementById("choose-grid").style.opacity = "0"
+ document.getElementById("info").style.display = "inline";
+ document.getElementById("info").style.opacity = "0";
+ document.getElementById("experiment-button").style.display = "inline"
+ document.getElementById("experiment-button").style.opacity = "0";
+ document.getElementById("training-button").style.display = "inline"
+ document.getElementById("training-button").style.opacity = "0";
+ document.getElementById("experiment-grid").style.display = "none"
+ document.getElementById("pause-grid-left").style.display = "none"
+ document.getElementById("pause-grid-right").style.display = "none"
+ document.getElementById("splash").style.display = "inline";
+ document.getElementById("splash").style.opacity = "0";
+ document.getElementById("dmg").style.display = "none";
+ document.getElementById("health-bg").style.display = "none";
+ document.getElementById("defense-bar").style.display = "none"
+ document.getElementById("damage-bar").style.display = "none"
+ document.body.style.cursor = "auto";
+ setTimeout(() => {
+ document.getElementById("experiment-button").style.opacity = "1";
+ document.getElementById("training-button").style.opacity = "1";
+ document.getElementById("info").style.opacity = "1";
+ document.getElementById("splash").style.opacity = "1";
+ }, 200);
+ },
+ fpsInterval: 0, //set in startGame
+ then: null,
+ startGame(isBuildRun = false, isTrainingRun = false) {
+ simulation.isTextLogOpen = true
+ simulation.clearMap()
+ if (!isBuildRun) { //if a build run logic flow returns to "experiment-button").addEventListener
+ document.body.style.cursor = "none";
+ document.body.style.overflow = "hidden"
+ }
+ if (isTrainingRun) {
+ simulation.isTraining = true
+ } else {
+ simulation.isTraining = false
+ }
+ simulation.onTitlePage = false;
+ // document.getElementById("choose-grid").style.display = "none"
+ document.getElementById("choose-grid").style.visibility = "hidden"
+ document.getElementById("choose-grid").style.opacity = "0"
+ document.getElementById("experiment-grid").style.display = "none"
+ document.getElementById("info").style.display = "none";
+ document.getElementById("experiment-button").style.display = "none";
+ document.getElementById("training-button").style.display = "none";
+ // document.getElementById("experiment-button").style.opacity = "0";
+ document.getElementById("splash").onclick = null; //removes the onclick effect so the function only runs once
+ document.getElementById("splash").style.display = "none"; //hides the element that spawned the function
+ document.getElementById("dmg").style.display = "inline";
+ document.getElementById("health").style.display = "inline"
+ document.getElementById("health-bg").style.display = "inline";
+ if (!localSettings.isHideHUD) {
+ document.getElementById("tech").style.display = "inline"
+ document.getElementById("defense-bar").style.display = "inline"
+ document.getElementById("damage-bar").style.display = "inline"
+ } else {
+ document.getElementById("tech").style.display = "none"
+ document.getElementById("defense-bar").style.display = "none"
+ document.getElementById("damage-bar").style.display = "none"
+ }
+ document.getElementById("guns").style.display = "inline"
+ document.getElementById("field").style.display = "inline"
+
+ // document.body.style.overflow = "hidden"
+ document.getElementById("pause-grid-left").style.display = "none"
+ document.getElementById("pause-grid-right").style.display = "none"
+ document.getElementById("pause-grid-right").style.opacity = "1"
+ document.getElementById("pause-grid-left").style.opacity = "1"
+ ctx.globalCompositeOperation = "source-over"
+ ctx.shadowBlur = 0;
+ requestAnimationFrame(() => {
+ ctx.setTransform(1, 0, 0, 1, 0, 0); //reset warp effect
+ ctx.setLineDash([]) //reset stroke dash effect
+ })
+ // ctx.shadowColor = '#000';
+ if (!m.isShipMode) {
+ m.resetSkin() //set the play draw to normal, undoing some junk tech
+ m.spawn(); //spawns the player
+ m.look = m.lookDefault
+ } else {
+ Composite.add(engine.world, [player])
+ }
+ level.populateLevels()
+
+ input.endKeySensing();
+ simulation.ephemera = []
+ tech.setupAllTech(); //sets tech to default values
+ b.removeAllGuns();
+ tech.duplication = 0;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
+ if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
+ if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
+ if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
+ if (b.guns[i].name === "foam") b.guns[i].chooseFireMethod()
+ }
+ tech.dynamoBotCount = 0;
+ tech.nailBotCount = 0;
+ tech.laserBotCount = 0;
+ tech.orbitBotCount = 0;
+ tech.foamBotCount = 0;
+ tech.soundBotCount = 0;
+ tech.boomBotCount = 0;
+ tech.plasmaBotCount = 0;
+ tech.missileBotCount = 0;
+
+ simulation.isChoosing = false;
+ b.setFireMethod()
+ b.setFireCD();
+ // simulation.updateTechHUD();
+ for (let i = 0; i < b.guns.length; i++) b.guns[i].isRecentlyShown = false //reset recently shown back to zero
+ for (let i = 0; i < m.fieldUpgrades.length; i++) m.fieldUpgrades[i].isRecentlyShown = false //reset recently shown back to zero
+ for (let i = 0; i < tech.tech.length; i++) tech.tech[i].isRecentlyShown = false //reset recently shown back to zero
+
+ powerUps.tech.choiceLog = [];
+ powerUps.gun.choiceLog = [];
+ powerUps.field.choiceLog = [];
+ powerUps.totalPowerUps = 0;
+ powerUps.research.count = 0;
+ powerUps.boost.endCycle = 0
+ powerUps.isFieldSpawned = false
+ m.setFillColors();
+ // m.maxHealth = 1
+ // m.maxEnergy = 1
+ // m.energy = 1
+ input.isPauseKeyReady = true
+ simulation.wipe = function () { //set wipe to normal
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ }
+ m.hole.isOn = false
+ simulation.paused = false;
+ // simulation.cycle = 0
+ // m.cycle = 0
+ engine.timing.timeScale = 1;
+ simulation.fpsCap = simulation.fpsCapDefault;
+ simulation.isAutoZoom = true;
+ simulation.makeGunHUD();
+ simulation.lastLogTime = 0;
+ mobs.mobDeaths = 0
+
+ level.onLevel = 0;
+ level.levelsCleared = 0;
+ //resetting difficulty
+ // simulation.difficulty = 0;
+ level.setDifficulty()
+ simulation.difficultyMode = Number(document.getElementById("difficulty-select").value)
+
+ simulation.clearNow = true;
+ document.getElementById("text-log").style.display = "none"
+ document.getElementById("fade-out").style.opacity = 0;
+ document.title = "n-gon";
+ // simulation.makeTextLog(`input.key.up: ["${input.key.up} ", "ArrowUp "]`);
+ // simulation.makeTextLog(`input.key.left: ["${input.key.left} ", "ArrowLeft "]`);
+ // simulation.makeTextLog(`input.key.down: ["${input.key.down} ", "ArrowDown "]`);
+ // simulation.makeTextLog(`input.key.right: ["${input.key.right} ", "ArrowRight "]`);
+ simulation.makeTextLog(`Math.seed = ${Math.initialSeed}`);
+ simulation.makeTextLog(`const engine = Engine.create(); //simulation begin `);
+ simulation.makeTextLog(`engine.timing.timeScale = 1`);
+ // simulation.makeTextLog(`input.key.field: ["${input.key.field} ", "MouseRight "]`);
+
+ // document.getElementById("health").style.display = "inline"
+ // document.getElementById("health-bg").style.display = "inline"
+ m.alive = true;
+ m.onGround = false
+ m.lastOnGroundCycle = 0
+ m.health = 0;
+ m.addHealth(0.25)
+ m.drop();
+ m.holdingTarget = null
+
+ //set to default field
+ tech.healMaxEnergyBonus = 0
+ // m.setMaxEnergy();
+ m.energy = 0
+ m.immuneCycle = 0;
+ // simulation.makeTextLog(`${simulation.SVGrightMouse} ${m.fieldUpgrades[m.fieldMode].name} ${m.fieldUpgrades[m.fieldMode].description}`, 600);
+ // simulation.makeTextLog(`
+ // input.key.up = ["${input.key.up} ", "ArrowUp "]
+ // input.key.left = ["${input.key.left} ", "ArrowLeft "]
+ // input.key.down = ["${input.key.down} ", "ArrowDown "]
+ // input.key.right = ["${input.key.right} ", "ArrowRight "]
+ //
+ // m .fieldMode = "${m.fieldUpgrades[m.fieldMode].name} "
+ // input.key.field = ["${input.key.field} ", "right mouse "]
+ // m .field.description = "${m.fieldUpgrades[m.fieldMode].description} "
+ // `, 800);
+ m.coupling = 0
+ m.setField(0) //this calls m.couplingChange(), which sets max health and max energy
+ // m.energy = 0;
+ //exit testing
+ if (simulation.testing) {
+ simulation.testing = false;
+ simulation.loop = simulation.normalLoop
+ if (simulation.isConstructionMode) document.getElementById("construct").style.display = 'none'
+ }
+ simulation.isCheating = false
+ simulation.firstRun = false;
+ build.hasExperimentalMode = false
+ build.isExperimentSelection = false;
+ build.isExperimentRun = false;
+
+
+ //setup checks
+ if (!localSettings.isHideHUD) {
+ simulation.ephemera.push({
+ name: "dmgDefBars", count: 0, do() {
+ if (!(m.cycle % 15)) { //4 times a second
+ const defense = m.defense() //update defense bar
+ if (m.lastCalculatedDefense !== defense) {
+ document.getElementById("defense-bar").style.width = Math.floor(300 * m.maxHealth * (1 - defense)) + "px";
+ m.lastCalculatedDefense = defense
+ }
+ const damage = tech.damageFromTech() //update damage bar
+ if (m.lastCalculatedDamage !== damage) {
+ document.getElementById("damage-bar").style.height = Math.floor((Math.atan(0.25 * damage - 0.25) + 0.25) * 0.53 * canvas.height) + "px";
+ m.lastCalculatedDamage = damage
+ }
+ }
+ },
+ })
+ }
+ simulation.ephemera.push({
+ name: "uniqueName", count: 0, do() {
+ if (!(m.cycle % 60)) { //once a second
+ //energy overfill
+ if (m.energy > m.maxEnergy) {
+ m.energy = m.maxEnergy + (m.energy - m.maxEnergy) * tech.overfillDrain //every second energy above max energy loses 25%
+ if (m.energy > 1000000) m.energy = 1000000
+ }
+ if (tech.isFlipFlopEnergy && m.immuneCycle < m.cycle) {
+ if (tech.isFlipFlopOn) {
+ if (m.immuneCycle < m.cycle) m.energy += 0.2;
+ } else {
+ m.energy -= 0.01;
+ if (m.energy < 0) m.energy = 0
+ }
+ }
+ if (tech.relayIce && tech.isFlipFlopOn) {
+ for (let j = 0; j < tech.relayIce; j++) {
+ for (let i = 0, len = 3 + Math.ceil(9 * Math.random()); i < len; i++) b.iceIX(2)
+ }
+ }
+
+ if (m.pos.y > simulation.fallHeight) { // if 4000px deep
+ Matter.Body.setVelocity(player, {
+ x: 0,
+ y: 0
+ });
+ Matter.Body.setPosition(player, {
+ x: level.enter.x + 50,
+ y: level.enter.y - 20
+ });
+ // move bots
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) {
+ Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
+ x: 250 * (Math.random() - 0.5),
+ y: 250 * (Math.random() - 0.5)
+ }));
+ Matter.Body.setVelocity(bullet[i], {
+ x: 0,
+ y: 0
+ });
+ }
+ }
+ m.damage(0.1 * simulation.difficultyMode);
+ m.energy -= 0.1 * simulation.difficultyMode
+ }
+ if (isNaN(player.position.x)) m.death();
+ if (m.lastKillCycle + 300 > m.cycle) { //effects active for 5 seconds after killing a mob
+ if (tech.isEnergyRecovery && m.immuneCycle < m.cycle) {
+ m.energy += m.maxEnergy * 0.05
+ simulation.drawList.push({ //add dmg to draw queue
+ x: m.pos.x,
+ y: m.pos.y - 45,
+ radius: Math.sqrt(m.maxEnergy * 0.05) * 60,
+ color: "rgba(0, 204, 255,0.4)", //#0cf
+ time: 4
+ });
+ }
+ if (tech.isHealthRecovery) {
+ const heal = 0.005 * m.maxHealth
+ m.addHealth(heal)
+ simulation.drawList.push({ //add dmg to draw queue
+ x: m.pos.x,
+ y: m.pos.y,
+ radius: Math.sqrt(heal) * 150,
+ color: "rgba(0,255,200,0.5)",
+ time: 4
+ });
+ }
+ }
+
+ if (!(m.cycle % 420)) { //once every 7 seconds
+ if (tech.isZeno) {
+ if (tech.isEnergyHealth) {
+ m.energy *= 0.95
+ } else {
+ m.health *= 0.95 //remove 5%
+ m.displayHealth();
+ }
+
+ }
+ if (tech.cyclicImmunity && m.immuneCycle < m.cycle + tech.cyclicImmunity) m.immuneCycle = m.cycle + tech.cyclicImmunity; //player is immune to damage for 60 cycles
+
+ fallCheck = function (who, save = false) {
+ let i = who.length;
+ while (i--) {
+ if (who[i].position.y > simulation.fallHeight) {
+ if (save) {
+ Matter.Body.setVelocity(who[i], {
+ x: 0,
+ y: 0
+ });
+ Matter.Body.setPosition(who[i], {
+ x: level.exit.x + 30 * (Math.random() - 0.5),
+ y: level.exit.y + 30 * (Math.random() - 0.5)
+ });
+ } else {
+ Matter.Composite.remove(engine.world, who[i]);
+ who.splice(i, 1);
+ }
+ }
+ }
+ };
+ fallCheck(body);
+ fallCheck(powerUp, true);
+ let i = mob.length;
+ while (i--) {
+ if (mob[i].position.y > simulation.fallHeight) mob[i].death();
+ }
+
+ }
+ }
+ },
+ })
+
+ //setup FPS cap
+ simulation.fpsInterval = 1000 / simulation.fpsCap;
+ simulation.then = Date.now();
+ requestAnimationFrame(cycle); //starts game loop
+ },
+ clearTimeouts() {
+ let id = window.setTimeout(function () { }, 0);
+ while (id--) {
+ window.clearTimeout(id); // will do nothing if no timeout with id is present
+ }
+ },
+ clearNow: false,
+ clearMap() {
+ level.isProcedural = false;
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ if (m.alive) {
+ if (tech.isLongitudinal) b.guns[3].waves = []; //empty array of wave bullets
+ if (b.guns[10].have) { //do you have mines as a gun
+ let count = 0;
+ for (i = 0, len = bullet.length; i < len; i++) { //count mines left on map
+ if (
+ (bullet[i].bulletType === "mine" && (!tech.isMineSentry || bullet[i].shots === undefined)) ||
+ bullet[i].bulletType === "laser mine") {
+ count++
+ }
+ }
+ if (tech.crouchAmmoCount) count = Math.ceil(count / 2)
+ b.guns[10].ammo += count
+ if (tech.ammoCap) b.guns[10].ammo = Math.min(tech.ammoCap, b.guns[10].ammo)
+ simulation.updateGunHUD();
+ }
+
+ // for (i = 0, len = b.guns.length; i < len; i++) { //find which gun is mine
+ // if (b.guns[i].name === "mine") {
+ // b.guns[i].ammo += count
+ // if (tech.ammoCap) b.guns[i].ammo = Math.min(tech.ammoCap, b.guns[i].ammo)
+ // simulation.updateGunHUD();
+ // break;
+ // }
+ // }
+
+ if (tech.isMutualism && !tech.isEnergyHealth) {
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].isMutualismActive) {
+ m.health += 0.01 + 0.01 * ((bullet[i].isSpore || bullet[i].isFlea) ? 0 : 1)
+ if (m.health > m.maxHealth) m.health = m.maxHealth;
+ m.displayHealth();
+ }
+ }
+ }
+ if (tech.isEndLevelPowerUp) {
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "tech") {
+ tech.giveTech()
+ } else if (powerUp[i].name === "gun") {
+ if (!tech.isOneGun) b.giveGuns("random")
+ } else if (powerUp[i].name === "field") {
+ if (m.fieldMode === 0) m.setField(Math.ceil(Math.random() * (m.fieldUpgrades.length - 1))) //pick a random field, but not field 0
+ } else {
+ powerUp[i].effect();
+ }
+ }
+ }
+ }
+ simulation.lastLogTime = 0; //clear previous messages
+ spawn.allowShields = true;
+ powerUps.totalPowerUps = powerUp.length
+ let holdTarget = (m.holdingTarget) ? m.holdingTarget : undefined //if player is holding something this remembers it before it gets deleted
+ tech.deathSpawnsFromBoss = 0;
+ simulation.fallHeight = 3000;
+ document.body.style.backgroundColor = "#eee" //"#d8dadf";
+ // color.map = "#444";
+ // color.bullet = "#FFFFFF";
+ color = { //light
+ // background: "#ddd", // used instead: document.body.style.backgroundColor
+ block: "rgba(140,140,140,0.85)",
+ blockS: "#222",
+ map: "#444",
+ bullet: "#000"
+ }
+ simulation.draw.drawMapPath = simulation.draw.drawMapPathDefault
+ m.fireCDcycle = 0
+ m.drop();
+ m.hole.isOn = false;
+ simulation.drawList = [];
+
+ if (tech.isHealAttract && m.alive) { //send health power ups to the next level
+ let healCount = 0
+ for (let i = 0, len = powerUp.length; i < len; i++) {
+ if (powerUp[i].name === "heal" && Vector.magnitudeSquared(Vector.sub(powerUp[i].position, m.pos)) < 1000000) healCount++
+ }
+ //respawn health in animation frame
+ let respawnHeal = () => {
+ if (healCount > 0) {
+ requestAnimationFrame(respawnHeal);
+ if (!simulation.paused && !simulation.isChoosing) {
+ healCount--
+ powerUps.directSpawn(level.enter.x + 50 + 100 * (Math.random() - 0.5), level.enter.y - 60 + 100 * (Math.random() - 0.5), "heal");
+ }
+ }
+ }
+ requestAnimationFrame(respawnHeal);
+ }
+ if (tech.isDronesTravel && m.alive) {
+ //count drones
+ let droneCount = 0
+ let sporeCount = 0
+ let wormCount = 0
+ let fleaCount = 0
+ let deliveryCount = 0
+ for (let i = 0; i < bullet.length; ++i) {
+ if (bullet[i].isDrone) {
+ droneCount++
+ if (bullet[i].isImproved) deliveryCount++
+ } else if (bullet[i].isSpore) {
+ sporeCount++
+ } else if (bullet[i].wormSize) {
+ wormCount++
+ } else if (bullet[i].isFlea) {
+ fleaCount++
+ }
+ }
+
+ //respawn drones in animation frame
+ requestAnimationFrame(() => { b.delayDrones({ x: level.enter.x + 50, y: level.enter.y - 60 }, droneCount) });
+
+ //respawn spores in animation frame
+ let respawnSpores = () => {
+ if (sporeCount > 0) {
+ requestAnimationFrame(respawnSpores);
+ if (!simulation.paused && !simulation.isChoosing) {
+ sporeCount--
+ const where = {
+ x: level.enter.x + 50,
+ y: level.enter.y - 60
+ }
+ b.spore({
+ x: where.x + 100 * (Math.random() - 0.5),
+ y: where.y + 120 * (Math.random() - 0.5)
+ })
+ }
+ }
+ }
+ requestAnimationFrame(respawnSpores);
+
+ //respawn worms in animation frame
+ let respawnWorms = () => {
+ if (wormCount > 0) {
+ requestAnimationFrame(respawnWorms);
+ if (!simulation.paused && !simulation.isChoosing) {
+ wormCount--
+ const where = {
+ x: level.enter.x + 50,
+ y: level.enter.y - 60
+ }
+ b.worm({
+ x: where.x + 100 * (Math.random() - 0.5),
+ y: where.y + 120 * (Math.random() - 0.5)
+ })
+ }
+ }
+ }
+ requestAnimationFrame(respawnWorms);
+
+ //respawn fleas in animation frame
+ let respawnFleas = () => {
+ if (fleaCount > 0) {
+ requestAnimationFrame(respawnFleas);
+ if (!simulation.paused && !simulation.isChoosing) {
+ fleaCount--
+ const where = {
+ x: level.enter.x + 50,
+ y: level.enter.y - 60
+ }
+ const speed = 6 + 3 * Math.random()
+ const angle = 2 * Math.PI * Math.random()
+ b.flea({
+ x: where.x + 100 * (Math.random() - 0.5),
+ y: where.y + 120 * (Math.random() - 0.5)
+ }, {
+ x: speed * Math.cos(angle),
+ y: speed * Math.sin(angle)
+ })
+ }
+ }
+ }
+ requestAnimationFrame(respawnFleas);
+ }
+ if (tech.isQuantumEraser) {
+ let count = 0
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isDropPowerUp && mob[i].alive) count++
+ }
+ count *= 0.17 //to fake the chance, this makes it not random, and maybe less confusing
+ let cycle = () => { //run after waiting a cycle for the map to be cleared
+ const types = ["heal", "ammo", "heal", "ammo", "research", "coupling", "boost", "tech", "gun", "field"]
+ for (let i = 0; i < count; i++) powerUps.spawnDelay(types[Math.floor(Math.random() * types.length)], 1)
+ }
+ requestAnimationFrame(cycle);
+ }
+
+ function removeAll(array) {
+ // for (let i = 0; i < array.length; ++i) Matter.Composite.remove(engine.world, array[i]);
+ for (let i = 0; i < array.length; ++i) Matter.Composite.remove(engine.world, array[i]);
+ }
+ removeAll(map);
+ map = [];
+ removeAll(body);
+ body = [];
+ removeAll(mob);
+ mob = [];
+ removeAll(powerUp);
+ powerUp = [];
+ removeAll(cons);
+ cons = [];
+ removeAll(consBB);
+ consBB = [];
+ removeAll(bullet);
+ bullet = [];
+ removeAll(composite);
+ composite = [];
+ // if player was holding something this makes a new copy to hold
+ if (holdTarget && m.alive) {
+ len = body.length;
+ body[len] = Matter.Bodies.fromVertices(0, 0, holdTarget.vertices, {
+ friction: holdTarget.friction,
+ frictionAir: holdTarget.frictionAir,
+ frictionStatic: holdTarget.frictionStatic
+ });
+ Matter.Body.setPosition(body[len], m.pos);
+ m.isHolding = true
+ m.holdingTarget = body[len];
+ m.holdingTarget.collisionFilter.category = 0;
+ m.holdingTarget.collisionFilter.mask = 0;
+ m.definePlayerMass(m.defaultMass + m.holdingTarget.mass * m.holdingMassScale)
+ Composite.add(engine.world, m.holdingTarget); //add to world
+ m.holdingTarget.classType = "body"
+ }
+ //set fps back to default
+ simulation.fpsCap = simulation.fpsCapDefault
+ simulation.fpsInterval = 1000 / simulation.fpsCap;
+ },
+ // getCoords: {
+ // //used when building maps, outputs a draw rect command to console, only works in testing mode
+ // pos1: {
+ // x: 0,
+ // y: 0
+ // },
+ // pos2: {
+ // x: 0,
+ // y: 0
+ // },
+ // out() {
+ // if (keys[49]) {
+ // simulation.getCoords.pos1.x = Math.round(simulation.mouseInGame.x / 25) * 25;
+ // simulation.getCoords.pos1.y = Math.round(simulation.mouseInGame.y / 25) * 25;
+ // }
+ // if (keys[50]) {
+ // //press 1 in the top left; press 2 in the bottom right;copy command from console
+ // simulation.getCoords.pos2.x = Math.round(simulation.mouseInGame.x / 25) * 25;
+ // simulation.getCoords.pos2.y = Math.round(simulation.mouseInGame.y / 25) * 25;
+ // window.getSelection().removeAllRanges();
+ // var range = document.createRange();
+ // range.selectNode(document.getElementById("test"));
+ // window.getSelection().addRange(range);
+ // document.execCommand("copy");
+ // window.getSelection().removeAllRanges();
+ // console.log(`spawn.mapRect(${simulation.getCoords.pos1.x}, ${simulation.getCoords.pos1.y}, ${simulation.getCoords.pos2.x - simulation.getCoords.pos1.x}, ${simulation.getCoords.pos2.y - simulation.getCoords.pos1.y}); //`);
+ // }
+ // }
+ // },
+ testingOutput() {
+ ctx.fillStyle = "#000";
+ ctx.textAlign = "center";
+ ctx.fillText(`(${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)})`, simulation.mouse.x, simulation.mouse.y - 20);
+ },
+ sight: { //credit to Cornbread for adding this algorithm to n-gon
+ // square: 0,
+ intersectMap: [], //this is precalculated in simulation.draw.lineOfSightPrecalculation()
+ getIntersection(v1, v1End, domain) {
+ const intersections = simulation.sight.getIntersections(v1, v1End, domain);
+ var best = { x: v1End.x, y: v1End.y, dist: (v1End.x - v1.x) ** 2 + (v1End.y - v1.y) ** 2 }
+ for (const intersection of intersections) {
+ const dist = (intersection.x - v1.x) ** 2 + (intersection.y - v1.y) ** 2;
+ if (dist < best.dist) best = { x: intersection.x, y: intersection.y, dist: dist }
+ }
+ best.dist = Math.sqrt(best.dist)
+ return best;
+ },
+ getIntersections(v1, v1End, domain) {
+ const intersections = [];
+ for (const obj of domain) {
+ for (var i = 0; i < obj.vertices.length - 1; i++) {
+ results = simulation.checkLineIntersection(v1, v1End, obj.vertices[i], obj.vertices[i + 1]);
+ if (results.onLine1 && results.onLine2) intersections.push({ x: results.x, y: results.y });
+ }
+ results = simulation.checkLineIntersection(v1, v1End, obj.vertices[obj.vertices.length - 1], obj.vertices[0]);
+ if (results.onLine1 && results.onLine2) intersections.push({ x: results.x, y: results.y });
+ }
+ return intersections;
+ },
+ circleLoS(pos, radius) {
+ function allCircleLineCollisions(c, radius, domain) {
+ var lines = [];
+ for (const obj of domain) {
+ for (var i = 0; i < obj.vertices.length - 1; i++) lines.push(circleLineCollisions(obj.vertices[i], obj.vertices[i + 1], c, radius));
+ lines.push(circleLineCollisions(obj.vertices[obj.vertices.length - 1], obj.vertices[0], c, radius));
+ }
+ const collisionLines = [];
+ for (const line of lines) {
+ if (line.length == 2) {
+ // const distance1 = Math.sqrt((line[0].x - c.x) ** 2 + (line[0].y - c.y) ** 2)
+ // const angle1 = Math.atan2(line[0].y - c.y, line[0].x - c.x);
+ // const queryPoint1 = {
+ // x: Math.cos(angle1) * (distance1 - 1) + c.x,
+ // y: Math.sin(angle1) * (distance1 - 1) + c.y
+ // }
+ // const distance2 = Math.sqrt((line[1].x - c.x) ** 2 + (line[1].y - c.y) ** 2)
+ // const angle2 = Math.atan2(line[1].y - c.y, line[1].x - c.x);
+ // const queryPoint2 = {
+ // x: Math.cos(angle2) * (distance2 - 1) + c.x,
+ // y: Math.sin(angle2) * (distance2 - 1) + c.y
+ // }
+ collisionLines.push(line)
+ }
+ }
+
+ return collisionLines;
+ }
+
+ function circleLineCollisions(a, b, c, radius) {
+ // calculate distances
+ const angleOffset = Math.atan2(b.y - a.y, b.x - a.x);
+ const sideB = Math.sqrt((a.x - c.x) ** 2 + (a.y - c.y) ** 2);
+ const sideC = Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2);
+ const sideA = Math.sqrt((c.x - b.x) ** 2 + (c.y - b.y) ** 2);
+
+ // calculate the closest point on line AB to point C
+ const angleA = Math.acos((sideB ** 2 + sideC ** 2 - sideA ** 2) / (2 * sideB * sideC)) * (a.x - c.x) / -Math.abs(a.x - c.x)
+ const sideAD = Math.cos(angleA) * sideB;
+ const d = { // closest point
+ x: Math.cos(angleOffset) * sideAD + a.x,
+ y: Math.sin(angleOffset) * sideAD + a.y
+ }
+ const distance = Math.sqrt((d.x - c.x) ** 2 + (d.y - c.y) ** 2);
+ if (distance == radius) {
+ // tangent
+ return [d];
+ } else if (distance < radius) {
+ // secant
+ const angleOffset = Math.atan2(d.y - c.y, d.x - c.x);
+ const innerAngle = Math.acos(distance / radius);
+ const intersection1 = {
+ x: Math.cos(angleOffset + innerAngle) * radius + c.x,
+ y: Math.sin(angleOffset + innerAngle) * radius + c.y
+ }
+
+ const intersection2 = {
+ x: Math.cos(angleOffset - innerAngle) * radius + c.x,
+ y: Math.sin(angleOffset - innerAngle) * radius + c.y
+ }
+
+ const distance1 = {
+ a: Math.sqrt((intersection1.x - a.x) ** 2 + (intersection1.y - a.y) ** 2),
+ b: Math.sqrt((intersection1.x - b.x) ** 2 + (intersection1.y - b.y) ** 2)
+ }
+ const distance2 = {
+ a: Math.sqrt((intersection2.x - a.x) ** 2 + (intersection2.y - a.y) ** 2),
+ b: Math.sqrt((intersection2.x - b.x) ** 2 + (intersection2.y - b.y) ** 2)
+ }
+ const result = [];
+ if (Math.abs(sideC - (distance1.a + distance1.b)) < 0.01) {
+ result.push(intersection1);
+ } else {
+ if (distance1.a < distance1.b) {
+ if (sideB <= radius) result.push(a);
+ } else {
+ if (sideA <= radius) result.push(b)
+ }
+ }
+ if (Math.abs(sideC - (distance2.a + distance2.b)) < 0.01) {
+ result.push(intersection2);
+ } else {
+ if (distance2.a <= distance2.b) {
+ if (sideB <= radius) result.push(a);
+ } else {
+ if (sideA <= radius) result.push(b)
+ }
+ }
+
+ return result;
+ } else {
+ // no intersection
+ return [];
+ }
+ }
+
+ var vertices = [];
+ for (const obj of simulation.sight.intersectMap) {
+ for (var i = 0; i < obj.vertices.length; i++) {
+ const vertex = obj.vertices[i];
+ const angleToVertex = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ // const distanceToVertex = Math.sqrt((vertex.x - pos.x) ** 2 + (vertex.y - pos.y) ** 2);
+ // const queryPoint = { x: Math.cos(angleToVertex) * (distanceToVertex - 1) + pos.x, y: Math.sin(angleToVertex) * (distanceToVertex - 1) + pos.y }
+ const queryPoint = { x: Math.cos(angleToVertex + Math.PI) + vertex.x, y: Math.sin(angleToVertex + Math.PI) + vertex.y }
+
+ if (Matter.Query.ray(map, pos, queryPoint).length == 0) {
+ var distance = Math.sqrt((vertex.x - pos.x) ** 2 + (vertex.y - pos.y) ** 2);
+ var endPoint = { x: vertex.x, y: vertex.y }
+
+ if (distance > radius) {
+ const angle = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ endPoint = { x: Math.cos(angle) * radius + pos.x, y: Math.sin(angle) * radius + pos.y }
+ distance = radius
+ }
+
+ var best = simulation.sight.getIntersection(pos, endPoint, map);
+ if (best.dist >= distance) best = { x: endPoint.x, y: endPoint.y, dist: distance }
+ vertices.push(best)
+
+ var angle = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ endPoint = { x: Math.cos(angle + 0.001) * radius + pos.x, y: Math.sin(angle + 0.001) * radius + pos.y }
+ best = simulation.sight.getIntersection(pos, endPoint, map);
+
+ if (best.dist >= radius) best = { x: endPoint.x, y: endPoint.y, dist: radius }
+ vertices.push(best)
+
+ angle = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ endPoint = { x: Math.cos(angle - 0.001) * radius + pos.x, y: Math.sin(angle - 0.001) * radius + pos.y }
+
+ best = simulation.sight.getIntersection(pos, endPoint, map);
+ if (best.dist >= radius) best = { x: endPoint.x, y: endPoint.y, dist: radius }
+ vertices.push(best)
+ }
+ }
+ }
+
+ const outerCollisions = allCircleLineCollisions(pos, radius, map);
+ const circleCollisions = [];
+ for (const line of outerCollisions) {
+ for (const vertex of line) {
+ // console.log('hi')
+ const distance = Math.sqrt((vertex.x - pos.x) ** 2 + (vertex.y - pos.y) ** 2)
+ const angle = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ // const queryPoint = {
+ // x: Math.cos(angle) * (distance - 1) + pos.x,
+ // y: Math.sin(angle) * (distance - 1) + pos.y
+ // }
+ const queryPoint = { x: Math.cos(angle + Math.PI) + vertex.x, y: Math.sin(angle + Math.PI) + vertex.y }
+
+ if (Math.abs(distance - radius) < 1 && Matter.Query.ray(map, pos, queryPoint).length == 0) circleCollisions.push(vertex)
+ }
+ }
+ for (var i = 0; i < circleCollisions.length; i++) {
+ const vertex = circleCollisions[i];
+ var nextIndex = i + 1;
+ if (nextIndex == circleCollisions.length) nextIndex = 0;
+ const nextVertex = circleCollisions[nextIndex];
+ const angle1 = Math.atan2(vertex.y - pos.y, vertex.x - pos.x);
+ const angle2 = Math.atan2(nextVertex.y - pos.y, nextVertex.x - pos.x);
+ var newAngle;
+ if (Math.abs(angle1) > Math.PI / 2 && Math.abs(angle2) > Math.PI / 2 && angle1 / Math.abs(angle1) != angle2 / Math.abs(angle2)) {
+ // if the arc between the to points crosses over the left side (+/- pi radians)
+ const newAngle1 = (Math.PI - Math.abs(angle1)) * (angle1 / Math.abs(angle1));
+ const newAngle2 = (Math.PI - Math.abs(angle2)) * (angle2 / Math.abs(angle2));
+ newAngle = (newAngle1 + newAngle2) / 2;
+ var multiplier;
+ if (newAngle == 0) {
+ multiplier = 1;
+ } else {
+ multiplier = newAngle / Math.abs(newAngle);
+ }
+ newAngle = Math.PI * multiplier - newAngle * multiplier;
+ test = true;
+ } else {
+ newAngle = (angle1 + angle2) / 2;
+ }
+
+ // shoot ray between them
+ var endPoint = { x: Math.cos(newAngle) * radius + pos.x, y: Math.sin(newAngle) * radius + pos.y }
+ var best = simulation.sight.getIntersection(pos, endPoint, map);
+ vertices.push(vertex);
+ if (best.dist <= radius) vertices.push({ x: best.x, y: best.y })
+ }
+ vertices.sort((a, b) => Math.atan2(a.y - pos.y, a.x - pos.x) - Math.atan2(b.y - pos.y, b.x - pos.x));
+ return vertices;
+ },
+ },
+ draw: {
+ // powerUp() { //is set by Bayesian tech
+ // // ctx.globalAlpha = 0.4 * Math.sin(m.cycle * 0.15) + 0.6;
+ // // for (let i = 0, len = powerUp.length; i < len; ++i) {
+ // // ctx.beginPath();
+ // // ctx.arc(powerUp[i].position.x, powerUp[i].position.y, powerUp[i].size, 0, 2 * Math.PI);
+ // // ctx.fillStyle = powerUp[i].color;
+ // // ctx.fill();
+ // // }
+ // // ctx.globalAlpha = 1;
+ // },
+ // powerUpNormal() { //back up in case power up draw gets changed
+ // ctx.globalAlpha = 0.4 * Math.sin(m.cycle * 0.15) + 0.6;
+ // for (let i = 0, len = powerUp.length; i < len; ++i) {
+ // ctx.beginPath();
+ // ctx.arc(powerUp[i].position.x, powerUp[i].position.y, powerUp[i].size, 0, 2 * Math.PI);
+ // ctx.fillStyle = powerUp[i].color;
+ // ctx.fill();
+ // }
+ // ctx.globalAlpha = 1;
+ // },
+ // powerUpBonus() { //draws crackle effect for bonus power ups
+ // ctx.globalAlpha = 0.4 * Math.sin(m.cycle * 0.15) + 0.6;
+ // for (let i = 0, len = powerUp.length; i < len; ++i) {
+ // ctx.beginPath();
+ // ctx.arc(powerUp[i].position.x, powerUp[i].position.y, powerUp[i].size, 0, 2 * Math.PI);
+ // ctx.fillStyle = powerUp[i].color;
+ // ctx.fill();
+ // }
+ // ctx.globalAlpha = 1;
+ // for (let i = 0, len = powerUp.length; i < len; ++i) {
+ // if (powerUp[i].isDuplicated && Math.random() < 0.1) {
+ // //draw electricity
+ // const mag = 5 + powerUp[i].size / 5
+ // let unit = Vector.rotate({
+ // x: mag,
+ // y: mag
+ // }, 2 * Math.PI * Math.random())
+ // let path = {
+ // x: powerUp[i].position.x + unit.x,
+ // y: powerUp[i].position.y + unit.y
+ // }
+ // ctx.beginPath();
+ // ctx.moveTo(path.x, path.y);
+ // for (let i = 0; i < 6; i++) {
+ // unit = Vector.rotate(unit, 3 * (Math.random() - 0.5))
+ // path = Vector.add(path, unit)
+ // ctx.lineTo(path.x, path.y);
+ // }
+ // ctx.lineWidth = 0.5 + 2 * Math.random();
+ // ctx.strokeStyle = "#000"
+ // ctx.stroke();
+ // }
+ // }
+ // },
+
+ // map: function() {
+ // ctx.beginPath();
+ // for (let i = 0, len = map.length; i < len; ++i) {
+ // let vertices = map[i].vertices;
+ // ctx.moveTo(vertices[0].x, vertices[0].y);
+ // for (let j = 1; j < vertices.length; j += 1) {
+ // ctx.lineTo(vertices[j].x, vertices[j].y);
+ // }
+ // ctx.lineTo(vertices[0].x, vertices[0].y);
+ // }
+ // ctx.fillStyle = "#444";
+ // ctx.fill();
+ // },
+ mapPath: null, //holds the path for the map to speed up drawing
+ setPaths() {
+ //runs at each new level to store the path for the map since the map doesn't change
+ simulation.draw.mapPath = new Path2D();
+ for (let i = 0, len = map.length; i < len; ++i) {
+ let vertices = map[i].vertices;
+ simulation.draw.mapPath.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j += 1) {
+ simulation.draw.mapPath.lineTo(vertices[j].x, vertices[j].y);
+ }
+ simulation.draw.mapPath.lineTo(vertices[0].x, vertices[0].y);
+ }
+ },
+ lineOfSightPrecalculation() {
+ simulation.sight.intersectMap = [];
+ for (var i = 0; i < map.length; i++) {
+ const obj = map[i];
+ const newVertices = [];
+ const restOfMap = [...map].slice(0, i).concat([...map].slice(i + 1))
+ for (var j = 0; j < obj.vertices.length - 1; j++) {
+ var intersections = simulation.sight.getIntersections(obj.vertices[j], obj.vertices[j + 1], restOfMap);
+ newVertices.push(obj.vertices[j]);
+ for (const vertex of intersections) newVertices.push({ x: vertex.x, y: vertex.y });
+ }
+ intersections = simulation.sight.getIntersections(obj.vertices[obj.vertices.length - 1], obj.vertices[0], restOfMap);
+ newVertices.push(obj.vertices[obj.vertices.length - 1]);
+ for (const vertex of intersections) newVertices.push({ x: vertex.x, y: vertex.y });
+ //draw the vertices as black circles for debugging
+ // for (const vertex of newVertices) {
+ // ctx.beginPath();
+ // ctx.moveTo(vertex.x, vertex.y);
+ // ctx.arc(vertex.x, vertex.y, 10, 0, 2 * Math.PI);
+ // ctx.fillStyle = '#000';
+ // ctx.fill()
+ // }
+ simulation.sight.intersectMap.push({ vertices: newVertices });
+ }
+ },
+ drawMapPath() { },
+ drawMapPathDefault() {
+ ctx.fillStyle = color.map;
+ ctx.fill(simulation.draw.mapPath);
+ },
+ drawMapSight() {
+ if (!simulation.isTimeSkipping) {
+ const pos = m.pos
+ const radius = 4000
+ const vertices = simulation.sight.circleLoS(pos, radius);
+ if (vertices.length) {
+ ctx.beginPath();
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (var i = 1; i < vertices.length; i++) {
+ var currentDistance = Math.sqrt((vertices[i - 1].x - pos.x) ** 2 + (vertices[i - 1].y - pos.y) ** 2);
+ var newDistance = Math.sqrt((vertices[i].x - pos.x) ** 2 + (vertices[i].y - pos.y) ** 2);
+ if (Math.abs(currentDistance - radius) < 1 && Math.abs(newDistance - radius) < 1) {
+ const currentAngle = Math.atan2(vertices[i - 1].y - pos.y, vertices[i - 1].x - pos.x);
+ const newAngle = Math.atan2(vertices[i].y - pos.y, vertices[i].x - pos.x);
+ ctx.arc(pos.x, pos.y, radius, currentAngle, newAngle);
+ } else {
+ ctx.lineTo(vertices[i].x, vertices[i].y)
+ }
+ }
+ newDistance = Math.sqrt((vertices[0].x - pos.x) ** 2 + (vertices[0].y - pos.y) ** 2);
+ currentDistance = Math.sqrt((vertices[vertices.length - 1].x - pos.x) ** 2 + (vertices[vertices.length - 1].y - pos.y) ** 2);
+ if (Math.abs(currentDistance - radius) < 1 && Math.abs(newDistance - radius) < 1) {
+ const currentAngle = Math.atan2(vertices[vertices.length - 1].y - pos.y, vertices[vertices.length - 1].x - pos.x);
+ const newAngle = Math.atan2(vertices[0].y - pos.y, vertices[0].x - pos.x);
+ ctx.arc(pos.x, pos.y, radius, currentAngle, newAngle);
+ } else {
+ ctx.lineTo(vertices[0].x, vertices[0].y)
+ }
+
+ // outline map edges, best with lighter colored document.body.style.backgroundColor
+ ctx.strokeStyle = "#000";
+ ctx.lineWidth = 5;
+ ctx.stroke(simulation.draw.mapPath);
+
+ ctx.globalCompositeOperation = "destination-in";
+ ctx.fillStyle = "#000";
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over";
+
+ // make map visible
+ // ctx.fill(simulation.draw.mapPath);
+ // ctx.fillStyle = "#000";
+
+ ctx.clip(); //this doesn't seem to be required, but it helps with performance, probably stops the canvas context from drawing the whole map
+ }
+ }
+ },
+ body() {
+ ctx.beginPath();
+ for (let i = 0, len = body.length; i < len; ++i) {
+ let vertices = body[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ }
+ ctx.lineWidth = 2;
+ ctx.fillStyle = color.block;
+ ctx.fill();
+ ctx.strokeStyle = color.blockS;
+ ctx.stroke();
+ },
+ cons() {
+ ctx.beginPath();
+ for (let i = 0, len = cons.length; i < len; ++i) {
+ ctx.moveTo(cons[i].pointA.x, cons[i].pointA.y);
+ // ctx.lineTo(cons[i].bodyB.position.x, cons[i].bodyB.position.y);
+ ctx.lineTo(cons[i].bodyB.position.x + cons[i].pointB.x, cons[i].bodyB.position.y + cons[i].pointB.y);
+ }
+ for (let i = 0, len = consBB.length; i < len; ++i) {
+ ctx.moveTo(consBB[i].bodyA.position.x, consBB[i].bodyA.position.y);
+ ctx.lineTo(consBB[i].bodyB.position.x, consBB[i].bodyB.position.y);
+ }
+ ctx.lineWidth = 2;
+ // ctx.strokeStyle = "#999";
+ ctx.strokeStyle = "rgba(0,0,0,0.15)";
+ ctx.stroke();
+ },
+ wireFrame() {
+ // ctx.textAlign = "center";
+ // ctx.textBaseline = "middle";
+ // ctx.fillStyle = "#999";
+ const bodies = Composite.allBodies(engine.world);
+ ctx.beginPath();
+ for (let i = 0; i < bodies.length; ++i) {
+ //ctx.fillText(bodies[i].id,bodies[i].position.x,bodies[i].position.y); //shows the id of every body
+ let vertices = bodies[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ }
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = "#000";
+ ctx.stroke();
+ },
+ testing() {
+ //jump
+ ctx.beginPath();
+ let bodyDraw = jumpSensor.vertices;
+ ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y);
+ for (let j = 1; j < bodyDraw.length; ++j) {
+ ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y);
+ }
+ ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y);
+ ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
+ ctx.fill();
+ // ctx.strokeStyle = "#000";
+ // ctx.stroke();
+ //main body
+ ctx.beginPath();
+ bodyDraw = playerBody.vertices;
+ ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y);
+ for (let j = 1; j < bodyDraw.length; ++j) {
+ ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y);
+ }
+ ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y);
+ ctx.fillStyle = "rgba(0, 255, 255, 0.25)";
+ ctx.fill();
+ // ctx.stroke();
+ //head
+ ctx.beginPath();
+ bodyDraw = playerHead.vertices;
+ ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y);
+ for (let j = 1; j < bodyDraw.length; ++j) {
+ ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y);
+ }
+ ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y);
+ ctx.fillStyle = "rgba(255, 255, 0, 0.4)";
+ ctx.fill();
+ // ctx.stroke();
+ //head sensor
+ ctx.beginPath();
+ bodyDraw = headSensor.vertices;
+ ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y);
+ for (let j = 1; j < bodyDraw.length; ++j) {
+ ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y);
+ }
+ ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y);
+ ctx.fillStyle = "rgba(0, 0, 255, 0.25)";
+ ctx.fill();
+ // ctx.stroke();
+ }
+ },
+ checkLineIntersection(v1, v1End, v2, v2End) {
+ // if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
+ let denominator, a, b, numerator1, numerator2;
+ let result = {
+ x: null,
+ y: null,
+ onLine1: false,
+ onLine2: false
+ };
+ denominator = (v2End.y - v2.y) * (v1End.x - v1.x) - (v2End.x - v2.x) * (v1End.y - v1.y);
+ if (denominator == 0) {
+ return result;
+ }
+ a = v1.y - v2.y;
+ b = v1.x - v2.x;
+ numerator1 = (v2End.x - v2.x) * a - (v2End.y - v2.y) * b;
+ numerator2 = (v1End.x - v1.x) * a - (v1End.y - v1.y) * b;
+ a = numerator1 / denominator;
+ b = numerator2 / denominator;
+
+ // if we cast these lines infinitely in both directions, they intersect here:
+ result.x = v1.x + a * (v1End.x - v1.x);
+ result.y = v1.y + a * (v1End.y - v1.y);
+ // if line1 is a segment and line2 is infinite, they intersect if:
+ if (a > 0 && a < 1) result.onLine1 = true;
+ // if line2 is a segment and line1 is infinite, they intersect if:
+ if (b > 0 && b < 1) result.onLine2 = true;
+ // if line1 and line2 are segments, they intersect if both of the above are true
+ return result;
+ },
+ constructMouseDownPosition: {
+ x: 0,
+ y: 0
+ },
+ constructMapString: [],
+ constructCycle() {
+ if (simulation.isConstructionMode && simulation.constructMouseDownPosition) {
+ function round(num, round = 25) {
+ return Math.ceil(num / round) * round;
+ }
+ const x = round(simulation.constructMouseDownPosition.x)
+ const y = round(simulation.constructMouseDownPosition.y)
+ const dx = Math.max(25, round(simulation.mouseInGame.x) - x)
+ const dy = Math.max(25, round(simulation.mouseInGame.y) - y)
+
+ ctx.strokeStyle = "#000"
+ ctx.lineWidth = 2;
+ ctx.strokeRect(x, y, dx, dy);
+ }
+ },
+ enableConstructMode() {
+ level.isProcedural = false //this is set to be true in levels like labs that need x+ and y+ in front of positions
+ simulation.isConstructionMode = true;
+ simulation.isHorizontalFlipped = false;
+ simulation.isAutoZoom = false;
+ simulation.zoomScale = 2600;
+ simulation.setZoom();
+
+ document.body.addEventListener("mouseup", (e) => {
+ if (simulation.testing && simulation.constructMouseDownPosition) {
+ function round(num, round = 25) {
+ return Math.ceil(num / round) * round;
+ }
+ //clean up positions
+ const x = round(simulation.constructMouseDownPosition.x)
+ const y = round(simulation.constructMouseDownPosition.y)
+ const dx = Math.max(25, round(simulation.mouseInGame.x) - x)
+ const dy = Math.max(25, round(simulation.mouseInGame.y) - y)
+ // console.log(e.button)
+ if (e.button === 1) {
+ if (level.isProcedural) {
+ simulation.outputMapString(`spawn.randomMob(x+${x}, ${y}, 0);\n`);
+ } else {
+ simulation.outputMapString(`spawn.randomMob(${x}, ${y}, 0);\n`);
+ }
+ } else if (e.button === 4) {
+ simulation.outputMapString(`${Math.floor(simulation.constructMouseDownPosition.x)}, ${Math.floor(simulation.constructMouseDownPosition.y)}`);
+ } else if (simulation.mouseInGame.x > simulation.constructMouseDownPosition.x && simulation.mouseInGame.y > simulation.constructMouseDownPosition.y) { //make sure that the width and height are positive
+ if (e.button === 0) { //add map
+ if (level.isProcedural) {
+ simulation.outputMapString(`spawn.mapRect(x+${x}, ${y}, ${dx}, ${dy});\n`);
+ } else {
+ simulation.outputMapString(`spawn.mapRect(${x}, ${y}, ${dx}, ${dy});\n`);
+ }
+ //see map in world
+ spawn.mapRect(x, y, dx, dy);
+ len = map.length - 1
+ map[len].collisionFilter.category = cat.map;
+ map[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(map[len], true); //make static
+ Composite.add(engine.world, map[len]); //add to world
+ simulation.draw.setPaths() //update map graphics
+ } else if (e.button === 2) { //add body
+ if (level.isProcedural) {
+ simulation.outputMapString(`spawn.bodyRect(x+${x}, ${y}, ${dx}, ${dy});\n`);
+ } else {
+ simulation.outputMapString(`spawn.bodyRect(${x}, ${y}, ${dx}, ${dy});\n`);
+ }
+ //see map in world
+ spawn.bodyRect(x, y, dx, dy);
+ }
+ }
+ }
+ simulation.constructMouseDownPosition.x = undefined
+ simulation.constructMouseDownPosition.y = undefined
+ });
+ simulation.constructMouseDownPosition.x = undefined
+ simulation.constructMouseDownPosition.y = undefined
+ document.body.addEventListener("mousedown", (e) => {
+ if (simulation.testing) {
+ simulation.constructMouseDownPosition.x = simulation.mouseInGame.x
+ simulation.constructMouseDownPosition.y = simulation.mouseInGame.y
+ }
+ });
+
+ //undo last element added after you press z
+ document.body.addEventListener("keydown", (e) => { // e.keyCode z=90 m=77 b=66 shift = 16 c = 67
+ if (simulation.testing && e.keyCode === 90 && simulation.constructMapString.length) {
+ if (simulation.constructMapString[simulation.constructMapString.length - 1][6] === 'm') { //remove map from current level
+ const index = map.length - 1
+ Matter.Composite.remove(engine.world, map[index]);
+ map.splice(index, 1);
+ simulation.draw.setPaths() //update map graphics
+ } else if (simulation.constructMapString[simulation.constructMapString.length - 1][6] === 'b') { //remove body from current level
+ const index = body.length - 1
+ Matter.Composite.remove(engine.world, body[index]);
+ body.splice(index, 1);
+ }
+ simulation.constructMapString.pop();
+ simulation.outputMapString();
+ }
+ });
+ },
+ outputMapString(string) {
+ if (string) simulation.constructMapString.push(string) //store command as a string in the next element of an array
+ let out = "" //combine set of map strings to one string
+ let outHTML = ""
+ for (let i = 0, len = simulation.constructMapString.length; i < len; i++) {
+ out += simulation.constructMapString[i];
+ outHTML += "" + simulation.constructMapString[i] + "
"
+ }
+ console.log(out)
+ navigator.clipboard.writeText(out).then(function () {
+ /* clipboard successfully set */
+ }, function () {
+ /* clipboard write failed */
+ console.log('copy failed')
+ });
+ document.getElementById("construct").innerHTML = outHTML
+ },
+ // copyToClipBoard(value) {
+ // // Create a fake textarea
+ // const textAreaEle = document.createElement('textarea');
+
+ // // Reset styles
+ // textAreaEle.style.border = '0';
+ // textAreaEle.style.padding = '0';
+ // textAreaEle.style.margin = '0';
+
+ // // Set the absolute position
+ // // User won't see the element
+ // textAreaEle.style.position = 'absolute';
+ // textAreaEle.style.left = '-9999px';
+ // textAreaEle.style.top = `0px`;
+
+ // // Set the value
+ // textAreaEle.value = value
+
+ // // Append the textarea to body
+ // document.body.appendChild(textAreaEle);
+
+ // // Focus and select the text
+ // textAreaEle.focus();
+ // textAreaEle.select();
+
+ // // Execute the "copy" command
+ // try {
+ // document.execCommand('copy');
+ // } catch (err) {
+ // // Unable to copy
+ // console.log(err)
+ // } finally {
+ // // Remove the textarea
+ // document.body.removeChild(textAreaEle);
+ // }
+ // },
+};
\ No newline at end of file
diff --git a/ngon/js/spawn.js b/ngon/js/spawn.js
new file mode 100644
index 00000000..c03b02d8
--- /dev/null
+++ b/ngon/js/spawn.js
@@ -0,0 +1,8509 @@
+//main object for spawning things in a level
+const spawn = {
+ nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture"],
+ // other bosses: suckerBoss, laserBoss, tetherBoss, bounceBoss, sprayBoss, mineBoss, hopMomBoss //these need a particular level to work so they are not included in the random pool
+ randomBossList: [
+ "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss",
+ "powerUpBoss", "powerUpBossBaby", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss",
+ "snakeSpitBoss", "laserBombingBoss", "blockBoss", "revolutionBoss", "slashBoss", "shieldingBoss",
+ "timeSkipBoss", "dragonFlyBoss", "beetleBoss", "sneakBoss", "mantisBoss"
+ ],
+ bossTypeSpawnOrder: [], //preset list of boss names calculated at the start of a run by the randomSeed
+ bossTypeSpawnIndex: 0, //increases as the boss type cycles
+ randomLevelBoss(x, y, options = []) {
+ if (options.length === 0) {
+ const boss = spawn.bossTypeSpawnOrder[spawn.bossTypeSpawnIndex++ % spawn.bossTypeSpawnOrder.length]
+ spawn[boss](x, y)
+ } else {
+ spawn[options[Math.floor(Math.random() * options.length)]](x, y)
+ }
+ },
+ pickList: ["starter", "starter"],
+ fullPickList: [
+ "slasher", "slasher", "slasher2", "slasher3",
+ "flutter", "flutter", "flutter",
+ "hopper", "hopper", "hopper",
+ "stabber", "stabber", "stabber",
+ "springer", "springer", "springer",
+ "shooter", "shooter",
+ "grenadier", "grenadier",
+ "striker", "striker",
+ "laser", "laser",
+ "pulsar", "pulsar",
+ "sneaker", "launcher", "launcherOne", "exploder", "sucker", "sniper", "spinner", "grower", "beamer", "spawner", "ghoster", "focuser"
+ ],
+ mobTypeSpawnOrder: [], //preset list of mob names calculated at the start of a run by the randomSeed
+ mobTypeSpawnIndex: 0, //increases as the mob type cycles
+ allowedGroupList: ["spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter", "launcher", "launcherOne", "stabber", "sniper", "pulsar", "grenadier", "slasher", "flutter"],
+ setSpawnList() { //this is run at the start of each new level to determine the possible mobs for the level
+ spawn.pickList.splice(0, 1);
+ const push = spawn.mobTypeSpawnOrder[spawn.mobTypeSpawnIndex++ % spawn.mobTypeSpawnOrder.length]
+ spawn.pickList.push(push);
+ // if (spawn.mobTypeSpawnIndex > spawn.mobTypeSpawnOrder.length) spawn.mobTypeSpawnIndex = 0
+ //each level has 2 mobs: one new mob and one from the last level
+ // spawn.pickList.splice(0, 1);
+ // spawn.pickList.push(spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]);
+ },
+ spawnChance(chance) {
+ return Math.random() < chance + 0.07 * simulation.difficulty && mob.length < -1 + 16 * Math.log10(simulation.difficulty + 1)
+ },
+ randomMob(x, y, chance = 1) {
+ if (spawn.spawnChance(chance) || chance === Infinity) {
+ const pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](x, y);
+ }
+ if (tech.isDuplicateMobs && Math.random() < tech.duplicationChance()) {
+ const pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](x, y);
+ }
+ },
+ randomSmallMob(x, y,
+ num = Math.max(Math.min(Math.round(Math.random() * simulation.difficulty * 0.2), 4), 0),
+ size = 16 + Math.ceil(Math.random() * 15),
+ chance = 1) {
+ if (spawn.spawnChance(chance)) {
+ for (let i = 0; i < num; ++i) {
+ const pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](x + Math.round((Math.random() - 0.5) * 20) + i * size * 2.5, y + Math.round((Math.random() - 0.5) * 20), size);
+ }
+ }
+ if (tech.isDuplicateMobs && Math.random() < tech.duplicationChance()) {
+ for (let i = 0; i < num; ++i) {
+ const pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](x + Math.round((Math.random() - 0.5) * 20) + i * size * 2.5, y + Math.round((Math.random() - 0.5) * 20), size);
+ }
+ }
+ },
+ randomGroup(x, y, chance = 1) {
+ if (spawn.spawnChance(chance) && simulation.difficulty > 2 || chance === Infinity) {
+ //choose from the possible picklist
+ let pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ //is the pick able to be a group?
+ let canBeGroup = false;
+ for (let i = 0, len = spawn.allowedGroupList.length; i < len; ++i) {
+ if (spawn.allowedGroupList[i] === pick) {
+ canBeGroup = true;
+ break;
+ }
+ }
+ if (canBeGroup) {
+ if (Math.random() < 0.55) {
+ spawn.nodeGroup(x, y, pick);
+ } else {
+ spawn.lineGroup(x, y, pick);
+ }
+ } else {
+ if (Math.random() < 0.1) {
+ spawn[pick](x, y, 90 + Math.random() * 40); //one extra large mob
+ spawn.spawnOrbitals(mob[mob.length - 1], mob[mob.length - 1].radius + 50 + 200 * Math.random(), 1)
+ // } else if (Math.random() < 0.35) {
+ // spawn.blockGroup(x, y) //hidden grouping blocks
+ } else {
+ pick = (Math.random() < 0.5) ? "randomList" : "random";
+ if (Math.random() < 0.55) {
+ spawn.nodeGroup(x, y, pick);
+ } else {
+ spawn.lineGroup(x, y, pick);
+ }
+ }
+ }
+ }
+ },
+ secondaryBossThreshold: 22,
+ secondaryBossChance(x, y) {
+ // if (tech.isDuplicateMobs && Math.random() < tech.duplicationChance()) {
+ // tech.isScaleMobsWithDuplication = true
+ // spawn.randomLevelBoss(x, y);
+ // tech.isScaleMobsWithDuplication = false
+ // return true
+ // } else if (tech.isResearchBoss) {
+ // if (powerUps.research.count > 2) {
+ // powerUps.research.changeRerolls(-3)
+ // simulation.makeTextLog(`m .research -= 3 ${powerUps.research.count}`)
+ // } else {
+ // tech.addJunkTechToPool(0.49)
+ // }
+ // spawn.randomLevelBoss(x, y);
+ // return true
+ // }
+ if (simulation.difficulty > spawn.secondaryBossThreshold) { //starts on hard mode level 6, level 12 on easy, level 4 on why?
+ spawn.randomLevelBoss(x, y);
+ } else {
+ return false
+ }
+ },
+ //mob templates *********************************************************************************************
+ //***********************************************************************************************************
+ MACHO(x = m.pos.x, y = m.pos.y) { //immortal mob that follows player //if you have the tech it spawns at start of every level at the player
+ mobs.spawn(x, y, 3, 0.1, "transparent");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent"
+ me.isShielded = true; //makes it immune to damage
+ me.leaveBody = false;
+ me.isBadTarget = true;
+ me.isUnblockable = true;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.collisionFilter.category = 0;
+ me.collisionFilter.mask = 0; //cat.player //| cat.body
+ me.chaseSpeed = 3.3
+ me.isMACHO = true;
+ me.frictionAir = 0.006
+ me.onDeath = function () {
+ tech.isHarmMACHO = false;
+ }
+ me.do = function () {
+ if (!simulation.isTimeSkipping) {
+ const sine = Math.sin(simulation.cycle * 0.015)
+ this.radius = 55 * tech.isDarkStar + 370 * (1 + 0.1 * sine)
+ //chase player
+ const sub = Vector.sub(player.position, this.position)
+ const mag = Vector.magnitude(sub)
+ // follow physics
+ // Matter.Body.setVelocity(this, { x: 0, y: 0 });
+ // const where = Vector.add(this.position, Vector.mult(Vector.normalise(sub), this.chaseSpeed))
+ // if (mag > 10) Matter.Body.setPosition(this, { x: where.x, y: where.y });
+
+ //realistic physics
+ const force = Vector.mult(Vector.normalise(sub), 0.000000003)
+ this.force.x += force.x
+ this.force.y += force.y
+
+
+ if (mag < this.radius) { //buff to player when inside radius
+ tech.isHarmMACHO = true;
+
+ //draw halo
+ ctx.strokeStyle = "rgba(80,120,200,0.2)" //"rgba(255,255,0,0.2)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})`
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 36, 0, 2 * Math.PI);
+ ctx.lineWidth = 10;
+ ctx.stroke();
+ // ctx.strokeStyle = "rgba(255,255,0,0.17)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})`
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, this.radius, 0, 2 * Math.PI);
+ // ctx.lineWidth = 30;
+ // ctx.stroke();
+ } else {
+ tech.isHarmMACHO = false;
+ }
+ //draw outline
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, this.radius + 15, 0, 2 * Math.PI);
+ ctx.strokeStyle = "#000"
+ ctx.lineWidth = 1;
+ ctx.stroke();
+ if (tech.isDarkStar && !m.isCloak) { //&& !m.isBodiesAsleep
+ ctx.fillStyle = "rgba(10,0,40,0.4)"
+ ctx.fill()
+ //damage mobs
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (mob[i].alive && !mob[i].isShielded) {
+ if (Vector.magnitude(Vector.sub(this.position, mob[i].position)) - mob[i].radius < this.radius) {
+ mob[i].damage(0.02 * m.dmgScale);
+ // mob[i].locatePlayer();//
+
+ simulation.drawList.push({ //add dmg to draw queue
+ x: mob[i].position.x,
+ y: mob[i].position.y,
+ radius: mob[i].radius + 8,
+ color: `rgba(10,0,40,0.1)`, // random hue, but not red
+ time: 4
+ });
+ }
+ }
+ }
+ }
+ //draw growing and fading out ring around the arc
+ ctx.beginPath();
+ const rate = 150
+ const r = simulation.cycle % rate
+ ctx.arc(this.position.x, this.position.y, 15 + this.radius + 0.3 * r, 0, 2 * Math.PI);
+ ctx.strokeStyle = `rgba(0,0,0,${0.5 * Math.max(0, 1 - 1.4 * r / rate)})`
+ ctx.stroke();
+ }
+ }
+ },
+ WIMP(x = level.exit.x + tech.wimpCount * 200 * (Math.random() - 0.5), y = level.exit.y + tech.wimpCount * 200 * (Math.random() - 0.5)) { //immortal mob that follows player //if you have the tech it spawns at start of every level at the exit
+ mobs.spawn(x, y, 3, 0.1, "transparent");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent"
+ me.isShielded = true; //makes it immune to damage
+ me.leaveBody = false;
+ me.isBadTarget = true;
+ me.isUnblockable = true;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.collisionFilter.category = 0;
+ me.collisionFilter.mask = 0; //cat.player //| cat.body
+ me.chaseSpeed = 1.2 + 2.3 * Math.random()
+
+ me.awake = function () {
+ //chase player
+ const sub = Vector.sub(player.position, this.position)
+ const where = Vector.add(this.position, Vector.mult(Vector.normalise(sub), this.chaseSpeed))
+
+ Matter.Body.setPosition(this, { //hold position
+ x: where.x,
+ y: where.y
+ });
+ Matter.Body.setVelocity(this, { x: 0, y: 0 });
+
+ //aoe damage to player
+ if (m.immuneCycle < m.cycle && Vector.magnitude(Vector.sub(player.position, this.position)) < this.radius) {
+ const DRAIN = tech.isRadioactiveResistance ? 0.05 * 0.25 : 0.05
+ if (m.energy > DRAIN) {
+ if (m.immuneCycle < m.cycle) m.energy -= DRAIN
+ } else {
+ m.energy = 0;
+ m.damage((tech.isRadioactiveResistance ? 0.005 * 0.25 : 0.005) * simulation.dmgScale)
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: this.radius,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ }
+ }
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, this.radius, 0, 2 * Math.PI);
+ ctx.fillStyle = `rgba(25,139,170,${0.2 + 0.12 * Math.random()})`;
+ ctx.fill();
+ this.radius = 100 * (1 + 0.25 * Math.sin(simulation.cycle * 0.03))
+ }
+ me.do = function () { //wake up after the player moves
+ if (player.speed > 1 && !m.isCloak) {
+ if (this.distanceToPlayer() < 500) {
+ const unit = Vector.rotate({ x: 1, y: 0 }, Math.random() * 6.28)
+ Matter.Body.setPosition(this, Vector.add(player.position, Vector.mult(unit, 2000)))
+ }
+ setTimeout(() => {
+ this.do = this.awake;
+ }, 1000 * Math.random());
+ }
+ this.checkStatus();
+ };
+ },
+ finalBoss(x, y, radius = 300) {
+ mobs.spawn(x, y, 6, radius, "rgb(150,150,255)");
+ let me = mob[mob.length - 1];
+ setTimeout(() => { //fix mob in place, but allow rotation
+ me.constraint = Constraint.create({
+ pointA: { x: me.position.x, y: me.position.y },
+ bodyB: me,
+ stiffness: 1,
+ damping: 1
+ });
+ Composite.add(engine.world, me.constraint);
+ }, 1000); //add in a delay in case the level gets flipped left right
+ me.isBoss = true;
+ me.isFinalBoss = true;
+ me.frictionAir = 0.01;
+ me.memory = Infinity;
+ me.locatePlayer();
+ me.hasRunDeathScript = false
+ me.cycle = 1;
+
+ Matter.Body.setDensity(me, 0.2); //extra dense //normal is 0.001 //makes effective life much larger
+ me.damageReduction = 0.14
+ me.startingDamageReduction = me.damageReduction
+ me.nextHealthThreshold = 0.999
+ me.invulnerableCount = 0
+ me.isInvulnerable = false
+ me.totalModes = 0
+ me.lastDamageCycle = 0
+ me.onDamage = function () {
+ this.lastDamageCycle = this.cycle
+ if (this.health < this.nextHealthThreshold) {
+ if (this.health === 1) me.cycle = 1; //reset fight
+ this.health = this.nextHealthThreshold - 0.01
+ this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
+ this.invulnerableCount = 220 + 10 * simulation.difficultyMode //how long does invulnerable time last
+ this.isInvulnerable = true
+ this.damageReduction = 0
+ }
+ };
+ me.invulnerable = function () {
+ if (this.isInvulnerable) {
+ this.invulnerableCount--
+ if (this.invulnerableCount < 0) {
+ this.isInvulnerable = false
+ this.damageReduction = this.startingDamageReduction
+ this.pushAway();
+ this.mode[this.totalModes].enter() //enter new mode
+ this.totalModes++
+ //spawn 6 mobs
+ me.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]; //fire a bullet from each vertex
+ for (let i = 0; i < 6; i++) me.spawnMobs(i)
+
+ level.newLevelOrPhase() //run some new level tech effects
+ }
+ ctx.beginPath(); //draw invulnerable
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 15 + 6 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ ctx.fillStyle = `rgba(255,255,255,${Math.min(1, 120 / (this.invulnerableCount + 60))})`;
+ ctx.fill()
+ }
+ }
+ me.damageReductionDecay = function () { //slowly make the boss take more damage over time //damageReduction resets with each invulnerability phase
+ if (!(me.cycle % 60) && this.lastDamageCycle + 240 > this.cycle) this.damageReduction *= 1.04 //only decay once a second //only decay if the player has done damage in the last 4 seconds
+ }
+ me.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]
+ me.spawnMobs = function (index = 0) {
+ const vertex = me.vertices[index]
+ const unit = Vector.normalise(Vector.sub(me.position, vertex))
+ const where = Vector.add(vertex, Vector.mult(unit, -30))
+ spawn[me.mobType](where.x + 50 * (Math.random() - 0.5), where.y + 50 * (Math.random() - 0.5));
+ const velocity = Vector.mult(Vector.perp(unit), -10) //give the mob a rotational velocity as if they were attached to a vertex
+ Matter.Body.setVelocity(mob[mob.length - 1], { x: me.velocity.x + velocity.x, y: me.velocity.y + velocity.y });
+ }
+ me.maxMobs = 400
+ me.mode = [{
+ name: "boulders",
+ spawnRate: 170 - 6 * simulation.difficultyMode,
+ do() {
+ if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
+ me.boulder(me.position.x, me.position.y + 250)
+ }
+ },
+ enter() { },
+ exit() { },
+ }, {
+ name: "mobs",
+ // whoSpawn: spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)],
+ spawnRate: 280 - 20 * simulation.difficultyMode,
+ do() {
+ if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
+ me.torque += 0.000015 * me.inertia; //spin
+ const index = Math.floor((me.cycle % (this.spawnRate * 6)) / this.spawnRate) //int from 0 to 5
+ if (index === 0) me.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]; //fire a bullet from each vertex
+ me.spawnMobs(index)
+ // const vertex = me.vertices[index]
+ // const unit = Vector.normalise(Vector.sub(me.position, vertex))
+ // const where = Vector.add(vertex, Vector.mult(unit, -30))
+ // spawn[me.mobType](where.x + 50 * (Math.random() - 0.5), where.y + 50 * (Math.random() - 0.5));
+ // const velocity = Vector.mult(Vector.perp(unit), -18) //give the mob a rotational velocity as if they were attached to a vertex
+ // Matter.Body.setVelocity(mob[mob.length - 1], { x: me.velocity.x + velocity.x, y: me.velocity.y + velocity.y });
+ }
+ },
+ enter() { },
+ exit() { },
+ },
+ {
+ name: "hoppers",
+ spawnRate: 480 - 16 * simulation.difficultyMode,
+ do() {
+ if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) {
+ me.torque += 0.00002 * me.inertia; //spin
+ for (let i = 0; i < 6; i++) {
+ const vertex = me.vertices[i]
+ spawn.hopBullet(vertex.x + 50 * (Math.random() - 0.5), vertex.y + 50 * (Math.random() - 0.5), 13 + Math.ceil(Math.random() * 8)); //hopBullet(x, y, radius = 10 + Math.ceil(Math.random() * 8))
+ Matter.Body.setDensity(mob[mob.length - 1], 0.002); //normal is 0.001
+ const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(me.position, vertex))), -18) //give the mob a rotational velocity as if they were attached to a vertex
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: me.velocity.x + velocity.x,
+ y: me.velocity.y + velocity.y
+ });
+ }
+ let where = { x: 600 - Math.random() * 100, y: -225 }
+ if (simulation.isHorizontalFlipped) where.x = -600 + Math.random() * 100
+ spawn.hopBullet(where.x, where.y, 13 + Math.ceil(Math.random() * 8)); //hopBullet(x, y, radius = 10 + Math.ceil(Math.random() * 8))
+ Matter.Body.setDensity(mob[mob.length - 1], 0.002); //normal is 0.001
+ }
+ },
+ enter() { },
+ exit() { },
+ },
+ {
+ name: "seekers",
+ spawnRate: 100 - 3 * simulation.difficultyMode,
+ do() {
+ if (!(me.cycle % this.spawnRate) && mob.length < me.maxMobs) { //spawn seeker
+ const index = Math.floor((me.cycle % 360) / 60)
+ spawn.seeker(me.vertices[index].x, me.vertices[index].y, 18 * (0.5 + Math.random())); //seeker(x, y, radius = 8, sides = 6)
+ const who = mob[mob.length - 1]
+ Matter.Body.setDensity(who, 0.00003); //normal is 0.001
+ who.timeLeft = 720 + 30 * simulation.difficulty //* (0.8 + 0.4 * Math.random());
+ who.accelMag = 0.0004 * simulation.accelScale; //* (0.8 + 0.4 * Math.random())
+ who.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
+ }
+ },
+ enter() { },
+ exit() { },
+ },
+ {
+ name: "mines",
+ bombCycle: 0,
+ bombInterval: 10 - simulation.difficultyMode,
+ do() {
+ const yOff = 120
+ this.bombCycle++
+ if (!(this.bombCycle % this.bombInterval) && (this.bombCycle % 660) > 330) { //mines above player
+ if (simulation.isHorizontalFlipped) {
+ const x = m.pos.x + 200 * (Math.random() - 0.5)
+ if (x > -750) { //mines above player IN tunnel
+ spawn.mine(Math.min(Math.max(-730, x), 100), -450 - yOff * Math.random()) //player in main room
+ mob[mob.length - 1].fallHeight = -209
+ } else { //mines above player NOT in tunnel
+ spawn.mine(Math.min(Math.max(-5375, x), -765), -1500 - yOff * Math.random()) //player in tunnel
+ mob[mob.length - 1].fallHeight = -9
+ }
+ if (Math.random() < 0.5) {
+ spawn.mine(-5350 + 4550 * Math.random(), -1500 - yOff * Math.random()) //random mines
+ mob[mob.length - 1].fallHeight = -9
+ }
+ } else {
+ const x = m.pos.x + 200 * (Math.random() - 0.5)
+ if (x < 750) { //mines above player IN tunnel
+ spawn.mine(Math.min(Math.max(-100, x), 735), -450 - yOff * Math.random()) //player in main room
+ mob[mob.length - 1].fallHeight = -209
+ } else { //mines above player NOT in tunnel
+ spawn.mine(Math.min(Math.max(760, x), 5375), -1500 - yOff * Math.random()) //player in tunnel
+ mob[mob.length - 1].fallHeight = -9
+ }
+ if (Math.random() < 0.5) { //random mines, but not in tunnel
+ spawn.mine(800 + 4550 * Math.random(), -1500 - yOff * Math.random()) //random mines
+ mob[mob.length - 1].fallHeight = -9
+ }
+ }
+ }
+ for (let i = 0; i < mob.length; i++) { //mines fall
+ if (mob[i].isMine) {
+ if (mob[i].position.y < mob[i].fallHeight) {
+ mob[i].force.y += mob[i].mass * 0.03;
+ } else if (!mob[i].isOnGround) {
+ mob[i].isOnGround = true
+ Matter.Body.setPosition(mob[i], {
+ x: mob[i].position.x,
+ y: mob[i].fallHeight
+ })
+ }
+ }
+ }
+ },
+ enter() {
+ this.bombCycle = 0;
+ },
+ exit() {
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].isMine) mob[i].isExploding = true //explode the mines at the start of new round
+ }
+ },
+ },
+ {
+ name: "orbiters",
+ spawnRate: Math.ceil(4 - 0.25 * simulation.difficultyMode),
+ orbitersCycle: 0,
+ do() {
+ this.orbitersCycle++
+ if (!(this.orbitersCycle % this.spawnRate) && (this.orbitersCycle % 660) > 600 && mob.length < me.maxMobs) {
+ const speed = (0.01 + 0.0005 * simulation.difficultyMode) * ((Math.random() < 0.5) ? 0.85 : -1.15)
+ const phase = 0 //Math.floor(2 * Math.random()) * Math.PI
+ //find distance to play and set orbs at that range
+ const dist = me.distanceToPlayer()
+ //360 + 2150 * Math.random()
+ me.orbitalNoVelocity(me, dist + 900 * (Math.random() - 0.5), 0.1 * Math.random() + phase, speed) // orbital(who, radius, phase, speed)
+ }
+ },
+ enter() { },
+ exit() { },
+ },
+ {
+ name: "laser",
+ spinForce: 0.00000008, // * (Math.random() < 0.5 ? -1 : 1),
+ fadeCycle: 0, //fades in over 4 seconds
+ do() {
+ this.fadeCycle++
+ if (this.fadeCycle > 0) {
+ me.torque += this.spinForce * me.inertia; //spin //0.00000015
+ if (this.fadeCycle > 360) this.fadeCycle = -150 + 2 * simulation.difficultyMode * simulation.difficultyMode //turn laser off and reset
+ ctx.strokeStyle = "#50f";
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.lineWidth = 1.5;
+ ctx.beginPath();
+ if (this.fadeCycle < 120) { //damage scales up over 2 seconds to give player time to move as it fades in
+ const scale = this.fadeCycle / 120
+ const dmg = this.fadeCycle < 60 ? 0 : 0.1 * simulation.dmgScale * scale
+ me.lasers(me.vertices[0], me.angle + Math.PI / 6, dmg);
+ me.lasers(me.vertices[1], me.angle + 3 * Math.PI / 6, dmg);
+ me.lasers(me.vertices[2], me.angle + 5 * Math.PI / 6, dmg);
+ me.lasers(me.vertices[3], me.angle + 7 * Math.PI / 6, dmg);
+ me.lasers(me.vertices[4], me.angle + 9 * Math.PI / 6, dmg);
+ me.lasers(me.vertices[5], me.angle + 11 * Math.PI / 6, dmg);
+ ctx.strokeStyle = `rgba(85, 0, 255,${scale})`;
+ ctx.stroke();
+ ctx.strokeStyle = `rgba(80, 0, 255,${0.07 * scale})`
+ } else if (this.fadeCycle > 0) {
+ me.lasers(me.vertices[0], me.angle + Math.PI / 6);
+ me.lasers(me.vertices[1], me.angle + 3 * Math.PI / 6);
+ me.lasers(me.vertices[2], me.angle + 5 * Math.PI / 6);
+ me.lasers(me.vertices[3], me.angle + 7 * Math.PI / 6);
+ me.lasers(me.vertices[4], me.angle + 9 * Math.PI / 6);
+ me.lasers(me.vertices[5], me.angle + 11 * Math.PI / 6);
+ ctx.strokeStyle = "#50f";
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(80,0,255,0.07)";
+ }
+ ctx.setLineDash([]);
+ ctx.lineWidth = 20;
+ ctx.stroke();
+ }
+ },
+ enter() { this.fadeCycle = 0 },
+ exit() { },
+ },
+ {
+ name: "black hole",
+ eventHorizon: 0,
+ eventHorizonRadius: 1900,
+ eventHorizonCycle: 0,
+ do() {
+ this.eventHorizonCycle++
+ this.eventHorizon = Math.max(0, this.eventHorizonRadius * Math.sin(this.eventHorizonCycle * 0.007)) //eventHorizon waves in and out
+ //draw darkness
+ ctx.beginPath();
+ ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.2, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.3)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.4, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.25)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.6, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.2)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(me.position.x, me.position.y, this.eventHorizon * 0.8, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.15)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(me.position.x, me.position.y, this.eventHorizon, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.1)";
+ ctx.fill();
+ //when player is inside event horizon
+ if (Vector.magnitude(Vector.sub(me.position, player.position)) < this.eventHorizon) {
+ if (m.immuneCycle < m.cycle) {
+ if (m.energy > 0) m.energy -= 0.018
+ if (m.energy < 0.05 && m.immuneCycle < m.cycle) m.damage(0.0003 * simulation.dmgScale);
+ }
+ const angle = Math.atan2(player.position.y - me.position.y, player.position.x - me.position.x);
+ player.force.x -= 0.0017 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1);
+ player.force.y -= 0.0017 * Math.sin(angle) * player.mass;
+ //draw line to player
+ ctx.beginPath();
+ ctx.moveTo(me.position.x, me.position.y);
+ ctx.lineTo(m.pos.x, m.pos.y);
+ ctx.lineWidth = Math.min(60, me.radius * 2);
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.3)";
+ ctx.fill();
+ }
+ me.curl(this.eventHorizon);
+ },
+ enter() { this.eventHorizonCycle = 0 },
+ exit() { },
+ },
+ {
+ name: "oscillation",
+ waveCycle: 0,
+ whereX: simulation.isHorizontalFlipped ? -3000 : 3000,
+ do() {
+ this.waveCycle += !me.isStunned + !me.isSlowed
+ // if (!me.isShielded && (!(this.waveCycle % 1800) || !(this.waveCycle % 1801))) spawn.shield(me, me.position.x, me.position.y, 1);
+ me.constraint.pointA = {
+ x: this.whereX + 600 * Math.sin(this.waveCycle * 0.005),
+ y: me.constraint.pointA.y
+ }
+ },
+ enter() {
+ spawn.shield(me, me.position.x, me.position.y, 1);
+ },
+ exit() { this.waveCycle = 0 },
+ },
+ // {
+ // name: "__",
+ // do() {},
+ // enter() {},
+ // exit() {},
+ // },
+ ]
+ shuffle(me.mode); //THIS SHOULDN'T BE COMMENTED OUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ me.do = function () {
+ this.fill = `hsl(${360 * Math.sin(this.cycle * 0.011)},${80 + 20 * Math.sin(this.cycle * 0.004)}%,${60 + 20 * Math.sin(this.cycle * 0.009)}%)`
+ if (this.health < 1) {
+ this.cycle++;
+ this.checkStatus();
+ this.invulnerable();
+ this.spawnBoss();
+ this.damageReductionDecay();
+ for (let i = 0; i < this.totalModes; i++) this.mode[i].do()
+ }
+ // this.mode[5].do() //deelete this
+ // this.cycle++;
+ // this.mode[4].do()
+ // this.mode[7].do()
+ };
+ me.spawnRate = 5800 - 30 * simulation.difficultyMode * simulation.difficultyMode
+ me.spawnBoss = function () { //if the fight lasts too long start spawning bosses
+ if (!(me.cycle % this.spawnRate) && this.health < 1) {
+ this.spawnRate = Math.max(300, this.spawnRate - 10 * simulation.difficultyMode * simulation.difficultyMode) //reduce the timer each time a boss spawns
+ spawn.randomLevelBoss(3000 * (simulation.isHorizontalFlipped ? -1 : 1) + 2000 * (Math.random() - 0.5), -1100 + 200 * (Math.random() - 0.5))
+ }
+ }
+ me.pushAway = function (magX = 0.13, magY = 0.05) {
+ for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally
+ body[i].force.x += magX * body[i].mass * (body[i].position.x > this.position.x ? 1 : -1)
+ body[i].force.y -= magY * body[i].mass
+ }
+ for (let i = 0, len = bullet.length; i < len; ++i) { //push blocks away horizontally
+ bullet[i].force.x += magX * bullet[i].mass * (bullet[i].position.x > this.position.x ? 1 : -1)
+ bullet[i].force.y -= magY * bullet[i].mass
+ }
+ for (let i = 0, len = powerUp.length; i < len; ++i) { //push blocks away horizontally
+ powerUp[i].force.x += magX * powerUp[i].mass * (powerUp[i].position.x > this.position.x ? 1 : -1)
+ powerUp[i].force.y -= magY * powerUp[i].mass
+ }
+ player.force.x += magX * player.mass * (player.position.x > this.position.x ? 1 : -1)
+ player.force.y -= magY * player.mass
+ }
+ me.boulder = function (x, y) {
+ mobs.spawn(x, y, 6, Math.floor(50 + 50 * Math.random()), this.fill);
+ let boss = this
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.onHit = function () {
+ this.timeLeft = 0
+ };
+ me.explodeRange = 500
+ me.onDeath = function () { //explode
+ simulation.drawList.push({ //draw explosion
+ x: this.position.x,
+ y: this.position.y,
+ radius: this.explodeRange,
+ color: this.fill,
+ time: 8
+ });
+ let sub, knock
+ sub = Vector.sub(player.position, this.position);
+ if (Vector.magnitude(sub) < this.explodeRange) { //player knock back
+ m.damage(0.05);
+ knock = Vector.mult(Vector.normalise(sub), player.mass * 0.1);
+ player.force.x += knock.x;
+ player.force.y += knock.y;
+ }
+ for (let i = 0, len = powerUp.length; i < len; ++i) { //power up knock backs
+ sub = Vector.sub(powerUp[i].position, this.position);
+ if (Vector.magnitude(sub) < this.explodeRange) {
+ knock = Vector.mult(Vector.normalise(sub), powerUp[i].mass * 0.1);
+ powerUp[i].force.x += knock.x;
+ powerUp[i].force.y += knock.y;
+ }
+ }
+ for (let i = 0, len = body.length; i < len; ++i) { //block knock backs
+ sub = Vector.sub(body[i].position, this.position);
+ if (Vector.magnitude(sub) < this.explodeRange) {
+ knock = Vector.mult(Vector.normalise(sub), body[i].mass * 0.1);
+ body[i].force.x += knock.x;
+ body[i].force.y += knock.y;
+ }
+ }
+ }
+ Matter.Body.setDensity(me, 0.003); //normal is 0.001
+ me.timeLeft = 360;
+ me.g = 0.0005; //required if using this.gravity
+ me.frictionAir = 0.005;
+ me.friction = 1;
+ me.frictionStatic = 1
+ me.restitution = 0;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
+ me.spin = me.inertia * 0.000005 * (1 + Math.random()) * (m.pos.x > me.position.x ? 1 : -1)
+ Matter.Body.setAngularVelocity(me, 0.1 * (1 + 0.3 * Math.random()) * (m.pos.x > me.position.x ? 1 : -1));
+ Matter.Body.setVelocity(me, { x: 0, y: 10 });
+ me.do = function () {
+ this.fill = boss.fill
+ this.torque += this.spin;
+ this.gravity();
+ this.timeLimit();
+ };
+ }
+ me.orbitalNoVelocity = function (who, radius, phase, speed) { //orbitals that don't include their host velocity //specifically for finalBoss
+ let boss = this
+ mobs.spawn(who.position.x, who.position.y, 6, 20, "rgb(255,0,150)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ Matter.Body.setDensity(me, 0.001); //normal is 0.001
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isUnstable = true; //dies when blocked
+ me.showHealthBar = false;
+ me.isOrbital = true;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.bullet; //cat.player | cat.map | cat.body
+ me.do = function () {
+ this.fill = boss.fill
+ const time = simulation.cycle * speed + phase
+ const orbit = { x: Math.cos(time), y: Math.sin(time) }
+ Matter.Body.setPosition(this, Vector.add(who.position, Vector.mult(orbit, radius)))
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ const dmg = 0.13 * simulation.dmgScale
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: Math.sqrt(dmg) * 200,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ this.death();
+ }
+ };
+ }
+ me.lasers = function (where, angle, dmg = 0.1 * simulation.dmgScale) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ };
+
+ const seeRange = 7000;
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ const look = {
+ x: where.x + seeRange * Math.cos(angle),
+ y: where.y + seeRange * Math.sin(angle)
+ };
+ // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ vertexCollision(where, look, body);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ if (m.immuneCycle < m.cycle + 60 + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 60 + m.collisionImmuneCycles; //player is immune to damage extra time
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: dmg * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ //draw beam
+ if (best.dist2 === Infinity) best = look;
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ }
+ me.onDeath = function () {
+ if (!this.hasRunDeathScript) {
+ this.hasRunDeathScript = true
+ //make a block body to replace this one
+ //this body is too big to leave behind in the normal way mobs.replace()
+ const len = body.length;
+ const v = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //might help with vertex collision issue, not sure
+ body[len] = Matter.Bodies.fromVertices(this.position.x, this.position.y, v);
+ Matter.Body.setVelocity(body[len], { x: 0, y: -3 });
+ Matter.Body.setAngularVelocity(body[len], this.angularVelocity);
+ body[len].collisionFilter.category = cat.body;
+ body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet;
+ body[len].classType = "body";
+ Composite.add(engine.world, body[len]); //add to world
+ const expand = function (that, massLimit) {
+ const scale = 1.05;
+ Matter.Body.scale(that, scale, scale);
+ if (that.mass < massLimit) setTimeout(expand, 20, that, massLimit);
+ };
+ expand(body[len], 200)
+
+ function unlockExit() {
+ if (simulation.isHorizontalFlipped) {
+ level.exit.x = -5500 - 100;
+ } else {
+ level.exit.x = 5500;
+ }
+ level.exit.y = -330;
+ Matter.Composite.remove(engine.world, map[map.length - 1]);
+ map.splice(map.length - 1, 1);
+ simulation.draw.setPaths(); //redraw map draw path
+ // level.levels.push("null")
+ }
+
+ //add lore level as next level if player took lore tech earlier in the game
+ if (lore.techCount > (lore.techGoal - 1) && !simulation.isCheating) {
+ simulation.makeTextLog(`undefined = ${lore.techCount}/${lore.techGoal}`, 360);
+ setTimeout(function () {
+ simulation.makeTextLog(`level.levels.push("null ")`, 720);
+ unlockExit()
+ level.levels.push("null")
+ }, 4000);
+ //remove block map element so exit is clear
+ } else { //reset game
+ let count = 0
+
+ function loop() {
+ if (!simulation.paused && !simulation.onTitlePage) {
+ count++
+ if (count < 660) {
+ if (count === 1) simulation.makeTextLog(`//enter testing mode to set level.levels.length to Infinite `);
+ if (!(count % 60)) simulation.makeTextLog(`simulation.analysis = ${((count / 60 - Math.random()) * 0.1).toFixed(3)}`);
+ } else if (count === 660) {
+ simulation.makeTextLog(`simulation.analysis = 1 //analysis complete `);
+ } else if (count === 780) {
+ simulation.makeTextLog(`undefined = ${lore.techCount}/${lore.techGoal}`)
+ } else if (count === 1020) {
+ simulation.makeTextLog(`Engine.clear(engine) //simulation successful `);
+ } else if (count === 1260) {
+ // tech.isImmortal = false;
+ // m.death()
+ // m.alive = false;
+ // simulation.paused = true;
+ // m.health = 0;
+ // m.displayHealth();
+ document.getElementById("health").style.display = "none"
+ document.getElementById("health-bg").style.display = "none"
+ document.getElementById("defense-bar").style.display = "none"
+ document.getElementById("damage-bar").style.display = "none"
+ document.getElementById("text-log").style.display = "none"
+ document.getElementById("fade-out").style.opacity = 1; //slowly fades out
+ // build.shareURL(false)
+ setTimeout(function () {
+ if (!simulation.onTitlePage) {
+ m.alive = false
+ simulation.paused = true;
+ // simulation.clearMap();
+ // Matter.Composite.clear(composite, keepStatic, [deep = false])
+ // Composite.clear(engine.composite);
+ engine.world.bodies.forEach((body) => { Matter.Composite.remove(engine.world, body) })
+ Engine.clear(engine);
+ simulation.splashReturn();
+ }
+ }, 6000);
+ return
+ }
+ }
+ if (simulation.testing) {
+ unlockExit()
+ setTimeout(function () {
+ simulation.makeTextLog(`level.levels.length = Infinite `);
+ }, 1500);
+ } else {
+ if (!simulation.onTitlePage) requestAnimationFrame(loop);
+ }
+ }
+ requestAnimationFrame(loop);
+ }
+ // for (let i = 0; i < 3; i++)
+ level.difficultyIncrease(simulation.difficultyMode) //ramp up damage
+ //remove power Ups, to avoid spamming console
+ function removeAll(array) {
+ for (let i = 0; i < array.length; ++i) Matter.Composite.remove(engine.world, array[i]);
+ }
+ removeAll(powerUp);
+ powerUp = [];
+
+ //pull in particles
+ for (let i = 0, len = body.length; i < len; ++i) {
+ const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, body[i].position)), 65)
+ const pushUp = Vector.add(velocity, { x: 0, y: -0.5 })
+ Matter.Body.setVelocity(body[i], Vector.add(body[i].velocity, pushUp));
+ }
+ //damage all mobs
+ for (let j = 0; j < 8; j++) { //in case some mobs leave things after they die
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (mob[i] !== this) {
+ if (mob[i].isInvulnerable) { //disable invulnerability
+ mob[i].isInvulnerable = false
+ mob[i].damageReduction = 1
+ }
+ mob[i].damage(Infinity, true);
+ }
+ }
+ }
+
+ //draw stuff
+ for (let i = 0, len = 22; i < len; i++) {
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: (i + 1) * 150,
+ color: `rgba(255,255,255,0.17)`,
+ time: 5 * (len - i + 1)
+ });
+ }
+ }
+ };
+ },
+ // finalBoss(x, y, radius = 300) {
+ // mobs.spawn(x, y, 6, radius, "rgb(150,150,255)");
+ // let me = mob[mob.length - 1];
+ // setTimeout(() => { //fix mob in place, but allow rotation
+ // me.constraint = Constraint.create({
+ // pointA: {
+ // x: me.position.x,
+ // y: me.position.y
+ // },
+ // bodyB: me,
+ // stiffness: 1,
+ // damping: 1
+ // });
+ // Composite.add(engine.world, me.constraint);
+ // }, 2000); //add in a delay in case the level gets flipped left right
+ // me.isBoss = true;
+ // me.isFinalBoss = true;
+ // me.frictionAir = 0.01;
+ // me.memory = Infinity;
+ // me.hasRunDeathScript = false
+ // me.locatePlayer();
+ // // const density = 0.2
+ // Matter.Body.setDensity(me, 0.2); //extra dense //normal is 0.001 //makes effective life much larger
+ // // spawn.shield(me, x, y, 1);
+ // me.onDamage = function() {};
+ // me.cycle = 660;
+ // me.endCycle = 780;
+ // me.totalCycles = 0
+ // me.mode = 0;
+ // me.damageReduction = 0.25 //reset on each new mode
+ // me.pushAway = function(magX = 0.13, magY = 0.05) {
+ // for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally
+ // body[i].force.x += magX * body[i].mass * (body[i].position.x > this.position.x ? 1 : -1)
+ // body[i].force.y -= magY * body[i].mass
+ // }
+ // for (let i = 0, len = bullet.length; i < len; ++i) { //push blocks away horizontally
+ // bullet[i].force.x += magX * bullet[i].mass * (bullet[i].position.x > this.position.x ? 1 : -1)
+ // bullet[i].force.y -= magY * bullet[i].mass
+ // }
+ // for (let i = 0, len = powerUp.length; i < len; ++i) { //push blocks away horizontally
+ // powerUp[i].force.x += magX * powerUp[i].mass * (powerUp[i].position.x > this.position.x ? 1 : -1)
+ // powerUp[i].force.y -= magY * powerUp[i].mass
+ // }
+ // player.force.x += magX * player.mass * (player.position.x > this.position.x ? 1 : -1)
+ // player.force.y -= magY * player.mass
+ // }
+ // me.do = function() {
+ // this.modeDo(); //this does different things based on the mode
+ // this.checkStatus();
+ // this.cycle++; //switch modes÷ if time isn't paused
+ // this.totalCycles++;
+ // if (this.health > 0.3) {
+ // if (this.cycle > this.endCycle) {
+ // this.showHealthBar = true
+ // this.cycle = 0;
+ // this.mode++
+ // this.damageReduction = 0.25
+ // if (this.totalCycles > 180) this.pushAway();
+ // if (this.mode > 3) {
+ // this.mode = 0;
+ // this.fill = "#50f";
+ // this.rotateVelocity = Math.abs(this.rotateVelocity) * (player.position.x > this.position.x ? 1 : -1) //rotate so that the player can get away
+ // this.modeDo = this.modeLasers
+ // //push blocks and player away, since this is the end of suck, and suck causes blocks to fall on the boss and stun it
+ // Matter.Body.scale(this, 1000, 1000);
+ // if (!this.isShielded) spawn.shield(this, this.position.x, this.position.y, 1); // regen shield to also prevent stun
+ // } else if (this.mode === 1) {
+ // this.fill = "#50f"; // this.fill = "rgb(150,150,255)";
+ // this.modeDo = this.modeSpawns
+ // } else if (this.mode === 2) {
+ // this.fill = "#50f";
+ // this.modeDo = this.modeBombs
+ // } else if (this.mode === 3) {
+ // for (let i = 0; i < mob.length; i++) {
+ // if (mob[i].isMine) mob[i].isExploding = true //explode the mines at the start of new round
+ // }
+ // this.fill = "#000";
+ // this.modeDo = this.modeSuck
+ // Matter.Body.scale(this, 0.001, 0.001);
+ // this.damageReduction = 0.000025
+ // this.showHealthBar = false
+ // }
+
+ // if (tech.isGunCycle) {
+ // b.inventoryGun++;
+ // if (b.inventoryGun > b.inventory.length - 1) b.inventoryGun = 0;
+ // simulation.switchGun();
+ // }
+ // }
+ // } else if (this.mode !== 3) { //all three modes at once , this runs once
+ // this.showHealthBar = true
+ // this.pushAway();
+ // this.cycle = 0;
+ // this.endCycle = Infinity
+ // this.damageReduction = 0.15
+ // if (this.mode === 2) {
+ // Matter.Body.scale(this, 500, 500);
+ // } else {
+ // Matter.Body.scale(this, 0.5, 0.5);
+ // }
+ // this.mode = 3
+ // this.fill = "#000";
+ // this.eventHorizon = 750
+ // this.spawnInterval = 600
+ // this.rotateVelocity = 0.001 * (player.position.x > this.position.x ? 1 : -1) //rotate so that the player can get away
+ // // if (!this.isShielded) spawn.shield(this, x, y, 1); //regen shield here ?
+ // this.modeDo = this.modeAll
+ // this.eventHorizonRadius = 700
+ // if (tech.isGunCycle) {
+ // b.inventoryGun++;
+ // if (b.inventoryGun > b.inventory.length - 1) b.inventoryGun = 0;
+ // simulation.switchGun();
+ // }
+ // }
+ // // }
+ // };
+ // me.modeDo = function() {}
+ // me.modeAll = function() {
+ // this.modeBombs()
+ // this.modeSpawns()
+ // this.modeSuck()
+ // this.modeLasers()
+ // }
+ // me.bombInterval = 36 - 0.5 * simulation.difficultyMode * simulation.difficultyMode
+ // me.modeBombs = function() {
+ // if (!(this.cycle % 20)) {
+ // if (m.pos.x < 750) {
+ // spawn.mine(m.pos.x + 200 * (Math.random() - 0.5), -500)
+ // } else {
+ // spawn.mine(Math.min(Math.max(770, m.pos.x + 200 * (Math.random() - 0.5)), 5350), -1500)
+ // }
+ // }
+ // if (!(this.cycle % 10)) spawn.mine(800 + 4550 * Math.random(), -1500)
+
+ // //mines fall
+ // for (let i = 0; i < mob.length; i++) {
+ // // if (mob[i].isMine && mob[i].position.y < -5) Matter.Body.setPosition(mob[i], { x: mob[i].position.x, y: mob[i].position.y + 5 })
+ // if (mob[i].isMine && mob[i].position.y < -14) mob[i].force.y += mob[i].mass * 0.03;
+ // }
+
+ // }
+ // me.spawnInterval = 395
+ // me.modeSpawns = function() {
+ // if (!(this.cycle % this.spawnInterval) && mob.length < 40) {
+ // if (this.mode !== 3) Matter.Body.setAngularVelocity(this, 0.1)
+ // //fire a bullet from each vertex
+ // const whoSpawn = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)];
+ // for (let i = 0, len = 2 + this.totalCycles / 1000; i < len; i++) {
+ // const vertex = this.vertices[i % 6]
+ // spawn[whoSpawn](vertex.x + 50 * (Math.random() - 0.5), vertex.y + 50 * (Math.random() - 0.5));
+ // const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position, vertex))), -18) //give the mob a rotational velocity as if they were attached to a vertex
+ // Matter.Body.setVelocity(mob[mob.length - 1], {
+ // x: this.velocity.x + velocity.x,
+ // y: this.velocity.y + velocity.y
+ // });
+ // }
+ // if (!(this.cycle % 2 * this.spawnInterval) && mob.length < 40) {
+ // const len = (this.totalCycles / 1000 + simulation.difficulty / 2 - 30) / 15
+ // for (let i = 0; i < len; i++) {
+ // spawn.randomLevelBoss(3000 * (simulation.isHorizontalFlipped ? -1 : 1) + 2000 * (Math.random() - 0.5), -1100 + 200 * (Math.random() - 0.5))
+ // }
+ // }
+ // }
+ // }
+ // me.eventHorizon = 0
+ // me.eventHorizonRadius = 1300
+ // me.modeSuck = function() {
+ // if (!(this.cycle % 30)) {
+ // const index = Math.floor((this.cycle % 360) / 60)
+ // spawn.seeker(this.vertices[index].x, this.vertices[index].y, 20 * (0.5 + Math.random()), 9); //give the bullet a rotational velocity as if they were attached to a vertex
+ // const who = mob[mob.length - 1]
+ // Matter.Body.setDensity(who, 0.00003); //normal is 0.001
+ // who.timeLeft = 720 + 10 * simulation.difficulty //* (0.8 + 0.4 * Math.random());
+ // who.accelMag = 0.0003 * simulation.accelScale; //* (0.8 + 0.4 * Math.random())
+ // who.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
+ // const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position, this.vertices[index]))), -7)
+ // Matter.Body.setVelocity(who, {
+ // x: this.velocity.x + velocity.x,
+ // y: this.velocity.y + velocity.y
+ // });
+ // }
+
+ // //eventHorizon waves in and out
+ // if (this.cycle + 30 > this.endCycle) { //shrink fast in last bit of cycle
+ // this.eventHorizon = 0.93 * this.eventHorizon
+ // } else {
+ // this.eventHorizon = 0.97 * this.eventHorizon + 0.03 * (this.eventHorizonRadius * (1 - 0.5 * Math.cos(this.cycle * 0.015)))
+ // }
+ // //draw darkness
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, this.eventHorizon * 0.2, 0, 2 * Math.PI);
+ // ctx.fillStyle = "rgba(0,20,40,0.6)";
+ // ctx.fill();
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, this.eventHorizon * 0.4, 0, 2 * Math.PI);
+ // ctx.fillStyle = "rgba(0,20,40,0.4)";
+ // ctx.fill();
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, this.eventHorizon * 0.6, 0, 2 * Math.PI);
+ // ctx.fillStyle = "rgba(0,20,40,0.3)";
+ // ctx.fill();
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, this.eventHorizon * 0.8, 0, 2 * Math.PI);
+ // ctx.fillStyle = "rgba(0,20,40,0.2)";
+ // ctx.fill();
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
+ // ctx.fillStyle = "rgba(0,0,0,0.05)";
+ // ctx.fill();
+ // //when player is inside event horizon
+ // if (Vector.magnitude(Vector.sub(this.position, player.position)) < this.eventHorizon) {
+ // if (m.immuneCycle < m.cycle) {
+ // if (m.energy > 0) m.energy -= 0.02
+ // if (m.energy < 0.05 && m.immuneCycle < m.cycle) m.damage(0.0004 * simulation.dmgScale);
+ // }
+ // const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
+ // player.force.x -= 0.0017 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1);
+ // player.force.y -= 0.0017 * Math.sin(angle) * player.mass;
+ // //draw line to player
+ // ctx.beginPath();
+ // ctx.moveTo(this.position.x, this.position.y);
+ // ctx.lineTo(m.pos.x, m.pos.y);
+ // ctx.lineWidth = Math.min(60, this.radius * 2);
+ // ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ // ctx.stroke();
+ // ctx.beginPath();
+ // ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ // ctx.fillStyle = "rgba(0,0,0,0.3)";
+ // ctx.fill();
+ // }
+ // this.curl(this.eventHorizon);
+ // }
+ // me.rotateVelocity = 0.0025
+ // me.rotateCount = 0;
+ // me.lasers = function(where, angle, dmg = 0.14 * simulation.dmgScale) {
+ // const vertexCollision = function(v1, v1End, domain) {
+ // for (let i = 0; i < domain.length; ++i) {
+ // let vertices = domain[i].vertices;
+ // const len = vertices.length - 1;
+ // for (let j = 0; j < len; j++) {
+ // results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ // if (results.onLine1 && results.onLine2) {
+ // const dx = v1.x - results.x;
+ // const dy = v1.y - results.y;
+ // const dist2 = dx * dx + dy * dy;
+ // if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = {
+ // x: results.x,
+ // y: results.y,
+ // dist2: dist2,
+ // who: domain[i],
+ // v1: vertices[j],
+ // v2: vertices[j + 1]
+ // };
+ // }
+ // }
+ // results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ // if (results.onLine1 && results.onLine2) {
+ // const dx = v1.x - results.x;
+ // const dy = v1.y - results.y;
+ // const dist2 = dx * dx + dy * dy;
+ // if (dist2 < best.dist2) best = {
+ // x: results.x,
+ // y: results.y,
+ // dist2: dist2,
+ // who: domain[i],
+ // v1: vertices[0],
+ // v2: vertices[len]
+ // };
+ // }
+ // }
+ // };
+
+ // const seeRange = 7000;
+ // best = {
+ // x: null,
+ // y: null,
+ // dist2: Infinity,
+ // who: null,
+ // v1: null,
+ // v2: null
+ // };
+ // const look = {
+ // x: where.x + seeRange * Math.cos(angle),
+ // y: where.y + seeRange * Math.sin(angle)
+ // };
+ // // vertexCollision(where, look, mob);
+ // vertexCollision(where, look, map);
+ // vertexCollision(where, look, body);
+ // if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ // if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ // if (m.immuneCycle < m.cycle + 60 + m.collisionImmuneCycles) m.immuneCycle = m.cycle + 60 + m.collisionImmuneCycles; //player is immune to damage extra time
+ // m.damage(dmg);
+ // simulation.drawList.push({ //add dmg to draw queue
+ // x: best.x,
+ // y: best.y,
+ // radius: dmg * 1500,
+ // color: "rgba(80,0,255,0.5)",
+ // time: 20
+ // });
+ // }
+ // //draw beam
+ // if (best.dist2 === Infinity) best = look;
+ // ctx.moveTo(where.x, where.y);
+ // ctx.lineTo(best.x, best.y);
+ // }
+ // me.modeLasers = function() {
+ // if (!this.isStunned) {
+ // let slowed = false //check if slowed
+ // for (let i = 0; i < this.status.length; i++) {
+ // if (this.status[i].type === "slow") {
+ // slowed = true
+ // break
+ // }
+ // }
+ // if (!slowed) {
+ // this.rotateCount++
+ // Matter.Body.setAngle(this, this.rotateCount * this.rotateVelocity)
+ // Matter.Body.setAngularVelocity(this, 0)
+ // Matter
+ // }
+ // }
+ // if (this.cycle < 240) { //damage scales up over 2 seconds to give player time to move
+ // const scale = this.cycle / 240
+ // const dmg = (this.cycle < 120) ? 0 : 0.14 * simulation.dmgScale * scale
+ // ctx.beginPath();
+ // this.lasers(this.vertices[0], this.angle + Math.PI / 6, dmg);
+ // this.lasers(this.vertices[1], this.angle + 3 * Math.PI / 6, dmg);
+ // this.lasers(this.vertices[2], this.angle + 5 * Math.PI / 6, dmg);
+ // this.lasers(this.vertices[3], this.angle + 7 * Math.PI / 6, dmg);
+ // this.lasers(this.vertices[4], this.angle + 9 * Math.PI / 6, dmg);
+ // this.lasers(this.vertices[5], this.angle + 11 * Math.PI / 6, dmg);
+ // ctx.strokeStyle = "#50f";
+ // ctx.lineWidth = 1.5 * scale;
+ // ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ // ctx.stroke(); // Draw it
+ // ctx.setLineDash([]);
+ // ctx.lineWidth = 20;
+ // ctx.strokeStyle = `rgba(80,0,255,${0.07 * scale})`;
+ // ctx.stroke(); // Draw it
+ // } else {
+ // ctx.beginPath();
+ // this.lasers(this.vertices[0], this.angle + Math.PI / 6);
+ // this.lasers(this.vertices[1], this.angle + 3 * Math.PI / 6);
+ // this.lasers(this.vertices[2], this.angle + 5 * Math.PI / 6);
+ // this.lasers(this.vertices[3], this.angle + 7 * Math.PI / 6);
+ // this.lasers(this.vertices[4], this.angle + 9 * Math.PI / 6);
+ // this.lasers(this.vertices[5], this.angle + 11 * Math.PI / 6);
+ // ctx.strokeStyle = "#50f";
+ // ctx.lineWidth = 1.5;
+ // ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ // ctx.stroke(); // Draw it
+ // ctx.setLineDash([]);
+ // ctx.lineWidth = 20;
+ // ctx.strokeStyle = "rgba(80,0,255,0.07)";
+ // ctx.stroke(); // Draw it
+ // }
+ // }
+ // me.onDeath = function() {
+ // if (!this.hasRunDeathScript) {
+ // this.hasRunDeathScript = true
+ // //make a block body to replace this one
+ // //this body is too big to leave behind in the normal way mobs.replace()
+ // const len = body.length;
+ // const v = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //might help with vertex collision issue, not sure
+ // body[len] = Matter.Bodies.fromVertices(this.position.x, this.position.y, v);
+ // Matter.Body.setVelocity(body[len], { x: 0, y: -3 });
+ // Matter.Body.setAngularVelocity(body[len], this.angularVelocity);
+ // body[len].collisionFilter.category = cat.body;
+ // body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet;
+ // body[len].classType = "body";
+ // Composite.add(engine.world, body[len]); //add to world
+ // const expand = function(that, massLimit) {
+ // const scale = 1.05;
+ // Matter.Body.scale(that, scale, scale);
+ // if (that.mass < massLimit) setTimeout(expand, 20, that, massLimit);
+ // };
+ // expand(body[len], 200)
+
+ // function unlockExit() {
+ // if (simulation.isHorizontalFlipped) {
+ // level.exit.x = -5500 - 100;
+ // } else {
+ // level.exit.x = 5500;
+ // }
+ // level.exit.y = -330;
+ // Matter.Composite.remove(engine.world, map[map.length - 1]);
+ // map.splice(map.length - 1, 1);
+ // simulation.draw.setPaths(); //redraw map draw path
+ // // level.levels.push("null")
+ // }
+
+ // //add lore level as next level if player took lore tech earlier in the game
+ // if (lore.techCount > (lore.techGoal - 1) && !simulation.isCheating) {
+ // simulation.makeTextLog(`undefined = ${lore.techCount}/${lore.techGoal}`, 360);
+ // setTimeout(function() {
+ // simulation.makeTextLog(`level.levels.push("null ")`, 720);
+ // unlockExit()
+ // level.levels.push("null")
+ // }, 4000);
+ // //remove block map element so exit is clear
+ // } else { //reset game
+ // let count = 0
+
+ // function loop() {
+ // if (!simulation.paused && !simulation.onTitlePage) {
+ // count++
+ // if (count < 660) {
+ // if (count === 1) simulation.makeTextLog(`//enter testing mode to set level.levels.length to Infinite `);
+ // if (!(count % 60)) simulation.makeTextLog(`simulation.analysis = ${((count / 60 - Math.random()) * 0.1).toFixed(3)}`);
+ // } else if (count === 660) {
+ // simulation.makeTextLog(`simulation.analysis = 1 //analysis complete `);
+ // } else if (count === 780) {
+ // simulation.makeTextLog(`undefined = ${lore.techCount}/${lore.techGoal}`)
+ // } else if (count === 1020) {
+ // simulation.makeTextLog(`Engine.clear(engine) //simulation successful `);
+ // } else if (count === 1260) {
+ // // tech.isImmortal = false;
+ // // m.death()
+ // // m.alive = false;
+ // // simulation.paused = true;
+ // // m.health = 0;
+ // // m.displayHealth();
+ // document.getElementById("health").style.display = "none"
+ // document.getElementById("health-bg").style.display = "none"
+ // document.getElementById("text-log").style.opacity = 0; //fade out any active text logs
+ // document.getElementById("fade-out").style.opacity = 1; //slowly fades out
+ // // build.shareURL(false)
+ // setTimeout(function() {
+ // if (!simulation.onTitlePage) {
+ // simulation.paused = true;
+ // // simulation.clearMap();
+ // // Matter.Composite.clear(composite, keepStatic, [deep = false])
+ // // Composite.clear(engine.composite);
+ // engine.world.bodies.forEach((body) => { Matter.Composite.remove(engine.world, body) })
+ // Engine.clear(engine);
+ // simulation.splashReturn();
+ // }
+ // }, 6000);
+ // return
+ // }
+ // }
+ // if (simulation.testing) {
+ // unlockExit()
+ // setTimeout(function() {
+ // simulation.makeTextLog(`level.levels.length = Infinite `);
+ // }, 1500);
+ // } else {
+ // if (!simulation.onTitlePage) requestAnimationFrame(loop);
+ // }
+ // }
+ // requestAnimationFrame(loop);
+ // }
+ // // for (let i = 0; i < 3; i++)
+ // level.difficultyIncrease(simulation.difficultyMode) //ramp up damage
+ // //remove power Ups, to avoid spamming console
+ // function removeAll(array) {
+ // for (let i = 0; i < array.length; ++i) Matter.Composite.remove(engine.world, array[i]);
+ // }
+ // removeAll(powerUp);
+ // powerUp = [];
+
+ // //pull in particles
+ // for (let i = 0, len = body.length; i < len; ++i) {
+ // const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, body[i].position)), 65)
+ // const pushUp = Vector.add(velocity, { x: 0, y: -0.5 })
+ // Matter.Body.setVelocity(body[i], Vector.add(body[i].velocity, pushUp));
+ // }
+ // //damage all mobs
+ // for (let j = 0; j < 8; j++) { //in case some mobs leave things after they die
+ // for (let i = 0, len = mob.length; i < len; ++i) {
+ // if (mob[i] !== this) {
+ // if (mob[i].isInvulnerable) { //disable invulnerability
+ // mob[i].isInvulnerable = false
+ // mob[i].damageReduction = 1
+ // }
+ // mob[i].damage(Infinity, true);
+ // }
+ // }
+ // }
+
+ // //draw stuff
+ // for (let i = 0, len = 22; i < len; i++) {
+ // simulation.drawList.push({ //add dmg to draw queue
+ // x: this.position.x,
+ // y: this.position.y,
+ // radius: (i + 1) * 150,
+ // color: `rgba(255,255,255,0.17)`,
+ // time: 5 * (len - i + 1)
+ // });
+ // }
+ // }
+ // };
+ // },
+ zombie(x, y, radius, sides, color) { //mob that attacks other mobs
+ mobs.spawn(x, y, sides, radius, color);
+ let me = mob[mob.length - 1];
+ me.damageReduction = 0 //take NO damage, but also slowly lose health
+ Matter.Body.setDensity(me, 0.0001) // normal density is 0.001 // this reduces life by half and decreases knockback
+ me.isZombie = true
+ me.isBadTarget = true;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.stroke = "#83a"
+ me.accelMag = 0.003
+ me.frictionAir = 0.005
+ me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.mob
+ me.seeAtDistance2 = 1000000 //1000 vision range
+ // me.onDeath = function() {
+ // const amount = Math.min(10, Math.ceil(this.mass * 0.5))
+ // if (tech.isSporeFlea) {
+ // const len = amount / 2
+ // for (let i = 0; i < len; i++) {
+ // const speed = 10 + 5 * Math.random()
+ // const angle = 2 * Math.PI * Math.random()
+ // b.flea(this.position, { x: speed * Math.cos(angle), y: speed * Math.sin(angle) })
+ // }
+ // } else if (tech.isSporeWorm) {
+ // const len = amount / 2
+ // for (let i = 0; i < len; i++) b.worm(this.position)
+ // } else {
+ // for (let i = 0; i < amount; i++) b.spore(this.position)
+ // }
+ // }
+ me.do = function () {
+ this.zombieHealthBar();
+ this.lookForMobTargets();
+ this.attack();
+ this.checkStatus();
+ };
+ me.mobSearchIndex = 0;
+ me.target = null
+ me.lookForMobTargets = function () {
+ if (this.target === null && mob.length > 1 && !(simulation.cycle % this.seePlayerFreq)) { //find mob targets
+ let closeDist = Infinity;
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (
+ !mob[i].isZombie &&
+ !mob[i].isUnblockable &&
+ !mob[i].isMobBullet &&
+ Matter.Query.ray(map, this.position, mob[i].position).length === 0 &&
+ Matter.Query.ray(body, this.position, mob[i].position).length === 0
+ // !mob[i].isBadTarget &&
+ // !mob[i].isInvulnerable &&
+ // (Vector.magnitudeSquared(Vector.sub(this.position, mob[this.mobSearchIndex].position)) < this.seeAtDistance2)
+ ) {
+ const DIST = Vector.magnitude(Vector.sub(this.position, mob[i].position));
+ if (DIST < closeDist) {
+ closeDist = DIST;
+ this.target = mob[i]
+ }
+ }
+ }
+ } else if (
+ !(simulation.cycle % this.memory) &&
+ this.target &&
+ (!this.target.alive || Matter.Query.ray(map, this.position, this.target.position).length !== 0)
+ ) {
+ this.target = null //chance to forget target
+ }
+ }
+ me.zombieHealthBar = function () {
+ this.health -= 0.0003 //decay
+ if ((this.health < 0.01 || isNaN(this.health)) && this.alive) this.death();
+ const h = this.radius * 0.3;
+ const w = this.radius * 2;
+ const x = this.position.x - w / 2;
+ const y = this.position.y - w * 0.7;
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(x, y, w, h);
+ ctx.fillStyle = "rgba(136, 51, 170,0.7)";
+ ctx.fillRect(x, y, w * this.health, h);
+ }
+ me.hitCD = 0
+ me.attack = function () { //hit non zombie mobs
+ if (this.hitCD < simulation.cycle) {
+ if (this.target) {
+ this.force = Vector.mult(Vector.normalise(Vector.sub(this.target.position, this.position)), this.accelMag * this.mass)
+ } else { //wonder around
+ this.torque += 0.0000003 * this.inertia;
+ const mag = 0.0003 * this.mass
+ this.force.x += mag * Math.cos(this.angle)
+ this.force.y += mag * Math.sin(this.angle)
+ }
+ if (this.speed > 15) { // speed cap instead of friction to give more agility
+ Matter.Body.setVelocity(this, { x: this.velocity.x * 0.96, y: this.velocity.y * 0.96 });
+ } else if (this.speed < 10) {
+ Matter.Body.setVelocity(this, { x: this.velocity.x * 0.98, y: this.velocity.y * 0.98 });
+ } else if (this.speed < 8) {
+ Matter.Body.setVelocity(this, { x: this.velocity.x * 0.99, y: this.velocity.y * 0.99 });
+ }
+ const hit = (who) => {
+ if (!who.isZombie && who.damageReduction) {
+ this.hitCD = simulation.cycle + 15
+ //knock back away from recently hit mob
+ const force = Vector.mult(Vector.normalise(Vector.sub(who.position, this.position)), 0.03 * this.mass)
+ this.force.x -= force.x;
+ this.force.y -= force.y;
+ this.target = null //look for a new target
+
+ // who.damage(dmg);
+ //by pass normal damage method
+ const dmg = 1.5 * who.damageReduction / Math.sqrt(who.mass)
+ who.health -= dmg
+ who.onDamage(dmg); //custom damage effects
+ who.locatePlayer();
+ if ((who.health < 0.01 || isNaN(who.health)) && who.alive) who.death();
+
+ simulation.drawList.push({
+ x: this.position.x,
+ y: this.position.y,
+ radius: Math.log(dmg + 1.1) * 40 * who.damageReduction + 3,
+ color: simulation.playerDmgColor,
+ time: simulation.drawTime
+ });
+ }
+ }
+ const collide = Matter.Query.collides(this, mob) //damage mob targets if nearby
+ if (collide.length > 1) { //don't count self collide
+ for (let i = 0, len = collide.length; i < len; i++) {
+ hit(collide[i].bodyA)
+ hit(collide[i].bodyB)
+ }
+ }
+ }
+ }
+ },
+ starter(x, y, radius = Math.floor(15 + 20 * Math.random())) { //easy mob for on level 1
+ mobs.spawn(x, y, 8, radius, "#9ccdc6");
+ let me = mob[mob.length - 1];
+ // console.log(`mass=${me.mass}, radius = ${radius}`)
+ me.accelMag = 0.0002
+ me.repulsionRange = 400000 + radius * radius; //squared
+ // me.memory = 120;
+ me.seeAtDistance2 = 2000000 //1400 vision range
+ Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback
+ me.do = function () {
+ this.seePlayerByLookingAt();
+ this.attraction();
+ this.repulsion();
+ this.checkStatus();
+ };
+ },
+ blockGroup(x, y, num = 3 + Math.random() * 8) {
+ for (let i = 0; i < num; i++) {
+ const radius = 25 + Math.floor(Math.random() * 20)
+ spawn.blockGroupMob(x + Math.random() * radius, y + Math.random() * radius, radius);
+ }
+ },
+ blockGroupMob(x, y, radius = 25 + Math.floor(Math.random() * 20)) {
+ mobs.spawn(x, y, 4, radius, "#999");
+ let me = mob[mob.length - 1];
+ me.g = 0.00015; //required if using this.gravity
+ me.accelMag = 0.0008 * simulation.accelScale;
+ me.groupingRangeMax = 250000 + Math.random() * 100000;
+ me.groupingRangeMin = (radius * 8) * (radius * 8);
+ me.groupingStrength = 0.0005
+ me.memory = 200;
+ me.isGrouper = true;
+ me.seeAtDistance2 = 600 * 600
+ me.seePlayerFreq = Math.floor(50 + 50 * Math.random())
+ me.do = function () {
+ this.gravity();
+ this.checkStatus();
+ this.seePlayerCheck();
+ if (this.seePlayer.recall) {
+ this.attraction();
+ //tether to other blocks
+ ctx.beginPath();
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isGrouper && mob[i] != this && mob[i].isDropPowerUp) { //don't tether to self, bullets, shields, ...
+ const distance2 = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position))
+ if (distance2 < this.groupingRangeMax) {
+ if (!mob[i].seePlayer.recall) mob[i].seePlayerCheck(); //wake up sleepy mobs
+ if (distance2 > this.groupingRangeMin) {
+ const angle = Math.atan2(mob[i].position.y - this.position.y, mob[i].position.x - this.position.x);
+ const forceMag = this.groupingStrength * mob[i].mass;
+ mob[i].force.x -= forceMag * Math.cos(angle);
+ mob[i].force.y -= forceMag * Math.sin(angle);
+ }
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(mob[i].position.x, mob[i].position.y);
+ }
+ }
+ }
+ ctx.strokeStyle = "#0ff";
+ ctx.lineWidth = 1;
+ ctx.stroke();
+ }
+ }
+ },
+ blockBoss(x, y, radius = 60) {
+ const activeBeams = []; // used to draw beams when converting
+ const beamTotalDuration = 60
+ mobs.spawn(x, y, 4, radius, "#999"); //#54291d
+ const me = mob[mob.length - 1];
+ me.isBoss = true;
+ Matter.Body.setDensity(me, 0.002); //normal density even though its a boss
+ me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1); //extra reduction for a boss, because normal density
+ me.frictionAir = 0.01;
+ me.accelMag = 0.0002;
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y);
+ for (const who of mob) {
+ if (who.isNecroMob) { //blockMobs leave their body, and die
+ who.leaveBody = true
+ who.damage(Infinity)
+ }
+ }
+ }
+ me.target = player; // the target to lock on. Usually a block, but will be the player under certain conditions
+ me.do = function () {
+ this.checkStatus();
+ this.seePlayerCheck();
+ if (this.target) { //(this.target === player && this.seePlayer.yes) || this.target !== player
+ const force = Vector.mult(Vector.normalise(Vector.sub(this.target.position, this.position)), this.accelMag * this.mass)
+ this.force.x += force.x;
+ this.force.y += force.y;
+ }
+
+ if (!(simulation.cycle % 30)) {
+ //find blocks to turn into mobs
+ for (let i = 0; i < body.length; i++) {
+ if (Vector.magnitude(Vector.sub(this.position, body[i].position)) < 700 && !body[i].isNotHoldable) { // check distance for each block
+ Matter.Composite.remove(engine.world, body[i]);
+ this.target = null //player;
+ spawn.blockMob(body[i].position.x, body[i].position.y, body[i], 0);
+ body.splice(i, 1);
+ activeBeams.push([beamTotalDuration, mob[mob.length - 1]]);
+ }
+ }
+
+ // generally, the boss will tend to stay in the player's area but focus on blocks.
+ if (this.distanceToPlayer() > 1500 && this.target === null) {
+ this.target = player; // too far, attract to the player
+ } else {
+ if (body.length) { // look for a new target by finding the closest block
+ let min = Infinity;
+ let closestBlock = null;
+ for (const block of body) {
+ const dist = Vector.magnitudeSquared(Vector.sub(this.position, block.position))
+ if (dist < min && Matter.Query.ray(map, this.position, block.position).length === 0) {
+ min = dist;
+ closestBlock = block;
+ }
+ }
+ this.target = closestBlock;
+ }
+ }
+
+ //randomly spawn new mobs from nothing
+ if (!(simulation.cycle % 90)) {
+ let count = 0
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isNecroMob) count++
+ }
+ if (count < 20 * Math.random() * Math.random()) { //limit number of spawns if there are already too many blockMobs
+ const unit = Vector.normalise(Vector.sub(player.position, this.position))
+ for (let i = 0, len = 3 * Math.random(); i < len; i++) {
+ this.damageReduction += 0.001; //0.05 is starting value
+ const scale = 0.99; //if 120 use 1.02
+ Matter.Body.scale(this, scale, scale);
+ this.radius *= scale;
+
+ const where = Vector.add(Vector.mult(unit, radius + 200 * Math.random()), this.position)
+ spawn.blockMob(where.x + 100 * (Math.random() - 0.5), where.y + 100 * (Math.random() - 0.5), null);
+ this.torque += 0.000035 * this.inertia; //spin after spawning
+ activeBeams.push([beamTotalDuration, mob[mob.length - 1]]);
+ }
+ }
+ }
+
+ }
+ for (let i = 0; i < activeBeams.length; i++) { // draw beams on new mobs
+ const [duration, newBlockMob] = activeBeams[i];
+ if (duration === 0) {
+ activeBeams.splice(i, 1);
+ continue;
+ }
+ if (newBlockMob.alive) {
+ const vertexIndex = Math.floor((newBlockMob.vertices.length - 1) * duration / beamTotalDuration)
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(newBlockMob.vertices[vertexIndex].x, newBlockMob.vertices[vertexIndex].y);
+
+ //outline mob
+ ctx.moveTo(newBlockMob.vertices[0].x, newBlockMob.vertices[0].y);
+ for (let j = 1; j < newBlockMob.vertices.length; j++) {
+ ctx.lineTo(newBlockMob.vertices[j].x, newBlockMob.vertices[j].y);
+ }
+ ctx.lineTo(newBlockMob.vertices[0].x, newBlockMob.vertices[0].y);
+
+ ctx.strokeStyle = "#0ff";
+ ctx.lineWidth = 3;
+ ctx.stroke();
+ }
+ activeBeams[i][0]--; // shorten duration
+ }
+ }
+ },
+ blockMob(x, y, host, growCycles = 60) {
+ if (host === null) {
+ mobs.spawn(x, y, 4, 1.25 + 3.5 * Math.random(), "#999");
+ } else {
+ const sideLength = Vector.magnitude(Vector.sub(host.vertices[0], host.vertices[1])) + Vector.magnitude(Vector.sub(host.vertices[1], host.vertices[2])) / 2 //average of first 2 sides
+ mobs.spawn(x, y, 4, Math.min(70, sideLength), "#999");
+ if (host.bounds.max.x - host.bounds.min.x < 150 && host.bounds.max.y - host.bounds.min.y < 150) {
+ Matter.Body.setVertices(mob[mob.length - 1], host.vertices) //if not too big match vertices of host exactly
+ // mob[mob.length - 1].radius =
+ }
+ }
+ const me = mob[mob.length - 1];
+ me.damageReduction = 0.5; //only until done growing
+ me.isNecroMob = true
+ me.g = 0.00012; //required if using this.gravity
+ me.accelMag = 0.0003 * Math.sqrt(simulation.accelScale);
+ me.memory = 120;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ // me.showHealthBar = false;
+ me.cycle = 0
+ me.do = function () { //grow phase only occurs for growCycles
+ this.checkStatus();
+ this.seePlayerCheck();
+ this.cycle++
+ if (this.cycle > growCycles) {
+ this.damageReduction = 1.8 //take extra damage
+ this.do = this.normalDo
+ } else {
+ const scale = 1.04; //if 120 use 1.02
+ Matter.Body.scale(this, scale, scale);
+ this.radius *= scale;
+ }
+ }
+ me.normalDo = function () {
+ this.gravity();
+ this.checkStatus();
+ this.seePlayerCheck();
+ this.attraction();
+ }
+ },
+ cellBossCulture(x, y, radius = 20, num = 5) {
+ const cellID = Math.random()
+ for (let i = 0; i < num; i++) {
+ spawn.cellBoss(x, y, radius, cellID)
+ }
+ },
+ cellBoss(x, y, radius = 20, cellID) {
+ mobs.spawn(x + Math.random(), y + Math.random(), 20, radius * (1 + 1.2 * Math.random()), "rgba(0,80,125,0.3)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent"
+ me.isBoss = true;
+ me.isCell = true;
+ me.cellID = cellID
+ me.accelMag = 0.000165 * simulation.accelScale;
+ me.memory = Infinity;
+ me.leaveBody = false;
+ me.isVerticesChange = true
+ me.frictionAir = 0.012
+ me.seePlayerFreq = Math.floor(11 + 7 * Math.random())
+ me.seeAtDistance2 = 1400000;
+ me.cellMassMax = 70
+ me.collisionFilter.mask = cat.player | cat.bullet //| cat.body | cat.map
+ Matter.Body.setDensity(me, 0.0001 + 0.00002 * simulation.difficulty) // normal density is 0.001
+ me.damageReduction = 0.17 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1); //me.damageReductionGoal
+
+ const k = 642 //k=r^2/m
+ me.split = function () {
+ const scale = 0.45
+ Matter.Body.scale(this, scale, scale);
+ this.radius *= scale;
+ spawn.cellBoss(this.position.x, this.position.y, this.radius, this.cellID);
+ mob[mob.length - 1].health = this.health
+ }
+ me.onHit = function () { //run this function on hitting player
+ this.health = 1;
+ this.split();
+ };
+ me.onDamage = function (dmg) {
+ if (Math.random() < 0.34 * dmg * Math.sqrt(this.mass) && this.health > dmg) this.split();
+ }
+ me.do = function () {
+ this.seePlayerByDistOrLOS();
+ this.checkStatus();
+ this.attraction();
+
+ if (this.seePlayer.recall && this.mass < this.cellMassMax) { //grow cell radius
+ const scale = 1 + 0.0002 * this.cellMassMax / this.mass;
+ Matter.Body.scale(this, scale, scale);
+ this.radius *= scale;
+ }
+ if (!(simulation.cycle % this.seePlayerFreq)) { //move away from other mobs
+ const repelRange = 150
+ const attractRange = 700
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isCell && mob[i].id !== this.id) {
+ const sub = Vector.sub(this.position, mob[i].position)
+ const dist = Vector.magnitude(sub)
+ if (dist < repelRange) {
+ this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.002)
+ } else if (dist > attractRange) {
+ this.force = Vector.mult(Vector.normalise(sub), -this.mass * 0.003)
+ }
+ }
+ }
+ }
+ };
+ me.onDeath = function () {
+ this.isCell = false;
+ let count = 0 //count other cells by id
+ // console.log(this.cellID)
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isCell && mob[i].cellID === this.cellID) count++
+ }
+ if (count < 1) { //only drop a power up if this is the last cell
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ } else {
+ this.isDropPowerUp = false;
+ }
+ }
+ },
+ spawnerBossCulture(x, y, radius = 50, num = 8 + Math.min(20, simulation.difficulty * 0.4)) {
+ tech.deathSpawnsFromBoss += 0.4
+ const spawnID = Math.random()
+ for (let i = 0; i < num; i++) spawn.spawnerBoss(x, y, radius, spawnID)
+ },
+ spawnerBoss(x, y, radius, spawnID) {
+ mobs.spawn(x + Math.random(), y + Math.random(), 4, radius, "rgba(255,60,0,0.3)") //);
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+
+ me.isSpawnBoss = true;
+ me.spawnID = spawnID
+ me.accelMag = 0.00022 * simulation.accelScale;
+ me.memory = Infinity;
+ me.showHealthBar = false;
+ me.isVerticesChange = true
+ me.frictionAir = 0.011
+ me.seePlayerFreq = Math.floor(14 + 7 * Math.random())
+ me.seeAtDistance2 = 200000 //1400000;
+ me.stroke = "transparent"
+ me.collisionFilter.mask = cat.player | cat.bullet | cat.body | cat.map //"rgba(255,60,0,0.3)"
+ // Matter.Body.setDensity(me, 0.0014) // normal density is 0.001
+ Matter.Body.setAngularVelocity(me, 0.12 * (Math.random() - 0.5))
+ // spawn.shield(me, x, y, 1);
+
+ me.onHit = function () { //run this function on hitting player
+ this.explode();
+ };
+ me.damageReduction = 0.14 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1);
+ me.doAwake = function () {
+ this.alwaysSeePlayer();
+ this.checkStatus();
+ this.attraction();
+
+ if (!(simulation.cycle % this.seePlayerFreq)) { //move away from other mobs
+ const repelRange = 40
+ const attractRange = 240
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isSpawnBoss && mob[i].id !== this.id) {
+ const sub = Vector.sub(this.position, mob[i].position)
+ const dist = Vector.magnitude(sub)
+ if (dist < repelRange) {
+ this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.002)
+ } else if (dist > attractRange) {
+ this.force = Vector.mult(Vector.normalise(sub), -this.mass * 0.002)
+ }
+ }
+ }
+ }
+ }
+ me.do = function () {
+ this.checkStatus();
+ if (this.seePlayer.recall) {
+ this.do = this.doAwake
+ //awaken other spawnBosses
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isSpawnBoss && mob[i].spawnID === this.spawnID) mob[i].seePlayer.recall = 1
+ }
+ }
+ };
+ me.onDeath = function () {
+ this.isSpawnBoss = false;
+ let count = 0 //count other cells by id
+ // console.log(this.spawnID)
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isSpawnBoss && mob[i].spawnID === this.spawnID) count++
+ }
+ if (count < 1) { //only drop a power up if this is the last cell
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ tech.deathSpawnsFromBoss -= 0.4
+ } else {
+ this.leaveBody = false;
+ this.isDropPowerUp = false;
+ }
+
+ const spawns = tech.deathSpawns + tech.deathSpawnsFromBoss
+ const len = Math.min(12, spawns * Math.ceil(Math.random() * simulation.difficulty * spawns))
+ for (let i = 0; i < len; i++) {
+ spawn.spawns(this.position.x + (Math.random() - 0.5) * radius * 2.5, this.position.y + (Math.random() - 0.5) * radius * 2.5);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + (Math.random() - 0.5) * 10,
+ y: this.velocity.x + (Math.random() - 0.5) * 10
+ });
+ }
+
+ }
+ },
+ growBossCulture(x, y, radius = 17, nodes = 12 + Math.min(10, simulation.difficulty * 0.25)) {
+ const buffID = Math.random()
+ const sideLength = 200 + 50 * Math.sqrt(nodes) // distance between each node mob
+ for (let i = 0; i < nodes; ++i) {
+ const angle = 2 * Math.PI * Math.random()
+ const mag = Math.max(radius, sideLength * (1 - Math.pow(Math.random(), 1.5))) //working on a distribution that is circular, random, but not too focused in the center
+ spawn.growBoss(x + mag * Math.cos(angle), y + mag * Math.sin(angle), radius, buffID);
+ }
+ spawn.constrain2AdjacentMobs(nodes, 0.0001, false); //loop mobs together
+ },
+ growBoss(x, y, radius, buffID) {
+ mobs.spawn(x + Math.random(), y + Math.random(), 6, radius, "hsl(144, 15%, 50%)") //);
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.isBuffBoss = true;
+ me.buffID = buffID
+ me.memory = Infinity;
+ me.isVerticesChange = true
+ me.frictionAir = 0.012
+ me.seePlayerFreq = Math.floor(11 + 7 * Math.random())
+ me.seeAtDistance2 = 200000 //1400000;
+ me.stroke = "transparent"
+ me.collisionFilter.mask = cat.player | cat.bullet //| cat.body //| cat.map //"rgba(255,60,0,0.3)"
+
+ me.buffCount = 0
+ me.accelMag = 0.00005 //* simulation.accelScale;
+ me.setBuffed = function () {
+ this.buffCount++
+ this.accelMag += 0.000024 //* Math.sqrt(simulation.accelScale)
+ this.fill = `hsl(144, ${5 + 10 * this.buffCount}%, 50%)`
+ const scale = 1.135;
+ Matter.Body.scale(this, scale, scale);
+ this.radius *= scale;
+
+ // this.isInvulnerable = true
+ // if (this.damageReduction) this.startingDamageReduction = this.damageReduction
+ // this.damageReduction = 0
+ // this.invulnerabilityCountDown = simulation.difficulty
+ }
+ me.onDeath = function () {
+ this.isBuffBoss = false;
+ let count = 0 //count other cells by id
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isBuffBoss && mob[i].buffID === this.buffID) {
+ count++
+ mob[i].setBuffed()
+ }
+ }
+ if (count < 1) { //only drop a power up if this is the last cell
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ } else {
+ this.leaveBody = false;
+ this.isDropPowerUp = false;
+ powerUps.spawnRandomPowerUp(this.position.x, this.position.y) // manual power up spawn to avoid spawning too many tech with "symbiosis"
+ }
+ }
+ me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ //required setup for invulnerable
+ // me.isInvulnerable = false
+ me.invulnerabilityCountDown = 0
+ me.do = function () {
+ // if (this.isInvulnerable) {
+ // if (this.invulnerabilityCountDown > 0) {
+ // this.invulnerabilityCountDown--
+ // ctx.beginPath();
+ // let vertices = this.vertices;
+ // ctx.moveTo(vertices[0].x, vertices[0].y);
+ // for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ // ctx.lineTo(vertices[0].x, vertices[0].y);
+ // ctx.lineWidth = 20;
+ // ctx.strokeStyle = "rgba(255,255,255,0.7)";
+ // ctx.stroke();
+ // } else {
+ // this.isInvulnerable = false
+ // this.damageReduction = this.startingDamageReduction
+ // }
+ // }
+ this.alwaysSeePlayer();
+ this.checkStatus();
+ this.attraction();
+ // if (!(simulation.cycle % this.seePlayerFreq)) { //move away from other mobs
+ // const repelRange = 100 + 4 * this.radius
+ // const attractRange = 240
+ // for (let i = 0, len = mob.length; i < len; i++) {
+ // if (mob[i].isBuffBoss && mob[i].id !== this.id) {
+ // const sub = Vector.sub(this.position, mob[i].position)
+ // const dist = Vector.magnitude(sub)
+ // if (dist < repelRange) {
+ // this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.002)
+ // } else if (dist > attractRange) {
+ // this.force = Vector.mult(Vector.normalise(sub), -this.mass * 0.002)
+ // }
+ // }
+ // }
+ // }
+ }
+ },
+ powerUpBossBaby(x, y, vertices = 9, radius = 60) {
+ mobs.spawn(x, y, vertices, radius, "rgba(225,240,245,0.4)"); //"rgba(120,140,150,0.4)"
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.frictionAir = 0.006
+ me.seeAtDistance2 = 1000000;
+ me.accelMag = 0.0004 + 0.0003 * simulation.accelScale;
+ // Matter.Body.setDensity(me, 0.001); //normal is 0.001
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map
+ me.memory = Infinity;
+ me.seePlayerFreq = 17
+ me.lockedOn = null;
+ if (vertices === 9) {
+ //on primary spawn
+ powerUps.spawnBossPowerUp(me.position.x, me.position.y)
+ powerUps.spawn(me.position.x, me.position.y, "heal");
+ powerUps.spawn(me.position.x, me.position.y, "ammo");
+ } else if (!m.isCloak) {
+ me.foundPlayer();
+ }
+ me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.isInvulnerable = true
+ me.startingDamageReduction = me.damageReduction
+ me.damageReduction = 0
+ me.invulnerabilityCountDown = 40 + simulation.difficulty
+ me.onHit = function () { //run this function on hitting player
+ if (powerUps.ejectTech()) {
+ powerUps.ejectGraphic("150, 138, 255");
+ // powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "ammo");
+ // powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "research");
+ this.accelMag *= 1.4
+ Matter.Body.setDensity(this, this.density * 1.4); //normal is 0.001
+ }
+ };
+ me.onDeath = function () {
+ this.leaveBody = false;
+ if (vertices > 3) {
+ this.isDropPowerUp = false;
+ spawn.powerUpBossBaby(this.position.x, this.position.y, vertices - 1)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x,
+ y: this.velocity.y
+ })
+ }
+ for (let i = 0; i < powerUp.length; i++) powerUp[i].collisionFilter.mask = cat.map | cat.powerUp
+ };
+ me.do = function () {
+ if (this.isInvulnerable) {
+ if (this.invulnerabilityCountDown > 0) {
+ this.invulnerabilityCountDown--
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ } else {
+ this.isInvulnerable = false
+ this.damageReduction = this.startingDamageReduction
+ }
+ }
+ // this.stroke = `hsl(0,0%,${80 + 25 * Math.sin(simulation.cycle * 0.01)}%)`
+ // this.fill = `hsla(0,0%,${80 + 25 * Math.sin(simulation.cycle * 0.01)}%,0.3)`
+
+ //steal all power ups
+ if (this.alive) {
+ for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) {
+ powerUp[i].collisionFilter.mask = 0
+ Matter.Body.setPosition(powerUp[i], this.vertices[i])
+ Matter.Body.setVelocity(powerUp[i], {
+ x: 0,
+ y: 0
+ })
+ }
+ }
+ this.seePlayerByHistory(50);
+ this.attraction();
+ this.checkStatus();
+ };
+ },
+ powerUpBoss(x, y, vertices = 9, radius = 130) {
+ mobs.spawn(x, y, vertices, radius, "transparent");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.frictionAir = 0.01
+ me.seeAtDistance2 = 1000000;
+ me.accelMag = 0.0002 + 0.0004 * simulation.accelScale;
+ Matter.Body.setDensity(me, 0.00035); //normal is 0.001
+ me.collisionFilter.mask = cat.bullet | cat.player //| cat.body
+ me.memory = Infinity;
+ me.seePlayerFreq = 30
+ me.lockedOn = null;
+ if (vertices === 9) {
+ //on primary spawn
+ powerUps.spawnBossPowerUp(me.position.x, me.position.y)
+ powerUps.spawn(me.position.x, me.position.y, "heal");
+ powerUps.spawn(me.position.x, me.position.y, "ammo");
+ } else if (!m.isCloak) {
+ me.foundPlayer();
+ }
+
+ me.damageReduction = 0.16 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ // me.isInvulnerable = true
+ // me.startingDamageReduction = me.damageReduction
+ // me.damageReduction = 0
+ // me.invulnerabilityCountDown = 60 + simulation.difficulty * 2
+
+ me.onHit = function () { //run this function on hitting player
+ if (powerUps.ejectTech()) {
+ powerUps.ejectGraphic("150, 138, 255");
+ // powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "ammo");
+ // powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "research");
+ this.accelMag *= 1.4
+ Matter.Body.setDensity(this, this.density * 1.4); //normal is 0.001
+ }
+ };
+ me.onDeath = function () {
+ this.leaveBody = false;
+ if (vertices > 3) {
+ this.isDropPowerUp = false;
+ spawn.powerUpBoss(this.position.x, this.position.y, vertices - 1)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x,
+ y: this.velocity.y
+ })
+ }
+ for (let i = 0; i < powerUp.length; i++) powerUp[i].collisionFilter.mask = cat.map | cat.powerUp
+ };
+
+ //steal all power ups
+ // for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) {
+ // powerUp[i].collisionFilter.mask = 0
+ // Matter.Body.setPosition(powerUp[i], this.vertices[i])
+ // Matter.Body.setVelocity(powerUp[i], {
+ // x: 0,
+ // y: 0
+ // })
+ // }
+ // me.powerUpList = []
+ // me.constrainPowerUps = function() {
+ // for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) {
+ // //remove other constraints on power up
+ // for (let i = 0, len = cons.length; i < len; ++i) {
+ // if (cons[i].bodyB === powerUp[i] || cons[i].bodyA === powerUp[i]) {
+ // Matter.Composite.remove(engine.world, cons[i]);
+ // cons.splice(i, 1);
+ // break;
+ // }
+ // }
+
+ // //add to list
+ // this.powerUpList.push(powerUp[i])
+ // //position and stop
+ // powerUp[i].collisionFilter.mask = 0
+ // Matter.Body.setPosition(powerUp[i], this.vertices[i])
+ // Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 })
+ // //add constraint
+ // cons[cons.length] = Constraint.create({
+ // pointA: this.vertices[i],
+ // bodyB: powerUp[i],
+ // stiffness: 1,
+ // damping: 1
+ // });
+ // Composite.add(engine.world, cons[cons.length - 1]);
+ // }
+ // for (let i = 0; i < this.powerUpList.length; i++) {}
+ // }
+ // me.constrainPowerUps()
+ me.do = function () {
+ this.stroke = `hsl(0,0%,${80 + 25 * Math.sin(simulation.cycle * 0.01)}%)`
+ // if (this.isInvulnerable) {
+ // if (this.invulnerabilityCountDown > 0) {
+ // this.invulnerabilityCountDown--
+ // ctx.beginPath();
+ // let vertices = this.vertices;
+ // ctx.moveTo(vertices[0].x, vertices[0].y);
+ // for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ // ctx.lineTo(vertices[0].x, vertices[0].y);
+ // ctx.lineWidth = 20;
+ // ctx.strokeStyle = "rgba(255,255,255,0.7)";
+ // ctx.stroke();
+ // } else {
+ // this.isInvulnerable = false
+ // this.damageReduction = this.startingDamageReduction
+ // }
+ // }
+ //steal all power ups
+ // for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) {
+ // powerUp[i].collisionFilter.mask = 0
+ // Matter.Body.setPosition(powerUp[i], this.vertices[i])
+ // Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 })
+ // }
+ if (this.alive) {
+ for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) {
+ powerUp[i].collisionFilter.mask = 0
+ Matter.Body.setPosition(powerUp[i], this.vertices[i])
+ Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 })
+ }
+ }
+
+ this.seePlayerCheckByDistance();
+ this.attraction();
+ this.checkStatus();
+ };
+ },
+
+ // chaser(x, y, radius = 35 + Math.ceil(Math.random() * 40)) {
+ // mobs.spawn(x, y, 8, radius, "rgb(255,150,100)"); //"#2c9790"
+ // let me = mob[mob.length - 1];
+ // // Matter.Body.setDensity(me, 0.0007); //extra dense //normal is 0.001 //makes effective life much lower
+ // me.friction = 0.1;
+ // me.frictionAir = 0;
+ // me.accelMag = 0.001 * Math.sqrt(simulation.accelScale);
+ // me.g = me.accelMag * 0.6; //required if using this.gravity
+ // me.memory = 180;
+ // spawn.shield(me, x, y);
+ // me.do = function() {
+ // this.gravity();
+ // this.seePlayerByHistory(15);
+ // this.checkStatus();
+ // this.attraction();
+ // };
+ // },
+ grower(x, y, radius = 15) {
+ mobs.spawn(x, y, 7, radius, "hsl(144, 15%, 50%)");
+ let me = mob[mob.length - 1];
+ me.isVerticesChange = true
+ me.big = false; //required for grow
+ me.accelMag = 0.00045 * simulation.accelScale;
+ me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.player //can't touch other mobs
+ // me.onDeath = function () { //helps collisions functions work better after vertex have been changed
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
+ // }
+ me.do = function () {
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ this.attraction();
+ this.grow();
+ };
+ },
+ springer(x, y, radius = 20 + Math.ceil(Math.random() * 35)) {
+ mobs.spawn(x, y, 10, radius, "#b386e8");
+ let me = mob[mob.length - 1];
+ me.friction = 0;
+ me.frictionAir = 0.006;
+ me.lookTorque = 0.0000008; //controls spin while looking for player
+ me.g = 0.0002; //required if using this.gravity
+ me.seePlayerFreq = Math.floor((40 + 25 * Math.random()));
+ const springStiffness = 0.00014;
+ const springDampening = 0.0005;
+
+ me.springTarget = {
+ x: me.position.x,
+ y: me.position.y
+ };
+ const len = cons.length;
+ cons[len] = Constraint.create({
+ pointA: me.springTarget,
+ bodyB: me,
+ stiffness: springStiffness,
+ damping: springDampening
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+
+ cons[len].length = 100 + 1.5 * radius;
+ me.cons = cons[len];
+
+ me.springTarget2 = {
+ x: me.position.x,
+ y: me.position.y
+ };
+ const len2 = cons.length;
+ cons[len2] = Constraint.create({
+ pointA: me.springTarget2,
+ bodyB: me,
+ stiffness: springStiffness,
+ damping: springDampening
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ cons[len2].length = 100 + 1.5 * radius;
+ me.cons2 = cons[len2];
+ me.do = function () {
+ this.gravity();
+ this.searchSpring();
+ this.checkStatus();
+ this.springAttack();
+ };
+
+ me.onDeath = function () {
+ this.removeCons();
+ };
+ spawn.shield(me, x, y);
+ },
+ hopper(x, y, radius = 30 + Math.ceil(Math.random() * 30)) {
+ mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
+ let me = mob[mob.length - 1];
+ me.accelMag = 0.05;
+ me.g = 0.0032; //required if using this.gravity
+ me.frictionAir = 0.01;
+ me.friction = 1
+ me.frictionStatic = 1
+ me.restitution = 0;
+ me.delay = 120 * simulation.CDScale;
+ me.randomHopFrequency = 200 + Math.floor(Math.random() * 150);
+ me.randomHopCD = simulation.cycle + me.randomHopFrequency;
+ Matter.Body.rotate(me, Math.random() * Math.PI);
+ spawn.shield(me, x, y);
+ me.do = function () {
+ this.gravity();
+ this.seePlayerCheck();
+ this.checkStatus();
+ if (this.seePlayer.recall) {
+ if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
+ this.cd = simulation.cycle + this.delay;
+ const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ this.force.x += forceMag * Math.cos(angle);
+ this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.06 + 0.1) * this.mass; //antigravity
+ }
+ } else {
+ //randomly hob if not aware of player
+ if (this.randomHopCD < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
+ this.randomHopCD = simulation.cycle + this.randomHopFrequency;
+ //slowly change randomHopFrequency after each hop
+ this.randomHopFrequency = Math.max(100, this.randomHopFrequency + (0.5 - Math.random()) * 200);
+ const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass * (0.1 + Math.random() * 0.3);
+ const angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI;
+ this.force.x += forceMag * Math.cos(angle);
+ this.force.y += forceMag * Math.sin(angle) - 0.07 * this.mass; //antigravity
+ }
+ }
+ };
+ },
+ hopBullet(x, y, radius = 10 + Math.ceil(Math.random() * 8)) {
+ mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ // me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.timeLeft = 1200 + Math.floor(600 * Math.random());
+
+ me.isRandomMove = Math.random() < 0.3 //most chase player, some don't
+ me.accelMag = 0.01; //jump height
+ me.g = 0.0015; //required if using this.gravity
+ me.frictionAir = 0.01;
+ me.friction = 1
+ me.frictionStatic = 1
+ me.restitution = 0;
+ me.delay = 130 + 60 * simulation.CDScale;
+ // Matter.Body.rotate(me, Math.random() * Math.PI);
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
+ me.onHit = function () {
+ this.explode(this.mass);
+ };
+ me.do = function () {
+ this.gravity();
+ this.checkStatus();
+ if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
+ this.cd = simulation.cycle + this.delay;
+ if (this.isRandomMove || Math.random() < 0.2) {
+ this.force.x += (0.01 + 0.03 * Math.random()) * this.mass * (Math.random() < 0.5 ? 1 : -1); //random move
+ } else {
+ this.force.x += (0.01 + 0.03 * Math.random()) * this.mass * (player.position.x > this.position.x ? 1 : -1); //chase player
+ }
+ this.force.y -= (0.04 + 0.04 * Math.random()) * this.mass
+ }
+ this.timeLimit();
+ };
+ },
+ hopMomBoss(x, y, radius = 120) {
+ mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.damageReduction = 0.08 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.accelMag = 0.05; //jump height
+ me.g = 0.003; //required if using this.gravity
+ me.frictionAir = 0.01;
+ me.friction = 1
+ me.frictionStatic = 1
+ me.restitution = 0;
+ me.delay = 120 + 40 * simulation.CDScale;
+ Matter.Body.rotate(me, Math.random() * Math.PI);
+ spawn.shield(me, x, y, 1);
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // for (let i = 0, len = 3 + 0.1 * simulation.difficulty; i < len; ++i) spawn.hopBullet(this.position.x + 100 * (Math.random() - 0.5), this.position.y + 100 * (Math.random() - 0.5))
+ };
+ me.do = function () {
+ this.gravity();
+ this.seePlayerCheck();
+ this.checkStatus();
+ if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
+ this.cd = simulation.cycle + this.delay;
+ //spawn hopBullets after each jump
+ for (let i = 0, len = 1 + 0.05 * simulation.difficulty; i < len; ++i) spawn.hopBullet(this.position.x + 100 * (Math.random() - 0.5), this.position.y + 100 * (Math.random() - 0.5))
+
+ this.force.x += (0.02 + 0.06 * Math.random()) * this.mass * (player.position.x > this.position.x ? 1 : -1);
+ this.force.y -= (0.08 + 0.08 * Math.random()) * this.mass
+ }
+ };
+ },
+ // hopBoss(x, y, radius = 90) {
+ // mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
+ // let me = mob[mob.length - 1];
+ // me.isBoss = true;
+ // me.g = 0.005; //required if using this.gravity
+ // me.frictionAir = 0.01;
+ // me.friction = 1
+ // me.frictionStatic = 1
+ // me.restitution = 0;
+ // me.accelMag = 0.07;
+ // me.delay = 120 * simulation.CDScale;
+ // me.randomHopFrequency = 200
+ // me.randomHopCD = simulation.cycle + me.randomHopFrequency;
+ // // me.memory = 420;
+ // me.isInAir = false
+ // Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger
+ // spawn.shield(me, x, y, 1);
+ // spawn.spawnOrbitals(me, radius + 60, 1)
+ // me.onDeath = function() {
+ // powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // };
+ // me.lastSpeed = me.speed
+ // me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ // me.do = function() {
+ // // this.armor();
+ // this.gravity();
+ // this.seePlayerCheck();
+ // this.checkStatus();
+ // if (this.seePlayer.recall) {
+ // const deltaSpeed = this.lastSpeed - this.speed
+ // this.lastSpeed = this.speed
+ // if (deltaSpeed > 13 && this.speed < 5) { //if the player slows down greatly in one cycle
+ // //damage and push player away, push away blocks
+ // const range = 800 //Math.min(800, 50 * deltaSpeed)
+ // for (let i = body.length - 1; i > -1; i--) {
+ // if (!body[i].isNotHoldable) {
+ // sub = Vector.sub(body[i].position, this.position);
+ // dist = Vector.magnitude(sub);
+ // if (dist < range) {
+ // knock = Vector.mult(Vector.normalise(sub), Math.min(20, 50 * body[i].mass / dist));
+ // body[i].force.x += knock.x;
+ // body[i].force.y += knock.y;
+ // }
+ // }
+ // }
+ // simulation.drawList.push({ //draw radius
+ // x: this.position.x,
+ // y: this.position.y,
+ // radius: range,
+ // color: "rgba(0,200,180,0.6)",
+ // time: 4
+ // });
+ // }
+ // if (this.isInAir) {
+ // if (this.velocity.y > -0.01 && Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length) { //not moving up, and has hit the map or a body
+ // this.isInAir = false //landing
+ // this.cd = simulation.cycle + this.delay
+ // }
+ // } else { //on ground
+ // if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) { //jump
+ // this.isInAir = true
+ // const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
+ // const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ // this.force.x += forceMag * Math.cos(angle);
+ // this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.05 + 0.04) * this.mass; //antigravity
+ // }
+ // }
+ // // if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
+ // // this.cd = simulation.cycle + this.delay;
+ // // const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
+ // // const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ // // this.force.x += forceMag * Math.cos(angle);
+ // // this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.05 + 0.04) * this.mass; //antigravity
+ // // }
+ // } else {
+ // //randomly hob if not aware of player
+ // if (this.randomHopCD < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
+ // this.randomHopCD = simulation.cycle + this.randomHopFrequency;
+ // //slowly change randomHopFrequency after each hop
+ // this.randomHopFrequency = Math.max(100, this.randomHopFrequency + 200 * (0.5 - Math.random()));
+ // const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass * (0.5 + Math.random() * 0.2);
+ // const angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI;
+ // this.force.x += forceMag * Math.cos(angle);
+ // this.force.y += forceMag * Math.sin(angle) - (0.1 + 0.08 * Math.random()) * this.mass; //antigravity
+ // }
+ // }
+ // };
+ // },
+ spinner(x, y, radius = 30 + Math.ceil(Math.random() * 35)) {
+ mobs.spawn(x, y, 5, radius, "#000000");
+ let me = mob[mob.length - 1];
+ me.fill = "#28b";
+ me.rememberFill = me.fill;
+ me.cd = 0;
+ me.burstDir = {
+ x: 0,
+ y: 0
+ };
+ me.frictionAir = 0.022;
+ me.lookTorque = 0.0000014;
+ me.restitution = 0;
+ spawn.shield(me, x, y);
+ me.look = function () {
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ if (this.seePlayer.recall && this.cd < simulation.cycle) {
+ this.burstDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ this.cd = simulation.cycle + 40;
+ this.do = this.spin
+ }
+ }
+ me.do = me.look
+ me.spin = function () {
+ this.checkStatus();
+ this.torque += 0.000035 * this.inertia;
+ //draw attack vector
+ const mag = this.radius * 2.5 + 50;
+ ctx.strokeStyle = "rgba(0,0,0,0.2)";
+ ctx.lineWidth = 3;
+ ctx.setLineDash([10, 20]); //30
+ const dir = Vector.add(this.position, Vector.mult(this.burstDir, mag));
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(dir.x, dir.y);
+ ctx.stroke();
+ ctx.setLineDash([]);
+ if (this.cd < simulation.cycle) {
+ this.fill = this.rememberFill;
+ this.cd = simulation.cycle + 180 * simulation.CDScale
+ this.do = this.look
+ this.force = Vector.mult(this.burstDir, this.mass * 0.25);
+ }
+ }
+ },
+ sucker(x, y, radius = 30 + Math.ceil(Math.random() * 25)) {
+ radius = 9 + radius / 8; //extra small
+ mobs.spawn(x, y, 6, radius, "transparent");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent"; //used for drawSneaker
+ me.eventHorizon = radius * 30; //required for blackhole
+ me.seeAtDistance2 = (me.eventHorizon + 400) * (me.eventHorizon + 400); //vision limit is event horizon
+ me.accelMag = 0.00012 * simulation.accelScale;
+ me.frictionAir = 0.025;
+ me.collisionFilter.mask = cat.player | cat.bullet //| cat.body
+ me.memory = Infinity;
+ Matter.Body.setDensity(me, 0.015); //extra dense //normal is 0.001 //makes effective life much larger
+ me.do = function () {
+ //keep it slow, to stop issues from explosion knock backs
+ if (this.speed > 5) {
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * 0.99,
+ y: this.velocity.y * 0.99
+ });
+ }
+ this.seePlayerCheckByDistance()
+ this.checkStatus();
+ //accelerate towards the player
+ if (this.seePlayer.recall) {
+ const forceMag = this.accelMag * this.mass;
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ this.force.x += forceMag * Math.cos(angle);
+ this.force.y += forceMag * Math.sin(angle);
+ }
+ //eventHorizon waves in and out
+ const eventHorizon = this.eventHorizon * (0.93 + 0.17 * Math.sin(simulation.cycle * 0.011))
+ //draw darkness
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, eventHorizon * 0.25, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.9)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, eventHorizon * 0.55, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.5)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.1)";
+ ctx.fill();
+
+ //when player is inside event horizon
+ if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) {
+ if (m.immuneCycle < m.cycle) {
+ if (m.energy > 0) m.energy -= 0.005
+ if (m.energy < 0.1) m.damage(0.0001 * simulation.dmgScale);
+ }
+ const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
+ player.force.x -= 0.00125 * player.mass * Math.cos(angle) * (m.onGround ? 1.8 : 1);
+ player.force.y -= 0.0001 * player.mass * Math.sin(angle);
+ //draw line to player
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(m.pos.x, m.pos.y);
+ ctx.lineWidth = Math.min(60, this.radius * 2);
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.3)";
+ ctx.fill();
+ }
+ }
+ },
+ // timeBoss(x, y, radius = 25) {
+ // mobs.spawn(x, y, 12, radius, "#000");
+ // let me = mob[mob.length - 1];
+ // me.isBoss = true;
+ // me.stroke = "transparent"; //used for drawSneaker
+ // me.eventHorizon = 1100; //required for black hole
+ // me.eventHorizonGoal = 1100; //required for black hole
+ // me.seeAtDistance2 = (me.eventHorizon + 1200) * (me.eventHorizon + 1200); //vision limit is event horizon
+ // me.accelMag = 0.00006 * simulation.accelScale;
+ // // me.collisionFilter.mask = cat.player | cat.bullet //| cat.body
+ // // me.frictionAir = 0.005;
+ // me.memory = Infinity;
+ // Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger
+ // me.onDeath = function() {
+ // powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // };
+ // me.damageReduction = 0.23 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ // me.do = function() {
+ // //keep it slow, to stop issues from explosion knock backs
+ // if (!(simulation.cycle % this.seePlayerFreq)) {
+ // if (this.distanceToPlayer2() < this.seeAtDistance2) { //&& !m.isCloak ignore cloak for black holes
+ // this.locatePlayer();
+ // if (!this.seePlayer.yes) this.seePlayer.yes = true;
+ // } else if (this.seePlayer.recall) {
+ // this.lostPlayer();
+ // }
+ // }
+ // this.checkStatus();
+ // if (this.seePlayer.recall) {
+ // //accelerate towards the player
+ // const forceMag = this.accelMag * this.mass;
+ // const dx = this.seePlayer.position.x - this.position.x
+ // const dy = this.seePlayer.position.y - this.position.y
+ // const mag = Math.sqrt(dx * dx + dy * dy)
+ // this.force.x += forceMag * dx / mag;
+ // this.force.y += forceMag * dy / mag;
+
+ // //eventHorizon waves in and out
+ // const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008))
+ // // zoom camera in and out with the event horizon
+
+ // //draw darkness
+ // if (!simulation.isTimeSkipping) {
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI);
+ // ctx.fillStyle = "rgba(0,0,0,0.05)";
+ // ctx.fill();
+ // //when player is inside event horizon
+ // if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) {
+ // // if (!(simulation.cycle % 10)) simulation.timePlayerSkip(5)
+ // // if (!(simulation.cycle % 2)) simulation.timePlayerSkip(1)
+ // simulation.timePlayerSkip(2)
+
+ // // if (m.immuneCycle < m.cycle) {
+ // // if (m.energy > 0) m.energy -= 0.004
+ // // if (m.energy < 0.1) m.damage(0.00017 * simulation.dmgScale);
+ // // }
+ // }
+ // }
+ // }
+ // }
+ // },
+ suckerBoss(x, y, radius = 25) {
+ mobs.spawn(x, y, 12, radius, "#000");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+
+ me.stroke = "transparent"; //used for drawSneaker
+ me.eventHorizon = 1100; //required for black hole
+ me.seeAtDistance2 = (me.eventHorizon + 3000) * (me.eventHorizon + 3000); //vision limit is event horizon
+ me.accelMag = 0.00004 * simulation.accelScale;
+ me.collisionFilter.mask = cat.player | cat.bullet //| cat.body
+ // me.frictionAir = 0.005;
+ me.memory = 1600;
+ Matter.Body.setDensity(me, 0.06); //extra dense //normal is 0.001 //makes effective life much larger
+ me.onDeath = function () {
+ //applying forces to player doesn't seem to work inside this method, not sure why
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ if (simulation.difficulty > 5) {
+ //teleport everything to center
+ function toMe(who, where, range) {
+ for (let i = 0, len = who.length; i < len; i++) {
+ if (!who[i].isNotHoldable) {
+ const SUB = Vector.sub(who[i].position, where)
+ const DISTANCE = Vector.magnitude(SUB)
+ if (DISTANCE < range) {
+ Matter.Body.setPosition(who[i], where)
+ }
+ }
+ }
+ }
+ toMe(body, this.position, this.eventHorizon)
+ toMe(mob, this.position, this.eventHorizon)
+ // toMe(bullet, this.position, this.eventHorizon))
+ }
+ };
+ me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.do = function () {
+ //keep it slow, to stop issues from explosion knock backs
+ if (this.speed > 1) {
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * 0.95,
+ y: this.velocity.y * 0.95
+ });
+ }
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ if (this.distanceToPlayer2() < this.seeAtDistance2) { //&& !m.isCloak ignore cloak for black holes
+ this.locatePlayer();
+ if (!this.seePlayer.yes) this.seePlayer.yes = true;
+ } else if (this.seePlayer.recall) {
+ this.lostPlayer();
+ }
+ }
+ this.checkStatus();
+ if (this.seePlayer.recall) {
+ //throw large seekers
+ if (!(simulation.cycle % 90)) {
+ spawn.seeker(this.position.x, this.position.y, 15 * (0.7 + 0.5 * Math.random()), 7); //give the bullet a rotational velocity as if they were attached to a vertex
+ const who = mob[mob.length - 1]
+ Matter.Body.setDensity(who, 0.00001); //normal is 0.001
+ who.timeLeft = 600
+ who.accelMag = 0.0002 * simulation.accelScale; //* (0.8 + 0.4 * Math.random())
+ who.frictionAir = 0.01 //* (0.
+ const velocity = Vector.mult(Vector.normalise(Vector.sub(m.pos, this.position)), -20); //set direction to turn to fire //Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position, this.vertices[index]))), -35)
+ Matter.Body.setVelocity(who, {
+ x: this.velocity.x + velocity.x,
+ y: this.velocity.y + velocity.y
+ });
+ }
+ //accelerate towards the player
+ const forceMag = this.accelMag * this.mass;
+ const dx = this.seePlayer.position.x - this.position.x
+ const dy = this.seePlayer.position.y - this.position.y
+ const mag = Math.sqrt(dx * dx + dy * dy)
+ this.force.x += forceMag * dx / mag;
+ this.force.y += forceMag * dy / mag;
+ //eventHorizon waves in and out
+ const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008)) // zoom camera in and out with the event horizon
+ //draw darkness
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, eventHorizon * 0.2, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.6)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, eventHorizon * 0.4, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.4)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, eventHorizon * 0.6, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.3)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, eventHorizon * 0.8, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,20,40,0.2)";
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.05)";
+ ctx.fill();
+ //when player is inside event horizon
+ if (Vector.magnitude(Vector.sub(this.position, player.position)) < eventHorizon) {
+ if (m.immuneCycle < m.cycle) {
+ if (m.energy > 0) m.energy -= 0.008
+ if (m.energy < 0.1) m.damage(0.00015 * simulation.dmgScale);
+ }
+ const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x);
+ player.force.x -= 0.0013 * Math.cos(angle) * player.mass * (m.onGround ? 1.7 : 1);
+ player.force.y -= 0.0013 * Math.sin(angle) * player.mass;
+ //draw line to player
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ ctx.lineTo(m.pos.x, m.pos.y);
+ ctx.lineWidth = Math.min(60, this.radius * 2);
+ ctx.strokeStyle = "rgba(0,0,0,0.5)";
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(0,0,0,0.3)";
+ ctx.fill();
+ }
+ this.curl(eventHorizon);
+ //attract other power ups
+ for (let i = 0; i < powerUp.length; i++) { //attract heal power ups
+ const sub = Vector.sub(this.position, powerUp[i].position)
+ const mag = 0.0015 * Math.min(1, (Vector.magnitude(sub) - 200) / this.eventHorizon)
+ const attract = Vector.mult(Vector.normalise(sub), mag * powerUp[i].mass)
+ powerUp[i].force.x += attract.x;
+ powerUp[i].force.y += attract.y - powerUp[i].mass * simulation.g; //negate gravity
+ // Matter.Body.setVelocity(powerUp[i], Vector.mult(powerUp[i].velocity, 0.7));
+ }
+ }
+ }
+ },
+ spiderBoss(x, y, radius = 60 + Math.ceil(Math.random() * 10)) {
+ let targets = [] //track who is in the node boss, for shields
+ mobs.spawn(x, y, 6, radius, "#b386e8");
+ let me = mob[mob.length - 1];
+ Matter.Body.setDensity(me, 0.003); //extra dense //normal is 0.001 //makes effective life much larger and damage on collision
+ me.isBoss = true;
+ me.damageReduction = 0.13 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) //normal is 1, most bosses have 0.25
+
+ targets.push(me.id) //add to shield protection
+ me.friction = 0;
+ me.frictionAir = 0.0067;
+ me.lookTorque = 0.0000008; //controls spin while looking for player
+ me.g = 0.0002; //required if using this.gravity
+ me.seePlayerFreq = Math.floor((30 + 20 * Math.random()));
+ const springStiffness = 0.00014;
+ const springDampening = 0.0005;
+
+ me.springTarget = {
+ x: me.position.x,
+ y: me.position.y
+ };
+ const len = cons.length;
+ cons[len] = Constraint.create({
+ pointA: me.springTarget,
+ bodyB: me,
+ stiffness: springStiffness,
+ damping: springDampening
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ cons[len].length = 100 + 1.5 * radius;
+ me.cons = cons[len];
+
+ me.springTarget2 = {
+ x: me.position.x,
+ y: me.position.y
+ };
+ const len2 = cons.length;
+ cons[len2] = Constraint.create({
+ pointA: me.springTarget2,
+ bodyB: me,
+ stiffness: springStiffness,
+ damping: springDampening,
+ length: 0
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ cons[len2].length = 100 + 1.5 * radius;
+ me.cons2 = cons[len2];
+ me.do = function () {
+ // this.armor();
+ this.gravity();
+ this.searchSpring();
+ this.checkStatus();
+ this.springAttack();
+ };
+
+ me.onDeath = function () {
+ this.removeCons();
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+
+ radius = 22 // radius of each node mob
+ const sideLength = 100 // distance between each node mob
+ const nodes = 6
+ const angle = 2 * Math.PI / nodes
+
+ spawn.allowShields = false; //don't want shields on individual mobs
+
+ for (let i = 0; i < nodes; ++i) {
+ spawn.stabber(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius, 12);
+ Matter.Body.setDensity(mob[mob.length - 1], 0.003); //extra dense //normal is 0.001 //makes effective life much larger
+ mob[mob.length - 1].damageReduction = 0.12
+ targets.push(mob[mob.length - 1].id) //track who is in the node boss, for shields
+ }
+
+ const attachmentStiffness = 0.02
+ spawn.constrain2AdjacentMobs(nodes, attachmentStiffness, true); //loop mobs together
+
+ for (let i = 0; i < nodes; ++i) { //attach to center mob
+ consBB[consBB.length] = Constraint.create({
+ bodyA: me,
+ bodyB: mob[mob.length - i - 1],
+ stiffness: attachmentStiffness,
+ damping: 0.03
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ //spawn shield around all nodes
+ spawn.groupShield(targets, x, y, sideLength + 1 * radius + nodes * 5 - 25);
+ spawn.allowShields = true;
+ },
+ mantisBoss(x, y, radius = 35, isSpawnBossPowerUp = true) {
+ mobs.spawn(x, y, 5, radius, "#6ba");
+ let me = mob[mob.length - 1];
+ me.babyList = [] //list of mobs that are apart of this boss
+ Matter.Body.setDensity(me, 0.0015); //extra dense //normal is 0.001 //makes effective life much larger and damage on collision
+ me.damageReduction = 0.13 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) //normal is 1, most bosses have 0.25
+ me.isBoss = true;
+
+ me.friction = 0;
+ me.frictionAir = 0.006;
+ me.g = 0.0002; //required if using this.gravity
+ me.seePlayerFreq = 31;
+ const springStiffness = 0.00003; //simulation.difficulty
+ const springDampening = 0.0002;
+ me.springTarget = {
+ x: me.position.x,
+ y: me.position.y
+ };
+ const len = cons.length;
+ cons[len] = Constraint.create({
+ pointA: me.springTarget,
+ bodyB: me,
+ stiffness: springStiffness,
+ damping: springDampening
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ cons[len].length = 100 + 1.5 * radius;
+ me.cons = cons[len];
+ me.springTarget2 = { x: me.position.x, y: me.position.y };
+ const len2 = cons.length;
+ cons[len2] = Constraint.create({
+ pointA: me.springTarget2,
+ bodyB: me,
+ stiffness: springStiffness,
+ damping: springDampening,
+ length: 0
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ cons[len2].length = 100 + 1.5 * radius;
+ me.cons2 = cons[len2];
+ me.startingDamageReduction = me.damageReduction
+ me.isInvulnerable = false
+ me.invulnerabilityCountDown = 0
+ me.do = function () {
+ this.checkStatus();
+ this.gravity();
+ //draw the two dots on the end of the springs
+ ctx.beginPath();
+ ctx.arc(this.cons.pointA.x, this.cons.pointA.y, 6, 0, 2 * Math.PI);
+ ctx.arc(this.cons2.pointA.x, this.cons2.pointA.y, 6, 0, 2 * Math.PI);
+ ctx.fillStyle = "#222";
+ ctx.fill();
+ // this.seePlayerCheck()
+ this.seePlayerByHistory()
+ this.invulnerabilityCountDown--
+ if (this.isInvulnerable) {
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ for (let i = 0; i < this.babyList.length; i++) {
+ if (this.babyList[i].alive) {
+ let vertices = this.babyList[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ }
+ }
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ if (this.invulnerabilityCountDown < 0) {
+ this.invulnerabilityCountDown = 110
+ this.isInvulnerable = false
+ this.damageReduction = this.startingDamageReduction
+ for (let i = 0; i < this.babyList.length; i++) {
+ if (this.babyList[i].alive) this.babyList[i].damageReduction = this.startingDamageReduction
+ }
+ }
+ } else if (this.invulnerabilityCountDown < 0) {
+ this.invulnerabilityCountDown = 120 + 9 * simulation.difficulty
+ this.isInvulnerable = true
+ if (this.damageReduction) this.startingDamageReduction = this.damageReduction
+ this.damageReduction = 0
+ for (let i = 0; i < this.babyList.length; i++) {
+ if (this.babyList[i].alive) {
+ this.babyList[i].isInvulnerable = true
+ this.babyList[i].damageReduction = 0
+ }
+ }
+ }
+ // set new values of the ends of the spring constraints
+ const stepRange = 700
+ if (this.seePlayer.recall && Matter.Query.ray(map, this.position, this.seePlayer.position).length === 0) {
+ if (!(simulation.cycle % (this.seePlayerFreq * 2))) {
+ const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position))
+ const goal = Vector.add(this.position, Vector.mult(unit, stepRange))
+ this.springTarget.x = goal.x;
+ this.springTarget.y = goal.y;
+ this.cons.length = -200;
+ this.cons2.length = 100 + 1.5 * this.radius;
+ } else if (!(simulation.cycle % this.seePlayerFreq)) {
+ const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position))
+ const goal = Vector.add(this.position, Vector.mult(unit, stepRange))
+ this.springTarget2.x = goal.x;
+ this.springTarget2.y = goal.y;
+ this.cons.length = 100 + 1.5 * this.radius;
+ this.cons2.length = -200;
+ }
+ } else {
+ this.torque = this.lookTorque * this.inertia;
+ //spring to random place on map
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ }
+ };
+ //move to a random location
+ if (!(simulation.cycle % (this.seePlayerFreq))) {
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ const seeRange = 3000;
+ const look = {
+ x: this.position.x + seeRange * Math.cos(this.angle),
+ y: this.position.y + seeRange * Math.sin(this.angle)
+ };
+ vertexCollision(this.position, look, map);
+ if (best.dist2 != Infinity) {
+ this.springTarget.x = best.x;
+ this.springTarget.y = best.y;
+ this.cons.length = 100 + 1.5 * this.radius;
+ this.cons2.length = 100 + 1.5 * this.radius;
+ }
+ }
+ }
+ };
+ me.onDeath = function () {
+ this.removeCons();
+ if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ for (let i = 0; i < this.babyList.length; i++) {
+ if (this.babyList[i].alive) {
+ this.babyList[i].collisionFilter.mask = cat.map | cat.bullet | cat.player
+ this.babyList[i].isInvulnerable = false
+ this.babyList[i].damageReduction = this.startingDamageReduction
+ this.babyList[i].collisionFilter.mask = cat.bullet | cat.player | cat.map | cat.body
+ }
+ }
+ };
+ const sideLength = 80 // distance between each node mob
+ const nodes = 3
+ const angle = 2 * Math.PI / nodes
+ spawn.allowShields = false; //don't want shields on individual mobs, it messes with the constraints
+ for (let i = 0; i < nodes; ++i) {
+ spawn.striker(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), 20, 12);
+ const babyMob = mob[mob.length - 1]
+ me.babyList.push(babyMob)
+ babyMob.fill = "rgb(68, 102, 119)"
+ babyMob.isBoss = true;
+ // Matter.Body.setDensity(babyMob, 0.001); //extra dense //normal is 0.001 //makes effective life much larger and increases damage
+ babyMob.damageReduction = this.startingDamageReduction * 0.8
+ babyMob.collisionFilter.mask = cat.bullet | cat.player //can't touch other mobs //cat.map | cat.body |
+ babyMob.delay = 60 + 55 * simulation.CDScale + Math.floor(Math.random() * 20);
+ babyMob.strikeRange = 400
+ babyMob.onHit = function () {
+ this.cd = simulation.cycle + this.delay;
+ //dislodge ammo
+ if (b.inventory.length) {
+ let isRemovedAmmo = false
+ const numRemoved = 3
+ for (let j = 0; j < numRemoved; j++) {
+ for (let i = 0; i < b.inventory.length; i++) {
+ const gun = b.guns[b.inventory[i]]
+ if (gun.ammo > 0 && gun.ammo !== Infinity) {
+ gun.ammo -= Math.ceil((0.45 * Math.random() + 0.45 * Math.random()) * gun.ammoPack) //Math.ceil(Math.random() * target.ammoPack)
+ if (gun.ammo < 0) gun.ammo = 0
+ isRemovedAmmo = true
+ }
+ }
+ }
+ if (isRemovedAmmo) {
+ simulation.updateGunHUD();
+ for (let j = 0; j < numRemoved; j++) powerUps.directSpawn(this.position.x + 10 * Math.random(), this.position.y + 10 * Math.random(), "ammo");
+ powerUps.ejectGraphic();
+ }
+ }
+ };
+ }
+ const stiffness = 0.01
+ const damping = 0.1
+ for (let i = 1; i < nodes; ++i) { //attach to center mob
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - i],
+ bodyB: mob[mob.length - i - 1],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - 1],
+ bodyB: mob[mob.length - nodes],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+
+
+ for (let i = 0; i < nodes; ++i) { //attach to center mob
+ consBB[consBB.length] = Constraint.create({
+ bodyA: me,
+ bodyB: mob[mob.length - i - 1],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ spawn.allowShields = true;
+ },
+ // timeSkipBoss(x, y, radius = 55) {
+ // mobs.spawn(x, y, 6, radius, '#000');
+ // let me = mob[mob.length - 1];
+ // me.isBoss = true;
+ // // me.stroke = "transparent"; //used for drawSneaker
+ // me.timeSkipLastCycle = 0
+ // me.eventHorizon = 1800; //required for black hole
+ // me.seeAtDistance2 = (me.eventHorizon + 2000) * (me.eventHorizon + 2000); //vision limit is event horizon + 2000
+ // me.accelMag = 0.0004 * simulation.accelScale;
+ // // me.frictionAir = 0.005;
+ // // me.memory = 1600;
+ // // Matter.Body.setDensity(me, 0.02); //extra dense //normal is 0.001 //makes effective life much larger
+ // Matter.Body.setDensity(me, 0.0005 + 0.00018 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ // spawn.shield(me, x, y, 1);
+ // me.onDeath = function() {
+ // //applying forces to player doesn't seem to work inside this method, not sure why
+ // powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // };
+ // me.do = function() {
+ // //keep it slow, to stop issues from explosion knock backs
+ // if (this.speed > 8) {
+ // Matter.Body.setVelocity(this, {
+ // x: this.velocity.x * 0.99,
+ // y: this.velocity.y * 0.99
+ // });
+ // }
+ // this.seePlayerCheck();
+ // this.checkStatus();
+ // this.attraction()
+ // if (!simulation.isTimeSkipping) {
+ // const compress = 1
+ // if (this.timeSkipLastCycle < simulation.cycle - compress &&
+ // Vector.magnitude(Vector.sub(this.position, player.position)) < this.eventHorizon) {
+ // this.timeSkipLastCycle = simulation.cycle
+ // simulation.timeSkip(compress)
+
+ // this.fill = `rgba(0,0,0,${0.4+0.6*Math.random()})`
+ // this.stroke = "#014"
+ // this.isShielded = false;
+ // this.isDropPowerUp = true;
+ // this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can't touch bullets
+
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
+ // ctx.fillStyle = "#fff";
+ // ctx.globalCompositeOperation = "destination-in"; //in or atop
+ // ctx.fill();
+ // ctx.globalCompositeOperation = "source-over";
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
+ // ctx.clip();
+
+ // // ctx.beginPath();
+ // // ctx.arc(this.position.x, this.position.y, 9999, 0, 2 * Math.PI);
+ // // ctx.fillStyle = "#000";
+ // // ctx.fill();
+ // // ctx.strokeStyle = "#000";
+ // // ctx.stroke();
+
+ // // ctx.beginPath();
+ // // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
+ // // ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`;
+ // // ctx.fill();
+ // // ctx.strokeStyle = "#000";
+ // // ctx.stroke();
+ // } else {
+ // this.isShielded = true;
+ // this.isDropPowerUp = false;
+ // this.seePlayer.recall = false
+ // this.fill = "transparent"
+ // this.stroke = "transparent"
+ // this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.mob; //can't touch bullets
+ // ctx.beginPath();
+ // ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
+ // ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`;
+ // ctx.fill();
+ // }
+ // }
+ // }
+ // },
+ beamer(x, y, radius = 15 + Math.ceil(Math.random() * 15)) {
+ mobs.spawn(x, y, 4, radius, "rgb(255,0,190)");
+ let me = mob[mob.length - 1];
+ me.repulsionRange = 73000; //squared
+ me.laserRange = 370;
+ me.accelMag = 0.0005 * simulation.accelScale;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ spawn.shield(me, x, y);
+ me.do = function () {
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ this.attraction();
+ this.repulsion();
+ this.harmZone();
+ };
+ },
+ historyBoss(x, y, radius = 30) {
+ if (tech.dynamoBotCount > 0) {
+ spawn.randomLevelBoss(x, y, spawn.nonCollideBossList)
+ return
+ }
+ mobs.spawn(x, y, 0, radius, "transparent");
+ let me = mob[mob.length - 1];
+ Matter.Body.setDensity(me, 0.21); //extra dense //normal is 0.001
+ me.laserRange = 350;
+ me.seeAtDistance2 = 2000000;
+ me.isBoss = true;
+ me.damageReduction = 0.35 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) // me.damageReductionGoal
+
+ me.showHealthBar = false; //drawn in this.awake
+ me.delayLimit = 60 + Math.floor(30 * Math.random());
+ me.followDelay = 600 - Math.floor(90 * Math.random())
+ me.stroke = "transparent"; //used for drawGhost
+ me.collisionFilter.mask = cat.bullet | cat.body
+ me.memory = Infinity
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ requestAnimationFrame(() => {
+ requestAnimationFrame(() => {
+ ctx.setTransform(1, 0, 0, 1, 0, 0); //reset warp effect
+ ctx.setLineDash([]) //reset stroke dash effect
+ })
+ })
+ };
+ me.warpIntensity = 0
+ me.awake = function () {
+ this.checkStatus();
+ //health bar needs to be here because the position is being set
+ const h = this.radius * 0.3;
+ const w = this.radius * 2;
+ const x = this.position.x - w / 2;
+ const y = this.position.y - w * 0.7;
+ ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
+ ctx.fillRect(x, y, w, h);
+ ctx.fillStyle = "rgba(150,0,255,0.7)";
+ ctx.fillRect(x, y, w * this.health, h);
+
+ //draw eye
+ const unit = Vector.normalise(Vector.sub(m.pos, this.position))
+ const eye = Vector.add(Vector.mult(unit, 15), this.position)
+ ctx.beginPath();
+ ctx.arc(eye.x, eye.y, 4, 0, 2 * Math.PI);
+ ctx.moveTo(this.position.x + 20 * unit.x, this.position.y + 20 * unit.y);
+ ctx.lineTo(this.position.x + 30 * unit.x, this.position.y + 30 * unit.y);
+ ctx.strokeStyle = this.stroke;
+ ctx.lineWidth = 2;
+ ctx.stroke();
+
+ ctx.setLineDash([125 * Math.random(), 125 * Math.random()]); //the dashed effect is not set back to normal, because it looks neat for how the player is drawn
+ // ctx.lineDashOffset = 6*(simulation.cycle % 215);
+ if (this.distanceToPlayer() < this.laserRange) {
+ if (m.immuneCycle < m.cycle) {
+ if (m.energy > 0.002) {
+ m.energy -= 0.004
+ } else {
+ m.damage(0.0004 * simulation.dmgScale)
+ }
+ }
+ this.warpIntensity += 0.0004
+ requestAnimationFrame(() => {
+ if (!simulation.paused && m.alive) {
+ ctx.transform(1, this.warpIntensity * (Math.random() - 0.5), this.warpIntensity * (Math.random() - 0.5), 1, 0, 0); //ctx.transform(Horizontal scaling. A value of 1 results in no scaling, Vertical skewing, Horizontal skewing, Vertical scaling. A value of 1 results in no scaling, Horizontal translation (moving), Vertical translation (moving)) //https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setTransform
+ // ctx.transform(1 - scale * (Math.random() - 0.5), skew * (Math.random() - 0.5), skew * (Math.random() - 0.5), 1 - scale * (Math.random() - 0.5), translation * (Math.random() - 0.5), translation * (Math.random() - 0.5)); //ctx.transform(Horizontal scaling. A value of 1 results in no scaling, Vertical skewing, Horizontal skewing, Vertical scaling. A value of 1 results in no scaling, Horizontal translation (moving), Vertical translation (moving)) //https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setTransform
+ }
+ })
+ ctx.beginPath();
+ ctx.moveTo(eye.x, eye.y);
+ ctx.lineTo(m.pos.x, m.pos.y);
+ ctx.lineTo(m.pos.x + (Math.random() - 0.5) * 3000, m.pos.y + (Math.random() - 0.5) * 3000);
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "rgb(150,0,255)";
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
+ ctx.fillStyle = "rgba(150,0,255,0.1)";
+ ctx.fill();
+ } else {
+ this.warpIntensity = 0;
+ }
+
+ //several ellipses spinning about the same axis
+ const rotation = simulation.cycle * 0.015
+ const phase = simulation.cycle * 0.021
+ ctx.lineWidth = 1;
+ ctx.fillStyle = "rgba(150,0,255,0.05)"
+ ctx.strokeStyle = "#70f"
+ for (let i = 0, len = 6; i < len; i++) {
+ ctx.beginPath();
+ ctx.ellipse(this.position.x, this.position.y, this.laserRange * Math.abs(Math.sin(phase + i / len * Math.PI)), this.laserRange, rotation, 0, 2 * Math.PI);
+ ctx.fill();
+ ctx.stroke();
+ }
+
+ if (!this.isStunned && !this.isSlowed) {
+ if (this.followDelay > this.delayLimit) this.followDelay -= 0.15;
+ let history = m.history[(m.cycle - Math.floor(this.followDelay)) % 600]
+ Matter.Body.setPosition(this, { x: history.position.x, y: history.position.y - history.yOff + 24.2859 }) //bullets move with player
+ }
+ }
+ me.do = function () {
+ if (this.seePlayer.recall || (!(simulation.cycle % this.seePlayerFreq) && this.distanceToPlayer2() < this.seeAtDistance2 && !m.isCloak)) {
+ setTimeout(() => {
+ this.do = this.awake
+ this.stroke = "rgba(205,0,255,0.5)"
+ this.fill = "rgba(205,0,255,0.1)"
+ this.seePlayer.yes = true
+ }, 2000);
+ }
+ this.checkStatus();
+ };
+ },
+ focuser(x, y, radius = 30 + Math.ceil(Math.random() * 10)) {
+ radius = Math.ceil(radius * 0.7);
+ mobs.spawn(x, y, 4, radius, "rgb(0,0,255)");
+ let me = mob[mob.length - 1];
+ Matter.Body.setDensity(me, 0.003); //extra dense //normal is 0.001
+ me.restitution = 0;
+ me.laserPos = me.position; //required for laserTracking
+ me.repulsionRange = 1200000; //squared
+ me.accelMag = 0.00009 * simulation.accelScale;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.onDamage = function () {
+ this.laserPos = this.position;
+ };
+ spawn.shield(me, x, y);
+ me.do = function () {
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ this.attraction();
+ const dist2 = this.distanceToPlayer2();
+ //laser Tracking
+ if (this.seePlayer.yes && dist2 < 4000000) {
+ const rangeWidth = 2000; //this is sqrt of 4000000 from above if()
+ //targeting laser will slowly move from the mob to the player's position
+ this.laserPos = Vector.add(this.laserPos, Vector.mult(Vector.sub(player.position, this.laserPos), 0.1));
+ let targetDist = Vector.magnitude(Vector.sub(this.laserPos, m.pos));
+ const r = 12;
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ if (targetDist < r + 16) {
+ targetDist = r + 10;
+ //charge at player
+ const forceMag = this.accelMag * 40 * this.mass;
+ const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ this.force.x += forceMag * Math.cos(angle);
+ this.force.y += forceMag * Math.sin(angle);
+ }
+ // else {
+ //high friction if can't lock onto player
+ // Matter.Body.setVelocity(this, {
+ // x: this.velocity.x * 0.98,
+ // y: this.velocity.y * 0.98
+ // });
+ // }
+ if (dist2 > 80000) {
+ const laserWidth = 0.002;
+ let laserOffR = Vector.rotateAbout(this.laserPos, (targetDist - r) * laserWidth, this.position);
+ let sub = Vector.normalise(Vector.sub(laserOffR, this.position));
+ laserOffR = Vector.add(laserOffR, Vector.mult(sub, rangeWidth));
+ ctx.lineTo(laserOffR.x, laserOffR.y);
+
+ let laserOffL = Vector.rotateAbout(this.laserPos, (targetDist - r) * -laserWidth, this.position);
+ sub = Vector.normalise(Vector.sub(laserOffL, this.position));
+ laserOffL = Vector.add(laserOffL, Vector.mult(sub, rangeWidth));
+ ctx.lineTo(laserOffL.x, laserOffL.y);
+ ctx.fillStyle = `rgba(0,0,255,${Math.max(0, 0.3 * r / targetDist)})`
+ ctx.fill();
+ }
+ } else {
+ this.laserPos = this.position;
+ }
+ }
+ },
+ flutter(x, y, radius = 20 + 6 * Math.random()) {
+ mobs.spawn(x, y, 7, radius, '#16576b');
+ let me = mob[mob.length - 1];
+ Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger
+ // me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.accelMag = 0.0006 + 0.0007 * Math.sqrt(simulation.accelScale);
+ me.frictionAir = 0.04;
+ // me.seePlayerFreq = 40 + Math.floor(13 * Math.random())
+ me.memory = 240;
+ me.restitution = 1;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.lookTorque = 0.000001 * (Math.random() > 0.5 ? -1 : 1);
+ me.fireDir = { x: 0, y: 0 }
+ spawn.shield(me, x, y);
+
+ // me.onDeath = function() {};
+ me.flapRate = 0.3 + Math.floor(3 * Math.random()) / 10 + 100 * me.accelMag
+ me.flapRadius = 75 + radius * 3
+ me.do = function () {
+ this.seePlayerByHistory()
+ this.checkStatus();
+ if (this.seePlayer.recall) {
+ this.force.x += Math.cos(this.angle) * this.accelMag * this.mass
+ this.force.y += Math.sin(this.angle) * this.accelMag * this.mass
+
+ //set direction to turn to fire
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+
+ //dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles
+ const mod = (a, n) => {
+ return a - Math.floor(a / n) * n
+ }
+ const sub = Vector.sub(m.pos, this.position) //check by comparing different between angles. Give this a nudge if angles are 180 degree different
+ const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI
+ if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random();
+ }
+
+ //rotate towards fireDir
+ const angle = this.angle + Math.PI / 2;
+ c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ const threshold = 0.4;
+ const turn = 0.000025 * this.inertia
+ if (c > threshold) {
+ this.torque += turn;
+ } else if (c < -threshold) {
+ this.torque -= turn;
+ }
+ const flapArc = 0.7 //don't go past 1.57 for normal flaps
+
+ ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.2)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
+ this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
+ this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.flapRadius)
+ }
+ };
+ },
+ beetleBoss(x, y, radius = 50) {
+ mobs.spawn(x, y, 7, radius, '#16576b');
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ Matter.Body.setDensity(me, 0.005); //extra dense //normal is 0.001 //makes effective life much larger
+ me.damageReduction = 0.07 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.startingDamageReduction = me.damageReduction
+ me.isInvulnerable = false
+ me.nextHealthThreshold = 0.75
+ me.invulnerableCount = 0
+
+ me.flapRate = 0.2
+ me.wingSize = 0
+ me.wingGoal = 250 + simulation.difficulty
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.accelMag = 0.00045 + 0.0005 * Math.sqrt(simulation.accelScale);
+ me.frictionAir = 0.05;
+ me.seePlayerFreq = 13
+ me.memory = 420;
+ me.restitution = 1;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.lookTorque = 0.000001 * (Math.random() > 0.5 ? -1 : 1);
+ me.fireDir = { x: 0, y: 0 }
+ spawn.shield(me, x, y);
+
+ // len = 0.3 * simulation.difficulty //spawn some baby flutters
+ // if (len > 3) {
+ // for (let i = 0; i < len; ++i) {
+ // const phase = i / len * 2 * Math.PI
+ // const where = Vector.add(me.position, Vector.mult({ x: Math.cos(phase), y: Math.sin(phase) }, radius * 1.5))
+ // spawn.flutter(where.x, where.y)
+ // }
+ // }
+
+ // if (Math.random() < 0.3) {
+ // const len = 0.1 * simulation.difficulty //spawn some baby flutters
+ // let i = 0
+ // let spawnFlutters = () => {
+ // if (i < len) {
+ // if (!(simulation.cycle % 30) && !simulation.paused && !simulation.isChoosing) {
+ // const phase = i / len * 2 * Math.PI
+ // const where = Vector.add(me.position, Vector.mult({ x: Math.cos(phase), y: Math.sin(phase) }, radius * 1.5))
+ // spawn.flutter(where.x, where.y)
+ // i++
+ // }
+ // requestAnimationFrame(spawnFlutters);
+ // }
+ // }
+ // requestAnimationFrame(spawnFlutters);
+ // me.isAlreadyHadBabies = true
+ // }
+
+ me.pushAway = function (magX = 0.13, magY = 0.05) {
+ for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally
+ if (Vector.magnitudeSquared(Vector.sub(body[i].position, this.position)) < 4000000) { //2000
+ body[i].force.x += magX * body[i].mass * (body[i].position.x > this.position.x ? 1 : -1)
+ body[i].force.y -= magY * body[i].mass
+ }
+ }
+ for (let i = 0, len = bullet.length; i < len; ++i) { //push blocks away horizontally
+ if (Vector.magnitudeSquared(Vector.sub(bullet[i].position, this.position)) < 4000000) { //2000
+ bullet[i].force.x += magX * bullet[i].mass * (bullet[i].position.x > this.position.x ? 1 : -1)
+ bullet[i].force.y -= magY * bullet[i].mass
+ }
+ }
+ for (let i = 0, len = powerUp.length; i < len; ++i) { //push blocks away horizontally
+ if (Vector.magnitudeSquared(Vector.sub(powerUp[i].position, this.position)) < 4000000) { //2000
+ powerUp[i].force.x += magX * powerUp[i].mass * (powerUp[i].position.x > this.position.x ? 1 : -1)
+ powerUp[i].force.y -= magY * powerUp[i].mass
+ }
+ }
+ if (Vector.magnitudeSquared(Vector.sub(player.position, this.position)) < 4000000) { //2000
+ player.force.x += magX * player.mass * (player.position.x > this.position.x ? 1 : -1)
+ player.force.y -= magY * player.mass
+ }
+ }
+
+ me.babies = function (len) {
+ const delay = Math.max(3, Math.floor(15 - len / 2))
+ let i = 0
+ let spawnFlutters = () => {
+ if (i < len) {
+ if (!(simulation.cycle % delay) && !simulation.paused && !simulation.isChoosing && m.alive) {
+ // const phase = i / len * 2 * Math.PI
+ // const where = Vector.add(this.position, Vector.mult({ x: Math.cos(phase), y: Math.sin(phase) }, radius * 1.5))
+ const unit = Vector.normalise(Vector.sub(player.position, this.position))
+ const velocity = Vector.mult(unit, 10 + 10 * Math.random())
+ const where = Vector.add(this.position, Vector.mult(unit, radius * 1.2))
+ spawn.allowShields = false
+ spawn.flutter(where.x, where.y, Math.floor(7 + 8 * Math.random()))
+ const who = mob[mob.length - 1]
+ Matter.Body.setDensity(who, 0.01); //extra dense //normal is 0.001 //makes effective life much larger
+ Matter.Body.setVelocity(who, velocity);
+ Matter.Body.setAngle(who, Math.atan2(velocity.y, velocity.x))
+
+ this.alertNearByMobs();
+ spawn.allowShields = true
+ i++
+ }
+ requestAnimationFrame(spawnFlutters);
+ }
+ }
+ requestAnimationFrame(spawnFlutters);
+ }
+ // me.babies(0.05 * simulation.difficulty + 1)
+
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ me.babies(0.05 * simulation.difficulty + 1)
+ };
+ me.onDamage = function () {
+ if (this.health < this.nextHealthThreshold && this.alive) {
+ this.health = this.nextHealthThreshold - 0.01
+ this.nextHealthThreshold = Math.floor(this.health * 4) / 4
+ this.invulnerableCount = 90 + Math.floor(30 * Math.random())
+ this.isInvulnerable = true
+ this.damageReduction = 0
+ this.frictionAir = 0
+ this.wingGoal = 0
+ this.wingSize = 0
+ this.flapRate += 0.13
+ this.accelMag *= 1.4
+ }
+ };
+ me.do = function () {
+ this.seePlayerByHistory(50)
+ this.checkStatus();
+ if (this.isInvulnerable) {
+ this.invulnerableCount--
+ if (this.invulnerableCount < 0) {
+ this.isInvulnerable = false
+ this.damageReduction = this.startingDamageReduction
+ this.frictionAir = 0.05
+ this.wingGoal = 250
+ this.pushAway(Math.sqrt(this.flapRate) * 0.13, Math.sqrt(this.flapRate) * 0.06) //this.flapRate = 0.2, +0.13x3 -> 0.6
+ me.babies(0.05 * simulation.difficulty + 1)
+ }
+ //draw invulnerable
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ } else if (this.seePlayer.recall) {
+ // const force = Vector.mult(Vector.normalise(Vector.sub(this.seePlayer.position, this.position)), this.accelMag * this.mass)
+ // const force = Vector.mult({ x: Math.cos(this.angle), y: Math.sin(this.angle) }, this.accelMag * this.mass)
+ // this.force.x += force.x;
+ // this.force.y += force.y;
+ this.force.x += Math.cos(this.angle) * this.accelMag * this.mass
+ this.force.y += Math.sin(this.angle) * this.accelMag * this.mass
+
+ //set direction to turn to fire
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+
+ //dot product can't tell if mob is facing directly away or directly towards, so check if pointed directly away from player every few cycles
+ //check by comparing different between angles. Give this a nudge if angles are 180 degree different
+ const mod = (a, n) => {
+ return a - Math.floor(a / n) * n
+ }
+ const sub = Vector.sub(m.pos, this.position)
+ const diff = mod(Math.atan2(sub.y, sub.x) - this.angle + Math.PI, 2 * Math.PI) - Math.PI
+ if (Math.abs(diff) > 2.8) this.torque += 0.0002 * this.inertia * Math.random();
+ }
+
+ //rotate towards fireDir
+ const angle = this.angle + Math.PI / 2;
+ c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ const threshold = 0.4;
+ const turn = 0.00003 * this.inertia
+ if (c > threshold) {
+ this.torque += turn;
+ } else if (c < -threshold) {
+ this.torque -= turn;
+ }
+ const flapArc = 0.7 //don't go past 1.57 for normal flaps
+ this.wingSize = 0.97 * this.wingSize + 0.03 * this.wingGoal
+ ctx.fillStyle = this.fill = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.9)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
+ this.wing(this.angle + Math.PI / 2 + flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingSize, 0.5, 0.0012)
+ this.wing(this.angle - Math.PI / 2 - flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingSize, 0.5, 0.0012)
+ } else {
+ this.wingSize = 0.96 * this.wingSize + 0 //shrink while stunned
+ }
+ };
+ },
+ laserTargetingBoss(x, y, radius = 80) {
+ const color = "#07f"
+ mobs.spawn(x, y, 3, radius, color);
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ Matter.Body.setDensity(me, 0.004); //extra dense //normal is 0.001 //makes effective life much larger
+ me.damageReduction = 0.1 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.accelMag = 0.00018 * Math.sqrt(simulation.accelScale);
+ me.seePlayerFreq = 30
+ me.memory = 420;
+ me.restitution = 1;
+ me.frictionAir = 0.01;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.lookTorque = 0.000001 * (Math.random() > 0.5 ? -1 : 1);
+ me.fireDir = { x: 0, y: 0 }
+ spawn.shield(me, x, y, 1);
+ // spawn.spawnOrbitals(me, radius + 50 + 100 * Math.random())
+ for (let i = 0, len = 2 + 0.3 * Math.sqrt(simulation.difficulty); i < len; i++) spawn.spawnOrbitals(me, radius + 40 + 10 * i, 1);
+ // me.onHit = function() { };
+ // spawn.shield(me, x, y, 1); //not working, not sure why
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+ me.laserInterval = 100
+ me.do = function () {
+ // this.armor();
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ this.attraction();
+
+ if (this.seePlayer.recall) {
+ //set direction to turn to fire
+ if (!(simulation.cycle % this.seePlayerFreq)) this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+
+ //rotate towards fireAngle
+ const angle = this.angle + Math.PI / 2;
+ c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ const threshold = 0.4;
+ if (c > threshold) {
+ this.torque += 0.000004 * this.inertia;
+ } else if (c < -threshold) {
+ this.torque -= 0.000004 * this.inertia;
+ }
+ if (simulation.cycle % this.laserInterval > this.laserInterval / 2) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ }
+ };
+ const seeRange = 8000;
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ const look = {
+ x: this.position.x + seeRange * Math.cos(this.angle),
+ y: this.position.y + seeRange * Math.sin(this.angle)
+ };
+ vertexCollision(this.position, look, map);
+ vertexCollision(this.position, look, body);
+ if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]);
+
+ // hitting player
+ if ((best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ const dmg = 0.006 * simulation.dmgScale;
+ m.damage(dmg);
+ //draw damage
+ ctx.fillStyle = color;
+ ctx.beginPath();
+ ctx.arc(best.x, best.y, dmg * 1500, 0, 2 * Math.PI);
+ ctx.fill();
+ }
+ //draw beam
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[1].x, this.vertices[1].y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 3;
+ ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
+ ctx.stroke();
+ ctx.setLineDash([]);
+
+ ctx.beginPath();
+ ctx.arc(this.vertices[1].x, this.vertices[1].y, 1 + 0.3 * (this.laserInterval - simulation.cycle % this.laserInterval), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ ctx.fillStyle = color;
+ ctx.fill();
+ } else {
+ ctx.beginPath();
+ ctx.arc(this.vertices[1].x, this.vertices[1].y, 1 + 0.3 * (simulation.cycle % this.laserInterval), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ ctx.fillStyle = color;
+ ctx.fill();
+ }
+ }
+ };
+ },
+ laserBombingBoss(x, y, radius = 80) {
+ mobs.spawn(x, y, 3, radius, "rgb(0,235,255)");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.accelMag = 0.00055 * Math.sqrt(simulation.accelScale);
+ me.seePlayerFreq = 30;
+ me.memory = 420;
+ me.restitution = 1;
+ me.frictionAir = 0.05;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.lookTorque = 0.0000055 * (Math.random() > 0.5 ? -1 : 1) * (1 + 0.1 * Math.sqrt(simulation.difficulty))
+ me.fireDir = { x: 0, y: 0 }
+ Matter.Body.setDensity(me, 0.01); //extra dense //normal is 0.001 //makes effective life much larger
+ spawn.shield(me, x, y, 1);
+ spawn.spawnOrbitals(me, radius + 200 + 300 * Math.random())
+ me.onHit = function () { };
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+ me.targetingCount = 0;
+ me.targetingTime = 60 - Math.min(58, 3 * simulation.difficulty)
+ me.do = function () {
+
+ // //wings
+ // const wing = (simulation.cycle % 9) > 4 ? this.vertices[0] : this.vertices[2] //Vector.add(this.position, { x: 100, y: 0 })
+ // const radius = 200
+ // //draw
+ // ctx.beginPath();
+ // ctx.arc(wing.x, wing.y, radius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ // ctx.fillStyle = "rgba(0,235,255,0.3)";
+ // ctx.fill();
+ // //check damage
+ // const hitPlayer = Matter.Query.ray([player], this.position, wing, radius)
+ // if (hitPlayer.length && m.immuneCycle < m.cycle) {
+ // m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage
+ // m.damage(0.02 * simulation.dmgScale);
+ // }
+
+
+
+
+
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ this.attraction();
+
+ if (this.seePlayer.recall) {
+ //set direction to turn to fire
+ if (!(simulation.cycle % this.seePlayerFreq)) this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+
+ //rotate towards fireAngle
+ const angle = this.angle + Math.PI / 2;
+ c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ const threshold = 0.02;
+ if (c > threshold) {
+ this.torque += 0.000004 * this.inertia;
+ } else if (c < -threshold) {
+ this.torque -= 0.000004 * this.inertia;
+ }
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ }
+ };
+
+ const seeRange = 8000;
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ const look = {
+ x: this.position.x + seeRange * Math.cos(this.angle),
+ y: this.position.y + seeRange * Math.sin(this.angle)
+ };
+ vertexCollision(this.position, look, map);
+ if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]);
+
+ // hitting player
+ if (best.who === playerBody || best.who === playerHead) {
+ this.targetingCount++
+ if (this.targetingCount > this.targetingTime) {
+ this.targetingCount -= 10;
+ const sub = Vector.sub(player.position, this.position)
+ const dist = Vector.magnitude(sub)
+ const speed = Math.min(55, 5 + 20 * simulation.accelScale)
+ const velocity = Vector.mult(Vector.normalise(sub), speed)
+ spawn.grenade(this.vertices[1].x, this.vertices[1].y, dist / speed, Math.min(550, 250 + simulation.difficulty * 3), 6); // grenade(x, y, lifeSpan = 90 + Math.ceil(60 / simulation.accelScale), pulseRadius = Math.min(550, 250 + simulation.difficulty * 3), size = 4) {
+ Matter.Body.setVelocity(mob[mob.length - 1], velocity);
+ }
+ } else if (this.targetingCount > 0) {
+ this.targetingCount--
+ }
+ //draw beam
+ if (best.dist2 === Infinity) best = look;
+ // ctx.beginPath();
+ // ctx.moveTo(this.vertices[1].x, this.vertices[1].y);
+ // ctx.lineTo(best.x, best.y);
+ // ctx.strokeStyle = "rgba(0,235,255,0.5)";
+ // ctx.lineWidth = 3// + 0.1 * this.targetingCount;
+ // ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
+ // ctx.stroke();
+ // ctx.setLineDash([]);
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[1].x, this.vertices[1].y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(0,235,255,1)";
+ ctx.lineWidth = 3
+ ctx.stroke();
+ if (this.targetingCount / this.targetingTime > 0.33) {
+ ctx.strokeStyle = "rgba(0,235,255,0.45)";
+ ctx.lineWidth = 10
+ ctx.stroke();
+ if (this.targetingCount / this.targetingTime > 0.66) {
+ ctx.strokeStyle = "rgba(0,235,255,0.25)";
+ ctx.lineWidth = 30
+ ctx.stroke();
+ }
+ }
+
+ // ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
+ // ctx.setLineDash([]);
+ }
+ };
+ },
+ blinkBoss(x, y) {
+ mobs.spawn(x, y, 5, 50, "rgb(0,235,255)"); //"rgb(221,102,119)"
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, Math.PI * 0.1);
+ Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger
+ me.isBoss = true;
+ me.damageReduction = 0.034 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.memory = 240
+ me.seePlayerFreq = 55
+ me.blinkRange = 250
+ if (0.5 < Math.random()) {
+ me.grenadeDelay = 260
+ me.blinkRange *= 1.5
+ } else {
+ me.grenadeDelay = 100
+ }
+ me.pulseRadius = 1.5 * Math.min(550, 200 + simulation.difficulty * 2)
+ me.delay = 55 + 35 * simulation.CDScale;
+ me.nextBlinkCycle = me.delay;
+ spawn.shield(me, x, y, 1);
+ me.onDamage = function () {
+ // this.cd = simulation.cycle + this.delay;
+ };
+ me.onDeath = function () {
+ const offAngle = Math.PI * Math.random()
+ for (let i = 0, len = 3; i < len; i++) {
+ spawn.grenade(this.position.x, this.position.y, this.grenadeDelay);
+ const who = mob[mob.length - 1]
+ const speed = 5 * simulation.accelScale;
+ const angle = 2 * Math.PI * i / len + offAngle
+ Matter.Body.setVelocity(who, {
+ x: speed * Math.cos(angle),
+ y: speed * Math.sin(angle)
+ });
+ }
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ }
+ me.do = function () {
+ this.seePlayerByHistory(40)
+ if (this.nextBlinkCycle < simulation.cycle && this.seePlayer.yes) { //teleport towards the player
+ this.nextBlinkCycle = simulation.cycle + this.delay;
+ const dist = Vector.sub(this.seePlayer.position, this.position);
+ const distMag = Vector.magnitude(dist);
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ if (distMag < this.blinkRange) { //if player is inside teleport range
+ Matter.Body.setPosition(this, this.seePlayer.position);
+ } else {
+ Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), this.blinkRange));
+ }
+ spawn.grenade(this.position.x, this.position.y, this.grenadeDelay, this.pulseRadius); //spawn at new location
+ ctx.lineTo(this.position.x, this.position.y);
+ ctx.lineWidth = this.radius * 2.1;
+ ctx.strokeStyle = this.fill; //"rgba(0,0,0,0.5)"; //'#000'
+ ctx.stroke();
+ Matter.Body.setVelocity(this, { x: 0, y: 0 });
+ this.torque += (0.00004 + 0.00003 * Math.random()) * this.inertia * (Math.round(Math.random()) * 2 - 1) //randomly spin around after firing
+ }
+ this.checkStatus();
+ };
+ },
+ pulsarBoss(x, y, radius = 90, isNonCollide = false) {
+ mobs.spawn(x, y, 3, radius, "#a0f");
+ let me = mob[mob.length - 1];
+ if (isNonCollide) me.collisionFilter.mask = cat.bullet | cat.player
+ setTimeout(() => { //fix mob in place, but allow rotation
+ me.constraint = Constraint.create({
+ pointA: {
+ x: me.position.x,
+ y: me.position.y
+ },
+ bodyB: me,
+ stiffness: 0.0001,
+ damping: 0.3
+ });
+ Composite.add(engine.world, me.constraint);
+ }, 2000); //add in a delay in case the level gets flipped left right
+
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.radius *= 1.5
+ me.vertices[1].x = me.position.x + Math.cos(me.angle) * me.radius; //make one end of the triangle longer
+ me.vertices[1].y = me.position.y + Math.sin(me.angle) * me.radius;
+ // me.homePosition = { x: x, y: y };
+ me.fireCycle = 0
+ me.fireTarget = { x: 0, y: 0 }
+ me.pulseRadius = Math.min(500, 230 + simulation.difficulty * 3)
+ me.fireDelay = Math.max(60, 150 - simulation.difficulty * 2)
+ me.isFiring = false
+ Matter.Body.setDensity(me, 0.01); //extra dense //normal is 0.001 //makes effective life much larger
+ me.isBoss = true;
+
+ spawn.shield(me, x, y, 1);
+ spawn.spawnOrbitals(me, radius + 200 + 300 * Math.random(), 1)
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+ me.onHit = function () { };
+ me.do = function () {
+ if (player.speed > 5) this.do = this.fire //don't attack until player moves
+ }
+ me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.fire = function () {
+ // this.armor();
+ this.checkStatus();
+ if (!m.isCloak && !this.isStunned) {
+ if (this.isFiring) {
+ if (this.fireCycle > this.fireDelay) { //fire
+ this.isFiring = false
+ this.fireCycle = 0
+ this.torque += (0.00008 + 0.00007 * Math.random()) * this.inertia * (Math.round(Math.random()) * 2 - 1) //randomly spin around after firing
+ //is player in beam path
+ if (Matter.Query.ray([player], this.fireTarget, this.position).length) {
+ unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100)
+ this.fireTarget = Vector.add(this.vertices[1], unit)
+ }
+ //damage player if in range
+ if (Vector.magnitude(Vector.sub(player.position, this.fireTarget)) < this.pulseRadius && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage
+ m.damage(0.045 * simulation.dmgScale);
+ }
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.fireTarget.x,
+ y: this.fireTarget.y,
+ radius: this.pulseRadius,
+ color: "rgba(120,0,255,0.6)",
+ time: simulation.drawTime
+ });
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
+ ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
+ ctx.lineWidth = 20;
+ ctx.strokeStyle = "rgba(120,0,255,0.3)";
+ ctx.stroke();
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = "rgba(120,0,255,1)";
+ ctx.stroke();
+ } else { //delay before firing
+ this.fireCycle++
+ //draw explosion outline
+ ctx.beginPath();
+ ctx.arc(this.fireTarget.x, this.fireTarget.y, this.pulseRadius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ ctx.fillStyle = "rgba(120,0,255,0.07)";
+ ctx.fill();
+ //draw path from mob to explosion
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
+ ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
+ ctx.setLineDash([40 * Math.random(), 200 * Math.random()]);
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "rgba(120,0,255,0.3)";
+ ctx.stroke();
+ ctx.setLineDash([]);
+ }
+ } else { //aim at player
+ this.fireCycle++
+ this.fireDir = Vector.normalise(Vector.sub(m.pos, this.position)); //set direction to turn to fire
+ //rotate towards fireAngle
+ const angle = this.angle + Math.PI / 2;
+ const c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ const threshold = 0.04;
+ if (c > threshold) {
+ this.torque += 0.0000015 * this.inertia;
+ } else if (c < -threshold) {
+ this.torque -= 0.0000015 * this.inertia;
+ } else if (this.fireCycle > 45) { //fire
+ unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100)
+ this.fireTarget = Vector.add(this.vertices[1], unit)
+ if (Vector.magnitude(Vector.sub(m.pos, this.fireTarget)) < 1000) { //if's possible for this to be facing 180 degrees away from the player, this makes sure that doesn't occur
+ Matter.Body.setAngularVelocity(this, 0)
+ this.fireLockCount = 0
+ this.isFiring = true
+ this.fireCycle = 0
+ }
+ }
+ }
+ //gently return to starting location
+ // const sub = Vector.sub(this.homePosition, this.position)
+ // const dist = Vector.magnitude(sub)
+ // if (dist > 250) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
+ } else {
+ this.isFiring = false
+ }
+ };
+ },
+ pulsar(x, y, radius = 40) {
+ mobs.spawn(x, y, 3, radius, "#f08");
+ let me = mob[mob.length - 1];
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.radius *= 2
+ // me.frictionAir = 0.02
+
+ me.vertices[1].x = me.position.x + Math.cos(me.angle) * me.radius; //make one end of the triangle longer
+ me.vertices[1].y = me.position.y + Math.sin(me.angle) * me.radius;
+ // me.homePosition = { x: x, y: y };
+ Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger
+ me.fireCycle = Infinity
+ me.fireTarget = { x: 0, y: 0 }
+ me.pulseRadius = Math.min(400, 170 + simulation.difficulty * 3)
+ me.fireDelay = Math.max(75, 140 - simulation.difficulty * 0.5)
+ me.isFiring = false
+ me.onHit = function () { };
+ me.canSeeTarget = function () {
+ const angle = this.angle + Math.PI / 2;
+ const dot = Vector.dot({
+ x: Math.cos(angle),
+ y: Math.sin(angle)
+ }, Vector.normalise(Vector.sub(this.fireTarget, this.position)));
+ //distance between the target and the player's location
+ if (
+ m.isCloak ||
+ dot > 0.03 || // not looking at target
+ Matter.Query.ray(map, this.fireTarget, this.position).length || Matter.Query.ray(body, this.fireTarget, this.position).length || //something blocking line of sight
+ Vector.magnitude(Vector.sub(m.pos, this.fireTarget)) > 1000 // distance from player to target is very far, (this is because dot product can't tell if facing 180 degrees away)
+ ) {
+ this.isFiring = false
+ return false
+ } else {
+ return true
+ }
+ }
+ me.do = function () {
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ if (this.seePlayer.recall) {
+ if (this.isFiring) {
+ if (this.fireCycle > this.fireDelay) { //fire
+ if (!this.canSeeTarget()) return
+ this.isFiring = false
+ this.fireCycle = 0
+ this.torque += (0.00002 + 0.0002 * Math.random()) * this.inertia * (Math.round(Math.random()) * 2 - 1) //randomly spin around after firing
+ //is player in beam path
+ if (Matter.Query.ray([player], this.fireTarget, this.position).length) {
+ unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100)
+ this.fireTarget = Vector.add(this.vertices[1], unit)
+ }
+ //damage player if in range
+ if (Vector.magnitude(Vector.sub(player.position, this.fireTarget)) < this.pulseRadius && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage
+ m.damage(0.03 * simulation.dmgScale);
+ }
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.fireTarget.x,
+ y: this.fireTarget.y,
+ radius: this.pulseRadius,
+ color: "rgba(255,0,100,0.6)",
+ time: simulation.drawTime
+ });
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
+ ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
+ ctx.lineWidth = 20;
+ ctx.strokeStyle = "rgba(255,0,100,0.3)";
+ ctx.stroke();
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = "rgba(255,0,100,1)";
+ ctx.stroke();
+ } else { //delay before firing
+ this.fireCycle++
+ if (!(simulation.cycle % 3)) {
+ if (!this.canSeeTarget()) return //if can't see stop firing
+ }
+ //draw explosion outline
+ ctx.beginPath();
+ ctx.arc(this.fireTarget.x, this.fireTarget.y, this.pulseRadius, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ ctx.fillStyle = "rgba(255,0,100,0.07)";
+ ctx.fill();
+ //draw path from mob to explosion
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[1].x, this.vertices[1].y)
+ ctx.lineTo(this.fireTarget.x, this.fireTarget.y)
+ ctx.setLineDash([40 * Math.random(), 200 * Math.random()]);
+ ctx.lineWidth = 2;
+ ctx.strokeStyle = "rgba(255,0,100,0.3)";
+ ctx.stroke();
+ ctx.setLineDash([]);
+ }
+ } else { //aim at player
+ this.fireCycle++
+ // this.fireDir = ; //set direction to turn to fire
+ const angle = this.angle + Math.PI / 2;
+ const dot = Vector.dot({
+ x: Math.cos(angle),
+ y: Math.sin(angle)
+ }, Vector.normalise(Vector.sub(this.seePlayer.position, this.position)))
+ const threshold = 0.04;
+ if (dot > threshold) { //rotate towards fireAngle
+ this.torque += 0.0000015 * this.inertia;
+ } else if (dot < -threshold) {
+ this.torque -= 0.0000015 * this.inertia;
+ } else if (this.fireCycle > 60) { // aim
+ unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100)
+ this.fireTarget = Vector.add(this.vertices[1], unit)
+ if (!this.canSeeTarget()) return
+ Matter.Body.setAngularVelocity(this, 0)
+ this.fireLockCount = 0
+ this.isFiring = true
+ this.fireCycle = 0
+ }
+ }
+ //gently return to starting location
+ // const sub = Vector.sub(this.homePosition, this.position)
+ // const dist = Vector.magnitude(sub)
+ // if (dist > 350) this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.0002)
+ } else {
+ this.isFiring = false
+ }
+ };
+ },
+ laser(x, y, radius = 30) {
+ const color = "#f00"
+ mobs.spawn(x, y, 3, radius, color);
+ let me = mob[mob.length - 1];
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ Matter.Body.rotate(me, Math.random() * Math.PI * 2);
+ me.accelMag = 0.0001 * simulation.accelScale;
+ me.laserInterval = 100
+ me.onHit = function () {
+ //run this function on hitting player
+ this.explode();
+ };
+ me.do = function () {
+ this.torque = this.lookTorque * this.inertia * 0.5;
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ this.attraction();
+ if (this.seePlayer.recall) {
+ //set direction to turn to fire
+ if (!(simulation.cycle % this.seePlayerFreq)) this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+
+ if (simulation.cycle % this.laserInterval > this.laserInterval / 2) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) {
+ best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ }
+ };
+ const seeRange = 8000;
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ const look = {
+ x: this.position.x + seeRange * Math.cos(this.angle),
+ y: this.position.y + seeRange * Math.sin(this.angle)
+ };
+ vertexCollision(this.position, look, map);
+ vertexCollision(this.position, look, body);
+ if (!m.isCloak) vertexCollision(this.position, look, [playerBody, playerHead]);
+
+ // hitting player
+ if ((best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ const dmg = 0.003 * simulation.dmgScale;
+ m.damage(dmg);
+ //draw damage
+ ctx.fillStyle = color;
+ ctx.beginPath();
+ ctx.arc(best.x, best.y, dmg * 1500, 0, 2 * Math.PI);
+ ctx.fill();
+ }
+ //draw beam
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath();
+ ctx.moveTo(this.vertices[1].x, this.vertices[1].y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 3;
+ ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
+ ctx.stroke();
+ ctx.setLineDash([]);
+
+ ctx.beginPath();
+ ctx.arc(this.vertices[1].x, this.vertices[1].y, 1 + 0.3 * (this.laserInterval - simulation.cycle % this.laserInterval), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ ctx.fillStyle = color;
+ ctx.fill();
+ } else {
+ ctx.beginPath();
+ ctx.arc(this.vertices[1].x, this.vertices[1].y, 1 + 0.3 * (simulation.cycle % this.laserInterval), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ ctx.fillStyle = color;
+ ctx.fill();
+ }
+ }
+ };
+ },
+ laserBoss(x, y, radius = 30) {
+ mobs.spawn(x, y, 3, radius, "#f00");
+ let me = mob[mob.length - 1];
+
+ setTimeout(() => { //fix mob in place, but allow rotation
+ me.constraint = Constraint.create({
+ pointA: {
+ x: me.position.x,
+ y: me.position.y
+ },
+ bodyB: me,
+ stiffness: 1,
+ damping: 1
+ });
+ Composite.add(engine.world, me.constraint);
+ }, 2000); //add in a delay in case the level gets flipped left right
+ me.count = 0;
+ me.frictionAir = 0.03;
+ // me.torque -= me.inertia * 0.002
+ spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
+ Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger
+ me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.isBoss = true;
+ // spawn.shield(me, x, y, 1); //not working, not sure why
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+ me.rotateVelocity = Math.min(0.0045, 0.0015 * simulation.accelScale * simulation.accelScale) * (level.levelsCleared > 8 ? 1 : -1) * (simulation.isHorizontalFlipped ? -1 : 1)
+ me.do = function () {
+ this.fill = '#' + Math.random().toString(16).substr(-6); //flash colors
+ this.checkStatus();
+
+ if (!this.isStunned) {
+ //check if slowed
+ let slowed = false
+ for (let i = 0; i < this.status.length; i++) {
+ if (this.status[i].type === "slow") {
+ slowed = true
+ break
+ }
+ }
+ if (!slowed) {
+ this.count++
+ Matter.Body.setAngle(this, this.count * this.rotateVelocity)
+ Matter.Body.setAngularVelocity(this, 0)
+ }
+
+ ctx.beginPath();
+ this.lasers(this.vertices[0], this.angle + Math.PI / 3);
+ this.lasers(this.vertices[1], this.angle + Math.PI);
+ this.lasers(this.vertices[2], this.angle - Math.PI / 3);
+ ctx.strokeStyle = "#50f";
+ ctx.lineWidth = 1.5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ ctx.lineWidth = 20;
+ ctx.strokeStyle = "rgba(80,0,255,0.07)";
+ ctx.stroke(); // Draw it
+ }
+
+
+ // Matter.Body.setVelocity(this, {
+ // x: 0,
+ // y: 0
+ // });
+ // Matter.Body.setPosition(this, this.startingPosition);
+
+ };
+ me.lasers = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[j],
+ v2: vertices[j + 1]
+ };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = {
+ x: results.x,
+ y: results.y,
+ dist2: dist2,
+ who: domain[i],
+ v1: vertices[0],
+ v2: vertices[len]
+ };
+ }
+ }
+ };
+
+ const seeRange = 7000;
+ best = {
+ x: null,
+ y: null,
+ dist2: Infinity,
+ who: null,
+ v1: null,
+ v2: null
+ };
+ const look = {
+ x: where.x + seeRange * Math.cos(angle),
+ y: where.y + seeRange * Math.sin(angle)
+ };
+ // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ vertexCollision(where, look, body);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
+ const dmg = 0.14 * simulation.dmgScale;
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: dmg * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ //draw beam
+ if (best.dist2 === Infinity) best = look;
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ }
+ },
+ stabber(x, y, radius = 25 + Math.ceil(Math.random() * 12), spikeMax = 7) {
+ if (radius > 80) radius = 65;
+ mobs.spawn(x, y, 6, radius, "rgb(220,50,205)"); //can't have sides above 6 or collision events don't work (probably because of a convex problem)
+ let me = mob[mob.length - 1];
+ me.isVerticesChange = true
+ me.accelMag = 0.0006 * simulation.accelScale;
+ // me.g = 0.0002; //required if using this.gravity
+ me.delay = 360 * simulation.CDScale;
+ me.spikeVertex = 0;
+ me.spikeLength = 0;
+ me.isSpikeGrowing = false;
+ me.spikeGrowth = 0;
+ me.isSpikeReset = true;
+ me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.player //can't touch other mobs
+ Matter.Body.rotate(me, Math.PI * 0.1);
+ spawn.shield(me, x, y);
+ // me.onDamage = function () {};
+ // me.onHit = function() { //run this function on hitting player
+ // };
+ me.onDeath = function () {
+ if (this.spikeLength > 4) {
+ this.spikeLength = 4
+ const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.spikeVertex], this.position)), this.radius * this.spikeLength)
+ this.vertices[this.spikeVertex].x = this.position.x + spike.x
+ this.vertices[this.spikeVertex].y = this.position.y + spike.y
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
+ }
+ };
+ me.do = function () {
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ this.attraction();
+ if (this.isSpikeReset) {
+ if (this.seePlayer.recall) {
+ const dist = Vector.sub(this.seePlayer.position, this.position);
+ const distMag = Vector.magnitude(dist);
+ if (distMag < radius * spikeMax) {
+ //find nearest vertex
+ let nearestDistance = Infinity
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ //find distance to player for each vertex
+ const dist = Vector.sub(this.seePlayer.position, this.vertices[i]);
+ const distMag = Vector.magnitude(dist);
+ //save the closest distance
+ if (distMag < nearestDistance) {
+ this.spikeVertex = i
+ nearestDistance = distMag
+ }
+ }
+ this.spikeLength = 1
+ this.isSpikeGrowing = true;
+ this.isSpikeReset = false;
+ Matter.Body.setAngularVelocity(this, 0)
+ }
+ }
+ } else {
+ if (this.isSpikeGrowing) {
+ this.spikeLength += Math.pow(this.spikeGrowth += 0.02, 8)
+ // if (this.spikeLength < 2) {
+ // this.spikeLength += 0.035
+ // } else {
+ // this.spikeLength += 1
+ // }
+ if (this.spikeLength > spikeMax) {
+ this.isSpikeGrowing = false;
+ this.spikeGrowth = 0
+ }
+ } else {
+ Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.8) //reduce rotation
+ this.spikeLength -= 0.3
+ if (this.spikeLength < 1) {
+ this.spikeLength = 1
+ this.isSpikeReset = true
+ this.radius = radius
+ }
+ }
+ const spike = Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.spikeVertex], this.position)), radius * this.spikeLength)
+ this.vertices[this.spikeVertex].x = this.position.x + spike.x
+ this.vertices[this.spikeVertex].y = this.position.y + spike.y
+ // this.radius = radius * this.spikeLength;
+ }
+ };
+ },
+
+ striker(x, y, radius = 14 + Math.ceil(Math.random() * 25)) {
+ mobs.spawn(x, y, 5, radius, "rgb(221,102,119)");
+ let me = mob[mob.length - 1];
+ me.accelMag = 0.00034 * simulation.accelScale;
+ me.g = 0.00015; //required if using this.gravity
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.delay = 30 + 60 * simulation.CDScale;
+ me.cd = Infinity;
+ me.strikeRange = 300
+ Matter.Body.rotate(me, Math.PI * 0.1);
+ spawn.shield(me, x, y);
+ me.onDamage = function () {
+ this.cd = simulation.cycle + this.delay;
+ };
+ me.do = function () {
+ this.gravity();
+ if (!(simulation.cycle % this.seePlayerFreq)) { // this.seePlayerCheck(); from mobs
+ if (
+ this.distanceToPlayer2() < this.seeAtDistance2 &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ // Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0 &&
+ !m.isCloak
+ ) {
+ this.foundPlayer();
+ if (this.cd === Infinity) this.cd = simulation.cycle + this.delay * 0.7;
+ } else if (this.seePlayer.recall) {
+ this.lostPlayer();
+ this.cd = Infinity
+ }
+ }
+ this.checkStatus();
+ this.attraction();
+ if (this.cd < simulation.cycle && this.seePlayer.recall) {
+ const dist = Vector.sub(this.seePlayer.position, this.position);
+ const distMag = Vector.magnitude(dist);
+ this.cd = simulation.cycle + this.delay;
+ ctx.beginPath();
+ ctx.moveTo(this.position.x, this.position.y);
+ if (distMag < 400) {
+ Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), distMag - 20 - radius));
+ } else {
+ Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), this.strikeRange));
+ }
+ ctx.lineTo(this.position.x, this.position.y);
+ ctx.lineWidth = radius * 2.1;
+ ctx.strokeStyle = this.fill; //"rgba(0,0,0,0.5)"; //'#000'
+ ctx.stroke();
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * 0.5,
+ y: this.velocity.y * 0.5
+ });
+ }
+ };
+ },
+ revolutionBoss(x, y, radius = 70) {
+ const sides = 9 + Math.floor(Math.min(12, 0.2 * simulation.difficulty))
+ const coolBends = [-1.8, 0, 0, 0.9, 1.2]
+ const bendFactor = coolBends[Math.floor(Math.random() * coolBends.length)];
+ mobs.spawn(x, y, sides, radius, "rgb(201,202,225)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.accelMag = 0.00018 + 0.00018 * Math.sqrt(simulation.accelScale);
+ me.frictionAir = 0.01;
+ me.swordRadiusMax = 400 + 10 * simulation.difficulty;
+ me.laserAngle = 0;
+ me.swordDamage = 0.025 * simulation.dmgScale //0.033 * simulation.dmgScale; previous //0.14 * simulation.dmgScale;laserBoss
+
+ // spawn.shield(me, x, y, 1);
+ Matter.Body.setDensity(me, 0.005); //extra dense //normal is 0.001 //makes effective life much larger
+ me.damageReduction = 0.12 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.isBoss = true;
+ me.onDamage = function () { };
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+
+ //invulnerability every 1/4 fraction of life lost
+ //required setup for invulnerable
+ me.isInvulnerable = false
+ me.isNextInvulnerability = 0.75
+ me.invulnerabilityCountDown = 0
+ me.invulnerable = function () {
+ if (this.health < this.isNextInvulnerability) {
+ this.isNextInvulnerability = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
+ this.isInvulnerable = true
+ this.startingDamageReduction = this.damageReduction
+ this.damageReduction = 0
+ this.invulnerabilityCountDown = 106
+ }
+ if (this.isInvulnerable) {
+ if (this.invulnerabilityCountDown > 0) {
+ this.invulnerabilityCountDown--
+ //draw invulnerability
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ } else {
+ this.isInvulnerable = false
+ this.damageReduction = this.startingDamageReduction
+ }
+ }
+ }
+ me.do = function () {
+ this.invulnerable();
+ this.checkStatus();
+ this.seePlayerByHistory(60);
+ this.attraction();
+ //traveling laser
+ this.laserAngle += this.isInvulnerable ? 0.025 : 0.006
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ // this.laserSword(this.vertices[1], this.angle + laserAngle);
+ const bend = bendFactor * Math.cos(this.laserAngle + 2 * Math.PI * i / len)
+ const long = this.swordRadiusMax * Math.sin(this.laserAngle + 2 * Math.PI * i / len)
+ if (long > 0) this.laserSword(this.vertices[i], bend + this.angle + (i + 0.5) / sides * 2 * Math.PI, Math.abs(long));
+ }
+ };
+ me.laserSword = function (where, angle, length) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let vertices = domain[i].vertices;
+ const len = vertices.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: vertices[j], v2: vertices[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: vertices[0], v2: vertices[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + length * Math.cos(angle), y: where.y + length * Math.sin(angle) };
+ // vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(100,100,255,0.1)"; // Purple path
+ ctx.lineWidth = 10;
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(100,100,255,0.5)"; // Purple path
+ ctx.lineWidth = 2;
+ // ctx.stroke();
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ },
+ sprayBoss(x, y, radius = 40, isSpawnBossPowerUp = true) {
+ mobs.spawn(x, y, 16, radius, "rgb(255,255,255)");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.isReactorBoss = true;
+ me.inertia = Infinity; //no rotation
+ me.burstFireFreq = 22 + Math.floor(13 * simulation.CDScale)
+ me.burstTotalPhases = 3 + Math.floor(1.4 / simulation.CDScale)
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0;
+ me.restitution = 1
+ // spawn.spawnOrbitals(me, radius + 50 + 125 * Math.random(), 1)
+ Matter.Body.setDensity(me, 0.002 + 0.0001 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ me.damageReduction = 0.09 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.startingDamageReduction = me.damageReduction
+ me.isInvulnerable = false
+ me.nextHealthThreshold = 0.75
+ me.onDeath = function () {
+ if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+ me.onDamage = function () {
+ if (this.health < this.nextHealthThreshold) {
+ this.health = this.nextHealthThreshold - 0.01
+ this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
+
+ this.phaseCycle = -2
+ this.do = this.burstFire
+ this.frictionAir = 1
+ this.isInvulnerable = true
+ this.damageReduction = 0
+ }
+ };
+
+ //draw radial lines from verticies showing future bullet paths?
+ me.radialLines = function () {
+ ctx.beginPath();
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ ctx.moveTo(this.vertices[i].x, this.vertices[i].y)
+ const unit = Vector.add(Vector.mult(Vector.normalise(Vector.sub(this.vertices[i], this.position)), 1000), this.vertices[i])
+ ctx.lineTo(unit.x, unit.y)
+ }
+ ctx.lineWidth = 10
+ ctx.strokeStyle = "rgb(200,0,200,0.03)"
+ ctx.stroke();
+ }
+
+ me.phaseCycle = 0
+ me.normalDoStuff = function () {
+ this.checkStatus();
+ me.seePlayer.recall = 1
+ //maintain speed //faster in the vertical to help avoid repeating patterns
+ if (this.speed < 0.01) {
+ Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(Vector.sub(player.position, this.position)), 0.1));
+ } else {
+ if (Math.abs(this.velocity.y) < 9) Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.03 });
+ if (Math.abs(this.velocity.x) < 7) Matter.Body.setVelocity(this, { x: this.velocity.x * 1.03, y: this.velocity.y });
+ }
+ }
+ me.burstFire = function () {
+ this.normalDoStuff();
+ this.radialLines()
+ //draw invulnerable
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+
+ if (!(simulation.cycle % this.burstFireFreq)) {
+ this.phaseCycle++
+ if (this.phaseCycle > this.burstTotalPhases) { //start spiral fire mode
+ // this.phaseCycle = -7
+ this.do = this.normalDoStuff
+ this.frictionAir = 0;
+ this.isInvulnerable = false
+ this.damageReduction = this.startingDamageReduction
+ Matter.Body.setVelocity(this, Vector.rotate({ x: 20, y: 0 }, 2 * Math.PI * Math.random()));
+ if (this.isShielded) { //remove shield
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].shield) mob[i].death()
+ }
+ }
+ }
+ if (this.phaseCycle > -1) {
+ Matter.Body.rotate(this, 0.02)
+ for (let i = 0, len = this.vertices.length; i < len; i++) { //fire a bullet from each vertex
+ spawn.sniperBullet(this.vertices[i].x, this.vertices[i].y, 3, 4);
+ const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[i])), -15)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: velocity.x,
+ y: velocity.y
+ });
+ }
+ }
+ }
+ };
+ me.do = me.normalDoStuff
+ Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) });
+ },
+ mineBoss(x, y, radius = 120, isSpawnBossPowerUp = true) {
+ mobs.spawn(x, y, 0, radius, "rgba(255,255,255,0.5)") // "rgb(201,202,225)");
+ let me = mob[mob.length - 1];
+ // Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.isBoss = true;
+ me.isReactorBoss = true;
+ Matter.Body.setDensity(me, 0.001); //normal is 0.001
+ me.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.startingDamageReduction = me.damageReduction
+ me.isInvulnerable = false
+ me.nextHealthThreshold = 0.75
+ me.invulnerableCount = 0
+
+ me.cycle = 0
+ me.inertia = Infinity;
+ me.frictionAir = 0.01
+ me.restitution = 1
+ me.friction = 0
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob
+ me.explodeRange = 400
+ Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) });
+ me.seePlayer.recall = 1;
+ // spawn.shield(me, x, y, 1);
+ me.onDamage = function () {
+ if (this.health < this.nextHealthThreshold) {
+ this.health = this.nextHealthThreshold - 0.01
+ this.nextHealthThreshold = Math.floor(this.health * 4) / 4
+ this.invulnerableCount = 60 + simulation.difficulty * 1.5
+ this.isInvulnerable = true
+ this.damageReduction = 0
+
+ //slow time to look cool
+ // simulation.fpsCap = 10 //new fps
+ // simulation.fpsInterval = 1000 / simulation.fpsCap;
+ //how long to wait to return to normal fps
+ // m.defaultFPSCycle = m.cycle + 20 + 90
+
+
+ for (let i = 0, len = mob.length; i < len; ++i) { //trigger nearby mines
+ if (mob[i].isMine && Vector.magnitude(Vector.sub(this.position, mob[i].position)) < this.explodeRange) mob[i].isExploding = true
+ }
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: this.explodeRange,
+ color: "rgba(255,25,0,0.6)",
+ time: simulation.drawTime * 2
+ });
+
+ }
+ };
+ me.onDeath = function () {
+ if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ for (let i = 0, len = mob.length; i < len; ++i) { //trigger nearby mines
+ if (mob[i].isMine && Vector.magnitude(Vector.sub(this.position, mob[i].position)) < this.explodeRange) mob[i].isExploding = true
+ }
+ };
+ // console.log(me.mass) //100
+ me.do = function () {
+ me.seePlayer.recall = 1
+ //maintain speed //faster in the vertical to help avoid repeating patterns
+ if (this.speed < 0.01) {
+ const unit = Vector.sub(player.position, this.position)
+ Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(unit), 0.1));
+ // this.invulnerableCount = 10 + simulation.difficulty * 0.5
+ // this.isInvulnerable = true
+ // this.damageReduction = 0
+ } else {
+ if (Math.abs(this.velocity.y) < 10) {
+ Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.03 });
+ }
+ if (Math.abs(this.velocity.x) < 7) {
+ Matter.Body.setVelocity(this, { x: this.velocity.x * 1.03, y: this.velocity.y });
+ }
+ }
+ if (this.isInvulnerable) {
+ this.invulnerableCount--
+ if (this.invulnerableCount < 0) {
+ this.isInvulnerable = false
+ this.damageReduction = this.startingDamageReduction
+ }
+ //draw invulnerable
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ }
+ this.checkStatus();
+ if (!(simulation.cycle % 15) && mob.length < 360) spawn.mine(this.position.x, this.position.y)
+ };
+ },
+ mine(x, y) {
+ mobs.spawn(x, y, 8, 10, "rgb(255, 255, 255)"); //"rgb(100,170,150)" //"rgb(61, 125, 121)"
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ Matter.Body.setDensity(me, 0.0001); //normal is 0.001
+ // Matter.Body.setStatic(me, true); //make static (disables taking damage)
+ me.frictionAir = 1
+ me.damageReduction = 2
+ me.collisionFilter.mask = cat.bullet //| cat.body
+ // me.collisionFilter.category = cat.mobBullet;
+ // me.collisionFilter.mask = cat.bullet | cat.body // | cat.player
+ me.isMine = true
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.isUnstable = true; //dies when blocked
+ me.showHealthBar = false;
+ me.explodeRange = 210 + 140 * Math.random()
+ me.isExploding = false
+ me.countDown = Math.ceil(4 * Math.random())
+ me.isInvulnerable = true //not actually invulnerable, just prevents block + ice-9 interaction
+
+ // me.onHit = function() {
+ // this.isExploding = true
+ // };
+ // me.onDamage = function() {
+ // this.health = 1
+ // this.isExploding = true
+ // };
+ me.do = function () {
+ this.checkStatus();
+
+ if (Matter.Query.collides(this, [player]).length > 0) {
+ this.isExploding = true
+ }
+
+ if (this.isExploding) {
+ if (this.countDown-- < 0) { //explode
+ this.death();
+ //hit player
+ if (Vector.magnitude(Vector.sub(this.position, player.position)) < this.explodeRange && m.immuneCycle < m.cycle) {
+ m.damage(0.02 * simulation.dmgScale * (tech.isRadioactiveResistance ? 0.25 : 1));
+ m.energy -= 0.2 * (tech.isRadioactiveResistance ? 0.25 : 1)
+ if (m.energy < 0) m.energy = 0
+ }
+ // mob[i].isInvulnerable = false //make mineBoss not invulnerable ?
+ const range = this.explodeRange + 50 //mines get a slightly larger range to explode
+ for (let i = 0, len = mob.length; i < len; ++i) {
+ if (mob[i].alive && Vector.magnitude(Vector.sub(this.position, mob[i].position)) < range) {
+ if (mob[i].isMine) mob[i].isExploding = true //explode other mines
+ }
+ }
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: this.explodeRange,
+ color: "rgba(80,220,190,0.45)",
+ time: 16
+ });
+ }
+ }
+ };
+ },
+ bounceBoss(x, y, radius = 80, isSpawnBossPowerUp = true) {
+ mobs.spawn(x, y, 0, radius, "rgb(255,255,255)") // "rgb(201,202,225)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.isBoss = true;
+ me.isReactorBoss = true;
+ Matter.Body.setDensity(me, 0.003); //normal is 0.001
+ me.damageReduction = 0.1 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.startingDamageReduction = me.damageReduction
+ me.inertia = Infinity;
+ me.isInvulnerable = false
+ me.frictionAir = 0.01
+ me.restitution = 1
+ me.friction = 0
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob
+ Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) });
+ me.seePlayer.recall = 1;
+ // spawn.shield(me, x, y, 1);
+ me.onDamage = function () {
+ if (this.health < this.nextHealthThreshold) {
+ this.health = this.nextHealthThreshold - 0.01
+ this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
+ this.fireCount = 60 + simulation.difficulty * 1.5
+ this.isInvulnerable = true
+ this.damageReduction = 0
+ }
+ };
+ if (isSpawnBossPowerUp) me.onDeath = function () { powerUps.spawnBossPowerUp(this.position.x, this.position.y) };
+ me.cycle = 0
+ me.nextHealthThreshold = 0.75
+ me.fireCount = 0
+ // console.log(me.mass) //100
+ me.do = function () {
+ me.seePlayer.recall = 1
+ //maintain speed //faster in the vertical to help avoid repeating patterns
+ if (this.speed < 0.01) {
+ const unit = Vector.sub(player.position, this.position)
+ Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(unit), 0.1));
+ // this.fireCount = 10 + simulation.difficulty * 0.5
+ // this.isInvulnerable = true
+ // this.damageReduction = 0
+ } else {
+ if (Math.abs(this.velocity.y) < 15) Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.03 });
+ if (Math.abs(this.velocity.x) < 11) Matter.Body.setVelocity(this, { x: this.velocity.x * 1.03, y: this.velocity.y });
+ }
+
+ if (this.isInvulnerable) {
+ this.fireCount--
+ if (this.fireCount < 0) {
+ this.isInvulnerable = false
+ this.damageReduction = this.startingDamageReduction
+ }
+
+ if (this.mass > 10) Matter.Body.scale(this, 0.99, 0.99);
+
+ // for (let i = 0; i < 1; i++) {
+ const velocity = Vector.rotate(Vector.mult(Vector.normalise(this.velocity), -5 - 10 * Math.random()), 0.5 * (Math.random() - 0.5))
+ spawn.bounceBullet(this.position.x, this.position.y, velocity)
+ // }
+ //draw invulnerable
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ } else if (this.mass < 100) {
+ Matter.Body.scale(this, 1.01, 1.01); //grow back to normal size
+ }
+
+ this.checkStatus();
+ //horizontal attraction
+ // const xMag = 0.0005
+ // if (player.position.x > this.position.x + 200) {
+ // this.force.x += xMag * this.mass;
+ // } else if (player.position.x < this.position.x - 200) {
+ // this.force.x -= xMag * this.mass;
+ // }
+ };
+ },
+ timeBoss(x, y, radius = 50, isSpawnBossPowerUp = true) {
+ mobs.spawn(x, y, 0, radius, `hsl(0, 100%, 50%)`) // "rgb(201,202,225)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.isBoss = true;
+ me.isReactorBoss = true;
+ me.inertia = Infinity;
+ me.frictionAir = 0.01
+ me.restitution = 1
+ me.friction = 0
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob
+ Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) });
+ me.seePlayer.recall = 1;
+ // for (let i = 0; i < 4; i++) spawn.spawnOrbitals(me, radius + 25, 1)
+ for (let i = 0, len = 2 + 0.3 * Math.sqrt(simulation.difficulty); i < len; i++) spawn.spawnOrbitals(me, radius + 10 + 10 * i, 1);
+ // me.skipRate = 1 + Math.floor(simulation.difficulty*0.02)
+ // spawn.shield(me, x, y, 1);
+ Matter.Body.setDensity(me, 0.001); //normal is 0.001
+ me.damageReduction = 0.05 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.startingDamageReduction = me.damageReduction
+ me.isInvulnerable = false
+ me.onDamage = function () {
+ if (this.health < this.nextHealthThreshold) {
+ this.health = this.nextHealthThreshold - 0.01
+ this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
+ this.invulnerableCount = 420 + simulation.difficulty * 5 //how long does invulnerable time last
+ this.isInvulnerable = true
+ this.damageReduction = 0
+ // requestAnimationFrame(() => { simulation.timePlayerSkip(300) }); //wrapping in animation frame prevents errors, probably
+ }
+ };
+ me.onDeath = function () {
+ if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ requestAnimationFrame(() => { simulation.timePlayerSkip(60) }); //wrapping in animation frame prevents errors, probably
+ };
+
+ me.cycle = Math.floor(360 * Math.random())
+ me.nextHealthThreshold = 0.75
+ me.invulnerableCount = 0
+ // console.log(me.mass) //100
+ me.do = function () {
+ this.cycle++
+ this.fill = `hsl(${this.cycle * 0.5}, 100%, 80%)`;
+ // this.fill = `hsl(${270 + 50*Math.sin(this.cycle*0.02)}, 100%, 60%)`;
+ this.seePlayer.recall = 1
+ //maintain speed //faster in the vertical to help avoid repeating patterns
+ if (this.speed < 0.01) {
+ const unit = Vector.sub(player.position, this.position)
+ Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(unit), 0.1));
+ } else {
+ if (Math.abs(this.velocity.y) < 10) Matter.Body.setVelocity(this, { x: this.velocity.x, y: this.velocity.y * 1.02 });
+ if (Math.abs(this.velocity.x) < 7) Matter.Body.setVelocity(this, { x: this.velocity.x * 1.02, y: this.velocity.y });
+ }
+
+ if (this.isInvulnerable) {
+ this.invulnerableCount--
+ if (this.invulnerableCount < 0) {
+ this.isInvulnerable = false
+ this.damageReduction = this.startingDamageReduction
+ }
+ //time dilation
+ if (!simulation.isTimeSkipping) {
+ requestAnimationFrame(() => {
+ simulation.timePlayerSkip(2)
+ m.walk_cycle += m.flipLegs * m.Vx //makes the legs look like they are moving fast
+ }); //wrapping in animation frame prevents errors, probably
+
+ // simulation.timePlayerSkip(2)
+ // m.walk_cycle += m.flipLegs * m.Vx //makes the legs look like they are moving fast
+
+ //draw invulnerable
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 15 + 6 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ }
+ }
+
+ this.checkStatus();
+ //horizontal attraction
+ // const xMag = 0.0005
+ // if (player.position.x > this.position.x + 200) {
+ // this.force.x += xMag * this.mass;
+ // } else if (player.position.x < this.position.x - 200) {
+ // this.force.x -= xMag * this.mass;
+ // }
+ };
+ },
+ bounceBullet(x, y, velocity = { x: 0, y: 0 }, radius = 11, sides = 6) {
+ //bullets
+ mobs.spawn(x, y, sides, radius, "rgb(255,0,155)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ Matter.Body.setDensity(me, 0.00001); //normal is 0.001
+ me.timeLeft = 360 + Math.floor(180 * Math.random())
+ me.inertia = Infinity;
+ me.damageReduction = 1
+ me.frictionAir = 0
+ me.friction = 0
+ me.restitution = 1
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map | cat.mob
+
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.onHit = function () {
+ this.explode(this.mass * 12);
+ };
+ me.do = function () {
+ this.timeLimit();
+ };
+ Matter.Body.setVelocity(me, velocity);
+ },
+ slashBoss(x, y, radius = 80) {
+ mobs.spawn(x, y, 5, radius, "rgb(201,202,225)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.isBoss = true;
+ me.damageReduction = 0.1 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.startingDamageReduction = me.damageReduction
+ me.isInvulnerable = false
+ me.frictionAir = 0.02
+ me.seeAtDistance2 = 1000000;
+ me.accelMag = 0.0004 + 0.00015 * simulation.accelScale;
+ Matter.Body.setDensity(me, 0.0005); //normal is 0.001
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map
+ me.memory = Infinity;
+ me.seePlayerFreq = 20
+ me.lockedOn = null;
+
+ me.torqueMagnitude = 0.00024 * me.inertia * (Math.random() > 0.5 ? -1 : 1);
+ me.delay = 70 + 70 * simulation.CDScale;
+ me.cd = 0;
+ me.swordRadius = 0;
+ me.swordVertex = 1
+ me.swordRadiusMax = 1100 + 20 * simulation.difficulty;
+ me.swordRadiusGrowRate = me.swordRadiusMax * (0.005 + 0.0003 * simulation.difficulty)
+ me.isSlashing = false;
+ me.swordDamage = 0.07 * simulation.dmgScale
+ me.laserAngle = 3 * Math.PI / 5
+ const seeDistance2 = 200000
+ spawn.shield(me, x, y);
+ me.onDamage = function () { };
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+ me.do = function () {
+ this.seePlayerByHistory(40);
+ this.attraction();
+ this.checkStatus();
+ this.sword() //does various things depending on what stage of the sword swing
+
+ // ctx.beginPath(); //hide map
+ // ctx.arc(this.position.x, this.position.y, 3000, 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ // ctx.fillStyle = "#444";
+ // ctx.fill();
+ };
+ me.swordWaiting = function () {
+ if (
+ this.seePlayer.recall &&
+ this.cd < simulation.cycle &&
+ this.distanceToPlayer2() < seeDistance2 &&
+ !m.isCloak &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ ) {
+ //find vertex farthest away from player
+ let dist = 0
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ const D = Vector.magnitudeSquared(Vector.sub({ x: this.vertices[i].x, y: this.vertices[i].y }, m.pos))
+ if (D > dist) {
+ dist = D
+ this.swordVertex = i
+ }
+ }
+ this.laserAngle = this.swordVertex / 5 * 2 * Math.PI + 0.6283
+ this.sword = this.swordGrow
+ Matter.Body.setVelocity(this, { x: 0, y: 0 });
+ Matter.Body.setAngularVelocity(this, 0)
+ this.accelMag = 0
+ this.damageReduction = 0
+ this.isInvulnerable = true
+ this.frictionAir = 1
+ }
+ }
+ me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
+ me.swordGrow = function () {
+ this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
+ this.swordRadius += this.swordRadiusGrowRate
+ if (this.swordRadius > this.swordRadiusMax) {
+ this.sword = this.swordSlash
+ this.spinCount = 0
+ }
+
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ }
+ me.swordSlash = function () {
+ this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
+ this.torque += this.torqueMagnitude;
+ this.spinCount++
+ if (this.spinCount > 80) {
+ this.sword = this.swordWaiting
+ this.swordRadius = 0
+ this.accelMag = 0.001 * simulation.accelScale;
+ this.cd = simulation.cycle + this.delay;
+ this.damageReduction = this.startingDamageReduction
+ this.isInvulnerable = false
+ this.frictionAir = 0.01
+ }
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ }
+ me.laserSword = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let v = domain[i].vertices;
+ const len = v.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
+ vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(100,100,255,0.1)"; // Purple path
+ ctx.lineWidth = 25;
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(100,100,255,0.5)"; // Purple path
+ ctx.lineWidth = 5;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ },
+ slasher(x, y, radius = 33 + Math.ceil(Math.random() * 30)) {
+ mobs.spawn(x, y, 5, radius, "rgb(201,202,225)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.accelMag = 0.0008 * simulation.accelScale;
+ me.torqueMagnitude = 0.00002 * me.inertia * (Math.random() > 0.5 ? -1 : 1);
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.035;
+ me.delay = 120 * simulation.CDScale;
+ me.cd = 0;
+ me.swordRadius = 0;
+ me.swordVertex = 1
+ me.swordRadiusMax = 350 + 5 * simulation.difficulty;
+ me.swordRadiusGrowRate = me.swordRadiusMax * (0.018 + 0.0006 * simulation.difficulty)
+ me.isSlashing = false;
+ me.swordDamage = 0.04 * simulation.dmgScale
+ me.laserAngle = 3 * Math.PI / 5
+ const seeDistance2 = 200000
+ spawn.shield(me, x, y);
+ me.onDamage = function () { };
+ me.do = function () {
+ this.checkStatus();
+ this.seePlayerByHistory(15);
+ this.attraction();
+ this.sword() //does various things depending on what stage of the sword swing
+ };
+ me.swordWaiting = function () {
+ if (
+ this.seePlayer.recall &&
+ this.cd < simulation.cycle &&
+ this.distanceToPlayer2() < seeDistance2 &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ ) {
+ //find vertex farthest away from player
+ let dist = 0
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ const D = Vector.magnitudeSquared(Vector.sub({ x: this.vertices[i].x, y: this.vertices[i].y }, m.pos))
+ if (D > dist) {
+ dist = D
+ this.swordVertex = i
+ }
+ }
+ this.laserAngle = this.swordVertex / 5 * 2 * Math.PI + 0.6283
+ this.sword = this.swordGrow
+ this.accelMag = 0
+ }
+ }
+ me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
+ me.swordGrow = function () {
+ this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
+ this.swordRadius += this.swordRadiusGrowRate
+ if (this.swordRadius > this.swordRadiusMax || this.isStunned) {
+ this.sword = this.swordSlash
+ this.spinCount = 0
+ }
+ }
+ me.swordSlash = function () {
+ this.laserSword(this.vertices[this.swordVertex], this.angle + this.laserAngle);
+ this.torque += this.torqueMagnitude;
+ this.spinCount++
+ if (this.spinCount > 60 || this.isStunned) {
+ this.sword = this.swordWaiting
+ this.swordRadius = 0
+ this.accelMag = 0.001 * simulation.accelScale;
+ this.cd = simulation.cycle + this.delay;
+ }
+ }
+ me.laserSword = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let v = domain[i].vertices;
+ const len = v.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
+ vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(100,100,255,0.1)"; // Purple path
+ ctx.lineWidth = 15;
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(100,100,255,0.5)"; // Purple path
+ ctx.lineWidth = 4;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ },
+ slasher2(x, y, radius = 33 + Math.ceil(Math.random() * 30)) {
+ mobs.spawn(x, y, 6, radius, "rgb(180,199,245)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.accelMag = 0.001 * simulation.accelScale;
+ me.torqueMagnitude = -0.000012 * me.inertia //* (Math.random() > 0.5 ? -1 : 1);
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.035;
+ me.delay = 140 * simulation.CDScale;
+ me.cd = 0;
+ me.swordRadius = 0;
+ me.swordVertex = 1
+ me.swordRadiusMax = 320 + 3.6 * simulation.difficulty;
+ me.swordRadiusGrowRate = me.swordRadiusMax * (0.011 + 0.0002 * simulation.difficulty)
+ me.isSlashing = false;
+ me.swordDamage = 0.03 * simulation.dmgScale
+ me.laserAngle = 3 * Math.PI / 5
+ const seeDistance2 = 200000
+ spawn.shield(me, x, y);
+ me.onDamage = function () { };
+ me.do = function () {
+ this.checkStatus();
+ this.seePlayerByHistory(15);
+ this.attraction();
+ this.sword() //does various things depending on what stage of the sword swing
+ };
+ me.swordWaiting = function () {
+ if (
+ this.seePlayer.recall &&
+ this.cd < simulation.cycle &&
+ this.distanceToPlayer2() < seeDistance2 &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ ) {
+ this.laserAngle = -Math.PI / 6
+ this.sword = this.swordGrow
+ this.accelMag = 0
+ }
+ }
+ me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
+ me.swordGrow = function () {
+ this.laserSword(this.vertices[0], this.angle + this.laserAngle);
+ this.laserSword(this.vertices[3], this.angle + this.laserAngle + Math.PI);
+ this.swordRadius += this.swordRadiusGrowRate
+ if (this.swordRadius > this.swordRadiusMax || this.isStunned) {
+ this.sword = this.swordSlash
+ this.spinCount = 0
+ }
+ }
+ me.swordSlash = function () {
+ this.laserSword(this.vertices[0], this.angle + this.laserAngle);
+ this.laserSword(this.vertices[3], this.angle + this.laserAngle + Math.PI);
+
+ this.torque += this.torqueMagnitude;
+ this.spinCount++
+ if (this.spinCount > 100 || this.isStunned) {
+ this.sword = this.swordWaiting
+ this.swordRadius = 0
+ this.accelMag = 0.001 * simulation.accelScale;
+ this.cd = simulation.cycle + this.delay;
+ }
+ }
+ me.laserSword = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let v = domain[i].vertices;
+ const len = v.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
+ vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(100,100,255,0.1)"; // Purple path
+ ctx.lineWidth = 15;
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(100,100,255,0.5)"; // Purple path
+ ctx.lineWidth = 4;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ },
+ slasher3(x, y, radius = 33 + Math.ceil(Math.random() * 30)) {
+ const sides = 6
+ mobs.spawn(x, y, sides, radius, "rgb(180,215,235)");
+ let me = mob[mob.length - 1];
+ Matter.Body.rotate(me, 2 * Math.PI * Math.random());
+ me.accelMag = 0.00055 * simulation.accelScale;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.02;
+ me.delay = 150 * simulation.CDScale;
+ me.cd = 0;
+ me.cycle = 0;
+ me.swordVertex = 1
+ me.swordRadiusInitial = radius / 2;
+ me.swordRadius = me.swordRadiusInitial;
+ me.swordRadiusMax = 800 + 6 * simulation.difficulty;
+ me.swordRadiusGrowRateInitial = 1.08
+ me.swordRadiusGrowRate = me.swordRadiusGrowRateInitial//me.swordRadiusMax * (0.009 + 0.0002 * simulation.difficulty)
+ me.isSlashing = false;
+ me.swordDamage = 0.03 * simulation.dmgScale
+ me.laserAngle = 3 * Math.PI / 5
+ const seeDistance2 = me.swordRadiusMax * me.swordRadiusMax
+ spawn.shield(me, x, y);
+ me.onDamage = function () { };
+ me.do = function () {
+ this.checkStatus();
+ this.seePlayerByHistory(15);
+ this.sword() //does various things depending on what stage of the sword swing
+ };
+ me.swordWaiting = function () {
+ this.attraction();
+ if (
+ this.seePlayer.recall &&
+ this.cd < simulation.cycle &&
+ this.distanceToPlayer2() < seeDistance2 &&
+ Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0
+ ) {
+ //find vertex closest to the player
+ let dist = Infinity
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ const D = Vector.magnitudeSquared(Vector.sub({ x: this.vertices[i].x, y: this.vertices[i].y }, m.pos))
+ if (D < dist) {
+ dist = D
+ this.swordVertex = i
+ }
+ }
+ this.laserAngle = this.swordVertex / sides * 2 * Math.PI + Math.PI / sides
+ this.sword = this.swordGrow
+ this.cycle = 0
+ this.swordRadius = this.swordRadiusInitial
+ //slow velocity but don't stop
+ Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.5))
+ //set angular velocity to 50%
+ // Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.5)
+ //gently rotate towards the player with a torque, use cross product to decided clockwise or counterclockwise
+ const laserStartVector = Vector.sub(this.position, this.vertices[this.swordVertex])
+ const playerVector = Vector.sub(this.position, m.pos)
+ const cross = Matter.Vector.cross(laserStartVector, playerVector)
+ this.torque = 0.00002 * this.inertia * (cross > 0 ? 1 : -1)
+ }
+ }
+ me.sword = me.swordWaiting //base function that changes during different aspects of the sword swing
+ me.swordGrow = function () {
+ this.laserSpear(this.vertices[this.swordVertex], this.angle + this.laserAngle);
+ Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.9))
+ // this.swordRadius += this.swordRadiusGrowRate
+ this.cycle++
+ // this.swordRadius = this.swordRadiusMax * Math.sin(this.cycle * 0.03)
+ this.swordRadius *= this.swordRadiusGrowRate
+
+ if (this.swordRadius > this.swordRadiusMax) this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial
+ // if (this.swordRadius > this.swordRadiusMax) this.swordRadiusGrowRate = -Math.abs(this.swordRadiusGrowRate)
+ if (this.swordRadius < this.swordRadiusInitial || this.isStunned) {
+ // this.swordRadiusGrowRate = Math.abs(this.swordRadiusGrowRate)
+ this.swordRadiusGrowRate = this.swordRadiusGrowRateInitial
+ this.sword = this.swordWaiting
+ this.swordRadius = 0
+ this.cd = simulation.cycle + this.delay;
+ }
+ }
+ me.laserSpear = function (where, angle) {
+ const vertexCollision = function (v1, v1End, domain) {
+ for (let i = 0; i < domain.length; ++i) {
+ let v = domain[i].vertices;
+ const len = v.length - 1;
+ for (let j = 0; j < len; j++) {
+ results = simulation.checkLineIntersection(v1, v1End, v[j], v[j + 1]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[j], v2: v[j + 1] };
+ }
+ }
+ results = simulation.checkLineIntersection(v1, v1End, v[0], v[len]);
+ if (results.onLine1 && results.onLine2) {
+ const dx = v1.x - results.x;
+ const dy = v1.y - results.y;
+ const dist2 = dx * dx + dy * dy;
+ if (dist2 < best.dist2) best = { x: results.x, y: results.y, dist2: dist2, who: domain[i], v1: v[0], v2: v[len] };
+ }
+ }
+ };
+ best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
+ const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
+ vertexCollision(where, look, body); // vertexCollision(where, look, mob);
+ vertexCollision(where, look, map);
+ if (!m.isCloak) vertexCollision(where, look, [playerBody, playerHead]);
+ if (best.who && (best.who === playerBody || best.who === playerHead)) {
+ this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial //!!!! this retracts the sword if it hits the player
+
+ if (m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
+ m.damage(this.swordDamage);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: best.x,
+ y: best.y,
+ radius: this.swordDamage * 1500,
+ color: "rgba(80,0,255,0.5)",
+ time: 20
+ });
+ }
+ }
+ if (best.dist2 === Infinity) best = look;
+ ctx.beginPath(); //draw beam
+ ctx.moveTo(where.x, where.y);
+ ctx.lineTo(best.x, best.y);
+ ctx.strokeStyle = "rgba(100,100,255,0.1)"; // Purple path
+ ctx.lineWidth = 15;
+ ctx.stroke();
+ ctx.strokeStyle = "rgba(100,100,255,0.5)"; // Purple path
+ ctx.lineWidth = 4;
+ ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
+ ctx.stroke(); // Draw it
+ ctx.setLineDash([]);
+ }
+ },
+ sneakBoss(x, y, radius = 70) {
+ mobs.spawn(x, y, 5, radius, "transparent");
+ let me = mob[mob.length - 1];
+ Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger
+ me.isBoss = true;
+ me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+
+ me.accelMag = 0.0017 * Math.sqrt(simulation.accelScale);
+ me.frictionAir = 0.01;
+ me.g = 0.0001; //required if using this.gravity
+ me.stroke = "transparent"; //used for drawSneaker
+ me.alpha = 1; //used in drawSneaker
+ me.isCloaked = true; //used in drawSneaker
+ me.isBadTarget = true;
+ me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
+ me.showHealthBar = false;
+ me.memory = 30;
+ me.vanishesLeft = Math.ceil(1 + simulation.difficultyMode * 0.5)
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+ me.onDamage = function () {
+ if (this.vanishesLeft > 0 && this.health < 0.1) { //if health is below 10% teleport to a random spot on player history, heal, and cloak
+ this.vanishesLeft--
+
+ for (let i = 0; i < 8; i++) { //flash screen to hide vanish
+ simulation.drawList.push({
+ x: this.position.x,
+ y: this.position.y,
+ radius: 3000,
+ color: `rgba(0, 0, 0,${1 - 0.1 * i})`,
+ time: (i + 2) * 4
+ });
+ }
+ //teleport to near the end of player history
+ const index = Math.floor((m.history.length - 1) * (0.66 + 0.2 * Math.random()))
+ let history = m.history[(m.cycle - index) % 600]
+ Matter.Body.setPosition(this, history.position)
+ Matter.Body.setVelocity(this, { x: 0, y: 0 });
+
+ this.damageReduction = 0 //immune to harm for the rest of this game cycle
+ this.seePlayer.recall = 0
+ this.cloak();
+ this.health = 1;
+ }
+ };
+ me.cloak = function () {
+ if (!this.isCloaked) { //stealth
+ this.alpha = 0;
+ this.isCloaked = true;
+ this.isBadTarget = true;
+ this.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
+ this.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ }
+ }
+ me.deCloak = function () {
+ if (this.isCloaked) {
+ this.damageReduction = 0.4 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ this.isCloaked = false;
+ this.isBadTarget = false;
+ this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can touch player
+ }
+ }
+ me.do = function () {
+ if (this.damageReduction === 0) {
+ this.damageReduction = 0.04 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ let i = this.status.length //clear bad status effects
+ while (i--) {
+ if (this.status[i].type === "stun" || this.status[i].type === "dot") this.status.splice(i, 1);
+ }
+ this.isStunned = false;
+ }
+ this.gravity();
+ this.seePlayerByHistory(55);
+ this.checkStatus();
+ this.attraction();
+ //draw
+ if (this.seePlayer.recall) {
+ if (this.alpha < 1) this.alpha += 0.005 + 0.003 / simulation.CDScale;
+ } else {
+ if (this.alpha > 0) this.alpha -= 0.04;
+ }
+ if (this.alpha > 0) {
+ if (this.alpha > 0.7) {
+ this.healthBar();
+ this.deCloak()
+ }
+ //draw body
+ ctx.beginPath();
+ const vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.fillStyle = `rgba(0,0,0,${this.alpha * this.alpha})`;
+ ctx.fill();
+ } else {
+ this.cloak()
+ }
+ };
+ },
+ sneaker(x, y, radius = 15 + Math.ceil(Math.random() * 10)) {
+ mobs.spawn(x, y, 5, radius, "transparent");
+ let me = mob[mob.length - 1];
+ // Matter.Body.setDensity(me, 0.001); //extra dense //normal is 0.001 //makes effective life much larger
+ me.accelMag = 0.001 * Math.sqrt(simulation.accelScale);
+ me.frictionAir = 0.01;
+ me.g = 0.0002; //required if using this.gravity
+ me.stroke = "transparent"; //used for drawSneaker
+ me.alpha = 1; //used in drawSneaker
+ me.isNotCloaked = false; //used in drawSneaker
+ me.isBadTarget = true;
+ me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
+ me.showHealthBar = false;
+ me.memory = 240;
+ me.isVanished = false;
+ me.onDamage = function () {
+ if (!this.isVanished && this.health < 0.1 && !this.isStunned && !this.isSlowed) { //if health is below 10% teleport to a random spot on player history, heal, and cloak
+ this.health = 1;
+ this.isVanished = true
+ this.cloak();
+ //teleport to near the end of player history
+ Matter.Body.setPosition(this, m.history[Math.floor((m.history.length - 1) * (0.66 + 0.33 * Math.random()))].position)
+ Matter.Body.setVelocity(this, { x: 0, y: 0 });
+ this.damageReduction = 0 //immune to harm for the rest of this game cycle
+ }
+ };
+ me.cloak = function () {
+ if (this.isNotCloaked) { //stealth
+ this.alpha = 0;
+ this.isNotCloaked = false;
+ this.isBadTarget = true;
+ this.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
+ }
+ }
+ me.do = function () {
+ if (this.damageReduction === 0) {
+ this.damageReduction = 1 //stop being immune to harm immediately
+ let i = this.status.length //clear bad status effects
+ while (i--) {
+ if (this.status[i].type === "stun" || this.status[i].type === "dot") this.status.splice(i, 1);
+ }
+ this.isStunned = false;
+ }
+ this.gravity();
+ this.seePlayerByHistory(25);
+ this.checkStatus();
+ this.attraction();
+ //draw
+ if (this.seePlayer.recall) {
+ if (this.alpha < 1) this.alpha += 0.003 + 0.003 / simulation.CDScale;
+ } else {
+ if (this.alpha > 0) this.alpha -= 0.03;
+ }
+ if (this.alpha > 0) {
+ if (this.alpha > 0.7) {
+ this.healthBar();
+ if (!this.isNotCloaked) {
+ this.isNotCloaked = true;
+ this.isBadTarget = false;
+ this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can touch player
+ }
+ }
+ //draw body
+ ctx.beginPath();
+ const vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.fillStyle = `rgba(0,0,0,${this.alpha * this.alpha})`;
+ ctx.fill();
+ } else {
+ this.cloak()
+ }
+ };
+ },
+ ghoster(x, y, radius = 50 + Math.ceil(Math.random() * 90)) {
+ mobs.spawn(x, y, 7, radius, "transparent");
+ let me = mob[mob.length - 1];
+ me.seeAtDistance2 = 300000;
+ me.accelMag = 0.00004 + 0.00015 * simulation.accelScale;
+ if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search
+ // Matter.Body.setDensity(me, 0.0015); //normal is 0.001
+ me.damageReduction = 0.5
+ me.stroke = "transparent"; //used for drawGhost
+ me.alpha = 1; //used in drawGhost
+ me.isNotCloaked = false; //used in drawGhost
+ me.isBadTarget = true;
+ // me.leaveBody = false;
+ me.collisionFilter.mask = cat.bullet //| cat.body
+ me.showHealthBar = false;
+ me.memory = 600;
+ me.do = function () {
+ //cap max speed to avoid getting launched by deflection, explosion
+ if (this.speed > 7) {
+ Matter.Body.setVelocity(this, {
+ x: this.velocity.x * 0.8,
+ y: this.velocity.y * 0.8
+ });
+ }
+ this.seePlayerCheckByDistance();
+ this.checkStatus();
+ this.attraction();
+ this.search();
+ //draw
+ if (this.distanceToPlayer2() < this.seeAtDistance2) {
+ if (this.alpha < 1) this.alpha += 0.011 * simulation.CDScale; //near player go solid
+ } else {
+ if (this.alpha > 0) this.alpha -= 0.05; ///away from player, hide
+ }
+ if (this.alpha > 0) {
+ if (this.alpha > 0.7 && this.seePlayer.recall) {
+ this.healthBar();
+ if (!this.isNotCloaked) {
+ this.isNotCloaked = true;
+ this.isBadTarget = false;
+ this.collisionFilter.mask = cat.player | cat.bullet
+ }
+ }
+ //draw body
+ ctx.beginPath();
+ const vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ // ctx.lineWidth = 1;
+ ctx.fillStyle = `rgba(255,255,255,${this.alpha * this.alpha})`;
+ ctx.fill();
+ } else if (this.isNotCloaked) {
+ this.isNotCloaked = false;
+ this.isBadTarget = true;
+ this.collisionFilter.mask = cat.bullet; //can't touch player or walls
+ }
+ };
+ },
+ // blinker(x, y, radius = 45 + Math.ceil(Math.random() * 70)) {
+ // mobs.spawn(x, y, 6, radius, "transparent");
+ // let me = mob[mob.length - 1];
+ // Matter.Body.setDensity(me, 0.0005); //normal is 0.001 //makes effective life much lower
+ // me.stroke = "rgb(0,200,255)"; //used for drawGhost
+ // Matter.Body.rotate(me, Math.random() * 2 * Math.PI);
+ // me.blinkRate = 40 + Math.round(Math.random() * 60); //required for blink
+ // me.blinkLength = 150 + Math.round(Math.random() * 200); //required for blink
+ // me.isStatic = true;
+ // me.memory = 360;
+ // me.seePlayerFreq = Math.round((40 + 30 * Math.random()));
+ // // me.isBig = false;
+ // // me.scaleMag = Math.max(5 - me.mass, 1.75);
+ // me.onDeath = function () {
+ // // if (this.isBig) {
+ // // Matter.Body.scale(this, 1 / this.scaleMag, 1 / this.scaleMag);
+ // // this.isBig = false;
+ // // }
+ // };
+ // me.onHit = function () {
+ // simulation.timeSkip(120)
+ // };
+ // me.do = function () {
+ // this.seePlayerCheck();
+ // this.blink();
+ // //strike by expanding
+ // // if (this.isBig) {
+ // // if (this.cd - this.delay + 15 < simulation.cycle) {
+ // // Matter.Body.scale(this, 1 / this.scaleMag, 1 / this.scaleMag);
+ // // this.isBig = false;
+ // // }
+ // // } else
+ // if (this.seePlayer.yes && this.cd < simulation.cycle) {
+ // const dist = Vector.sub(this.seePlayer.position, this.position);
+ // const distMag2 = Vector.magnitudeSquared(dist);
+ // if (distMag2 < 80000) {
+ // this.cd = simulation.cycle + this.delay;
+
+ // // Matter.Body.scale(this, this.scaleMag, this.scaleMag);
+ // // this.isBig = true;
+ // }
+ // }
+ // };
+ // },
+ bomberBoss(x, y, radius = 88) {
+ //boss that drops bombs from above and holds a set distance from player
+ mobs.spawn(x, y, 3, radius, "rgba(255,0,200,0.5)");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+
+ Matter.Body.setDensity(me, 0.0025 + 0.00013 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+
+ me.stroke = "transparent"; //used for drawGhost
+ me.seeAtDistance2 = 1500000;
+ me.fireFreq = 10 + Math.floor(70 * simulation.CDScale);
+ me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search
+ me.hoverElevation = 460 + (Math.random() - 0.5) * 200; //squared
+ me.hoverXOff = (Math.random() - 0.5) * 100;
+ me.accelMag = Math.floor(10 * (Math.random() + 4.5)) * 0.00001 * simulation.accelScale;
+ me.g = 0.0002; //required if using this.gravity // gravity called in hoverOverPlayer
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.01;
+ me.memory = Infinity;
+ me.collisionFilter.mask = cat.player | cat.bullet //| cat.body
+ spawn.shield(me, x, y, 1);
+
+ const len = Math.floor(Math.min(15, 3 + Math.sqrt(simulation.difficulty))) // simulation.difficulty = 40 on hard mode level 10
+ const speed = (0.007 + 0.003 * Math.random() + 0.004 * Math.sqrt(simulation.difficulty))
+ let radiusOrbitals = radius + 125 + 350 * Math.random()
+ for (let i = 0; i < len; i++) spawn.orbital(me, radiusOrbitals, i / len * 2 * Math.PI, speed)
+ radiusOrbitals = radius + 125 + 350 * Math.random()
+ for (let i = 0; i < len; i++) spawn.orbital(me, radiusOrbitals, i / len * 2 * Math.PI, -speed)
+
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+ me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.do = function () {
+ // this.armor();
+ this.seePlayerCheckByDistance();
+ this.checkStatus();
+ if (this.seePlayer.recall) {
+ this.hoverOverPlayer();
+ this.bomb();
+ this.search();
+ }
+ };
+ },
+ shooter(x, y, radius = 25 + Math.ceil(Math.random() * 50)) {
+ mobs.spawn(x, y, 3, radius, "rgb(255,100,150)");
+ let me = mob[mob.length - 1];
+ // me.vertices = Matter.Vertices.clockwiseSort(Matter.Vertices.rotate(me.vertices, Math.PI, me.position)); //make the pointy side of triangle the front
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ me.isVerticesChange = true
+ // Matter.Body.rotate(me, Math.PI)
+
+ me.memory = 120;
+ me.fireFreq = 0.007 + Math.random() * 0.005;
+ me.noseLength = 0;
+ me.fireAngle = 0;
+ me.accelMag = 0.0005 * simulation.accelScale;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.05;
+ me.lookTorque = 0.0000025 * (Math.random() > 0.5 ? -1 : 1);
+ me.fireDir = { x: 0, y: 0 };
+ me.onDeath = function () { //helps collisions functions work better after vertex have been changed
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
+ }
+ // spawn.shield(me, x, y);
+ me.do = function () {
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ this.fire();
+ };
+ },
+ shooterBoss(x, y, radius = 110, isSpawnBossPowerUp = true) {
+ mobs.spawn(x, y, 3, radius, "rgb(255,70,180)");
+ let me = mob[mob.length - 1];
+ setTimeout(() => { //fix mob in place, but allow rotation
+ me.constraint = Constraint.create({
+ pointA: {
+ x: me.position.x,
+ y: me.position.y
+ },
+ bodyB: me,
+ stiffness: 0.00004,
+ damping: 0.2
+ });
+ Composite.add(engine.world, me.constraint);
+ }, 2000); //add in a delay in case the level gets flipped left right
+
+ me.isBoss = true;
+ Matter.Body.setDensity(me, 0.01 + 0.0004 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ me.isVerticesChange = true
+ me.memory = 240;
+ me.fireFreq = 0.01 + 0.0005 * Math.min(40, simulation.difficulty); //bigger number means more shots per second
+ me.noseLength = 0;
+ me.fireAngle = 0;
+ me.accelMag = 0.005 * simulation.accelScale;
+ me.frictionAir = 0.05;
+ me.lookTorque = 0.000006 * (Math.random() > 0.5 ? -1 : 1);
+ me.fireDir = { x: 0, y: 0 };
+ setTimeout(() => {
+ for (let i = 0, len = 3 + 0.5 * Math.sqrt(simulation.difficulty); i < len; i++) spawn.spawnOrbitals(me, radius + 40 + 10 * i, 1);
+ }, 100); //have to wait a sec so the tether constraint doesn't attach to an orbital
+ me.onDeath = function () {
+ if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
+ };
+ me.do = function () {
+ // this.armor();
+ this.seePlayerByLookingAt();
+ this.checkStatus();
+ // this.fire();
+ const setNoseShape = () => {
+ const mag = this.radius + this.radius * this.noseLength;
+ this.vertices[1].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[1].y = this.position.y + Math.sin(this.angle) * mag;
+ };
+ //throw a mob/bullet at player
+ if (this.seePlayer.recall) {
+ //set direction to turn to fire
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 5000; //gives the bullet an arc //was / 1600
+ }
+ //rotate towards fireAngle
+ const angle = this.angle + Math.PI / 2;
+ const dot = Vector.dot({ x: Math.cos(angle), y: Math.sin(angle) }, this.fireDir)
+ // c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ const threshold = 0.1;
+ if (dot > threshold) {
+ this.torque += 0.000004 * this.inertia;
+ } else if (dot < -threshold) {
+ this.torque -= 0.000004 * this.inertia;
+ } else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) {
+ //fire
+ for (let i = 0, len = 2 + 0.07 * simulation.difficulty; i < len; i++) {
+ spawn.bullet(this.vertices[1].x, this.vertices[1].y, 10 + Math.ceil(this.radius / 25));
+ const spread = Vector.rotate({ x: Math.sqrt(len) + 4, y: 0 }, 2 * Math.PI * Math.random())
+ const dir = Vector.add(Vector.mult(this.fireDir, 25), spread)
+ Matter.Body.setVelocity(mob[mob.length - 1], dir);
+ }
+ this.noseLength = 0;
+ }
+ if (this.noseLength < 1.5) this.noseLength += this.fireFreq;
+ setNoseShape();
+ } else if (this.noseLength > 0.1) {
+ this.noseLength -= this.fireFreq / 2;
+ setNoseShape();
+ }
+ };
+ },
+ bullet(x, y, radius = 9, sides = 0) {
+ //bullets
+ mobs.spawn(x, y, sides, radius, "rgb(255,0,0)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.onHit = function () {
+ this.explode(this.mass * 15);
+ };
+ Matter.Body.setDensity(me, 0.00004); //normal is 0.001
+ me.timeLeft = 220;
+ me.g = 0.001; //required if using this.gravity
+ me.frictionAir = 0;
+ me.restitution = 0.8;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
+ me.do = function () {
+ this.gravity();
+ this.timeLimit();
+ };
+ },
+ bomb(x, y, radius = 9, sides = 5) {
+ mobs.spawn(x, y, sides, radius, "rgb(255,0,0)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.onHit = function () {
+ this.explode(this.mass * 120);
+ };
+ me.onDeath = function () {
+ spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);
+ spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);
+ spawn.bullet(this.position.x, this.position.y, this.radius / 3, 5);
+ const mag = 8
+ const v1 = Vector.rotate({
+ x: 1,
+ y: 1
+ }, 2 * Math.PI * Math.random())
+ const v2 = Vector.rotate({
+ x: 1,
+ y: 1
+ }, 2 * Math.PI * Math.random())
+ const v3 = Vector.normalise(Vector.add(v1, v2)) //last vector is opposite the sum of the other two to look a bit like momentum is conserved
+
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: mag * v1.x,
+ y: mag * v1.y
+ });
+ Matter.Body.setVelocity(mob[mob.length - 2], {
+ x: mag * v2.x,
+ y: mag * v2.y
+ });
+ Matter.Body.setVelocity(mob[mob.length - 3], {
+ x: -mag * v3.x,
+ y: -mag * v3.y
+ });
+ }
+ Matter.Body.setDensity(me, 0.00005); //normal is 0.001
+ me.timeLeft = 140 + Math.floor(Math.random() * 30);
+ me.g = 0.001; //required if using this.gravity
+ me.frictionAir = 0;
+ me.restitution = 1;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
+ me.do = function () {
+ this.gravity();
+ this.timeLimit();
+ };
+ },
+ sniper(x, y, radius = 35 + Math.ceil(Math.random() * 30)) {
+ mobs.spawn(x, y, 3, radius, "transparent"); //"rgb(25,0,50)")
+ let me = mob[mob.length - 1];
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ me.isVerticesChange = true
+ // Matter.Body.rotate(me, Math.PI)
+ me.stroke = "transparent"; //used for drawSneaker
+ me.alpha = 1; //used in drawSneaker
+ me.showHealthBar = false;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.isNotCloaked = false; //used in drawSneaker
+ me.isBadTarget = true;
+ me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
+
+ me.memory = 30 //140;
+ me.fireFreq = 0.005 + Math.random() * 0.002 + 0.0005 * simulation.difficulty; //larger = fire more often
+ me.noseLength = 0;
+ me.fireAngle = 0;
+ me.accelMag = 0.0005 * simulation.accelScale;
+ me.frictionAir = 0.05;
+ me.torque = 0.0001 * me.inertia;
+ me.fireDir = {
+ x: 0,
+ y: 0
+ };
+ me.onDeath = function () { //helps collisions functions work better after vertex have been changed
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices))
+ }
+ // spawn.shield(me, x, y);
+ me.do = function () {
+ // this.seePlayerByLookingAt();
+ this.seePlayerCheck();
+ this.checkStatus();
+
+ const setNoseShape = () => {
+ const mag = this.radius + this.radius * this.noseLength;
+ this.vertices[1].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[1].y = this.position.y + Math.sin(this.angle) * mag;
+ };
+ //throw a mob/bullet at player
+ if (this.seePlayer.recall) {
+ //set direction to turn to fire
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ // this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 1600; //gives the bullet an arc
+ }
+ //rotate towards fireAngle
+ const angle = this.angle + Math.PI / 2;
+ // c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ //rotate towards fireAngle
+ const dot = Vector.dot({
+ x: Math.cos(angle),
+ y: Math.sin(angle)
+ }, this.fireDir)
+ const threshold = 0.03;
+ if (dot > threshold) {
+ this.torque += 0.000004 * this.inertia;
+ } else if (dot < -threshold) {
+ this.torque -= 0.000004 * this.inertia;
+ } else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) {
+ //fire
+ spawn.sniperBullet(this.vertices[1].x, this.vertices[1].y, 7 + Math.ceil(this.radius / 15), 5);
+ const v = 10 + 8 * simulation.accelScale;
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v + Math.random(),
+ y: this.velocity.y + this.fireDir.y * v + Math.random()
+ });
+ this.noseLength = 0;
+ // recoil
+ this.force.x -= 0.005 * this.fireDir.x * this.mass;
+ this.force.y -= 0.005 * this.fireDir.y * this.mass;
+ }
+ if (this.noseLength < 1.5) this.noseLength += this.fireFreq;
+ setNoseShape();
+ } else if (this.noseLength > 0.1) {
+ this.noseLength -= this.fireFreq / 2;
+ setNoseShape();
+ }
+ // else if (this.noseLength < -0.1) {
+ // this.noseLength += this.fireFreq / 4;
+ // setNoseShape();
+ // }
+
+ if (this.seePlayer.recall) {
+ if (this.alpha < 1) this.alpha += 0.01;
+ } else {
+ if (this.alpha > 0) this.alpha -= 0.03;
+ }
+ //draw
+ if (this.alpha > 0) {
+ if (this.alpha > 0.95) {
+ this.healthBar();
+ if (!this.isNotCloaked) {
+ this.isNotCloaked = true;
+ this.isBadTarget = false;
+ this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can touch player
+ }
+ }
+ //draw body
+ ctx.beginPath();
+ const vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) {
+ ctx.lineTo(vertices[j].x, vertices[j].y);
+ }
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.fillStyle = `rgba(25,0,50,${this.alpha * this.alpha})`;
+ ctx.fill();
+ } else if (this.isNotCloaked) {
+ this.isNotCloaked = false;
+ this.isBadTarget = true
+ this.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
+ }
+ };
+ },
+ sniperBullet(x, y, radius = 9, sides = 5) { //bullets
+ mobs.spawn(x, y, sides, radius, "rgb(255,0,155)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.onHit = function () {
+ this.explode(this.mass * 20);
+ };
+ Matter.Body.setDensity(me, 0.00005); //normal is 0.001
+ me.timeLeft = 120;
+ // me.g = 0.0005; //required if using this.gravity
+ me.frictionAir = 0;
+ me.restitution = 0;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
+ me.onDeath = function () {
+ if (simulation.difficulty > 11) { //explode AoE
+ const radius = 100 + 0.5 * simulation.difficulty + 50 * Math.random()
+ if (m.immuneCycle < m.cycle && Vector.magnitude(Vector.sub(this.position, player.position)) < radius) m.damage(0.0003 * radius * simulation.dmgScale);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: radius,
+ color: "rgba(255,0,155,0.5)",
+ time: simulation.drawTime
+ });
+ }
+ };
+ me.do = function () {
+ // this.gravity();
+ this.timeLimit();
+ if (Matter.Query.collides(this, map).length > 0 || Matter.Query.collides(this, body).length > 0 && this.speed < 10) {
+ this.isDropPowerUp = false;
+ this.death(); //death with no power up
+ }
+ };
+ },
+ launcherOne(x, y, radius = 30 + Math.ceil(Math.random() * 40)) {
+ mobs.spawn(x, y, 3, radius, "rgb(150,150,255)");
+ let me = mob[mob.length - 1];
+ me.accelMag = 0.00004 * simulation.accelScale;
+ me.fireFreq = Math.floor(420 + 90 * Math.random() * simulation.CDScale)
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.015;
+ spawn.shield(me, x, y);
+ me.onDamage = function () { };
+ me.do = function () {
+ this.seePlayerCheck();
+ this.checkStatus();
+ this.attraction();
+ if (this.seePlayer.recall && !(simulation.cycle % this.fireFreq)) {
+ Matter.Body.setAngularVelocity(this, 0.14)
+ spawn.seeker(this.vertices[0].x, this.vertices[0].y, 20, 9); //give the bullet a rotational velocity as if they were attached to a vertex
+ const who = mob[mob.length - 1]
+ Matter.Body.setDensity(who, 0.00003); //normal is 0.001
+ who.timeLeft = 840 //* (0.8 + 0.4 * Math.random());
+ who.accelMag = 0.00035 * simulation.accelScale; //* (0.8 + 0.4 * Math.random())
+ who.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
+ const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position, this.vertices[0]))), -6)
+ Matter.Body.setVelocity(who, {
+ x: this.velocity.x + velocity.x,
+ y: this.velocity.y + velocity.y
+ });
+ }
+ };
+ },
+ launcher(x, y, radius = 30 + Math.ceil(Math.random() * 40)) {
+ mobs.spawn(x, y, 3, radius, "rgb(150,150,255)");
+ let me = mob[mob.length - 1];
+ me.accelMag = 0.00004 * simulation.accelScale;
+ me.fireFreq = Math.floor(420 + 90 * Math.random() * simulation.CDScale)
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.02;
+ spawn.shield(me, x, y);
+ me.onDamage = function () { };
+ me.do = function () {
+ this.seePlayerCheck();
+ this.checkStatus();
+ this.attraction();
+ if (this.seePlayer.recall && !(simulation.cycle % this.fireFreq)) {
+ Matter.Body.setAngularVelocity(this, 0.14)
+ //fire a bullet from each vertex
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ spawn.seeker(this.vertices[i].x, this.vertices[i].y, 7)
+ //give the bullet a rotational velocity as if they were attached to a vertex
+ const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position, this.vertices[i]))), -8)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + velocity.x,
+ y: this.velocity.y + velocity.y
+ });
+ }
+ }
+ };
+ },
+ launcherBoss(x, y, radius = 90, isSpawnBossPowerUp = true) {
+ mobs.spawn(x, y, 6, radius, "rgb(150,150,255)");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ Matter.Body.setDensity(me, 0.0022 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+
+ me.accelMag = 0.0001 * simulation.accelScale;
+ me.fireFreq = Math.floor(330 * simulation.CDScale)
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.02;
+ me.memory = 420;
+ me.repulsionRange = 1000000; //squared
+ spawn.shield(me, x, y, 1);
+ spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
+
+ me.onDeath = function () {
+ if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
+ };
+ me.onDamage = function () { };
+ me.do = function () {
+ // this.armor();
+ this.seePlayerCheck();
+ this.checkStatus();
+ this.attraction();
+ this.repulsion();
+ if (this.seePlayer.recall && !(simulation.cycle % this.fireFreq)) {
+ Matter.Body.setAngularVelocity(this, 0.11)
+ //fire a bullet from each vertex
+ for (let i = 0, len = this.vertices.length; i < len; i++) {
+ spawn.seeker(this.vertices[i].x, this.vertices[i].y, 8)
+ //give the bullet a rotational velocity as if they were attached to a vertex
+ const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position, this.vertices[i]))), -10)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + velocity.x,
+ y: this.velocity.y + velocity.y
+ });
+ }
+ }
+ };
+ },
+ // blowSuckBoss(x, y, radius = 80) {
+ // mobs.spawn(x, y, 10, radius, "transparent");
+ // let me = mob[mob.length - 1];
+ // me.isBoss = true;
+ // Matter.Body.setDensity(me, 0.0022 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ // me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+
+ // me.fireFreq = Math.floor(60 * simulation.CDScale)
+ // me.seePlayerFreq = 15
+ // me.seeAtDistance2 = 300000;
+ // me.accelMag = 0.0003 * simulation.accelScale;
+ // if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search
+ // // Matter.Body.setDensity(me, 0.001); //normal is 0.001 //makes effective life much lower
+ // me.stroke = "transparent"; //used for drawGhost
+ // me.alpha = 1; //used in drawGhost
+ // me.isNotCloaked = false; //used in drawGhost
+ // me.isBadTarget = true;
+ // // me.leaveBody = false;
+ // me.collisionFilter.mask = cat.bullet //| cat.body
+ // me.showHealthBar = false;
+ // me.memory = 480;
+ // me.onDeath = function() {
+ // powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // };
+ // me.onDamage = function() {};
+ // me.suck = function() {
+ // for (let i = 0; i < mob.length; i++) {
+ // if (mob[i].isBlowSuckBullet) {
+ // const unit = Vector.normalise(Vector.sub(this.position, mob[i].position))
+ // const mag = Vector.mult(unit, 0.0008 * mob[i].mass)
+ // mob[i].force.x += mag.x
+ // mob[i].force.y += mag.y
+ // }
+ // }
+ // }
+ // me.do = function() {
+ // //cap max speed
+ // if (this.speed > 8) {
+ // Matter.Body.setVelocity(this, {
+ // x: this.velocity.x * 0.8,
+ // y: this.velocity.y * 0.8
+ // });
+ // }
+ // this.seePlayerCheckByDistance();
+ // this.checkStatus();
+ // this.attraction();
+ // this.search();
+ // //draw
+ // if (this.distanceToPlayer2() < this.seeAtDistance2) {
+ // if (this.alpha < 1) this.alpha += 0.005 * simulation.CDScale; //near player go solid
+ // } else {
+ // if (this.alpha > 0) this.alpha -= 0.05; ///away from player, hide
+ // }
+ // if (this.alpha > 0) {
+ // if (this.alpha > 0.8 && this.seePlayer.recall) {
+ // this.healthBar();
+ // if (!this.isNotCloaked) {
+ // this.isNotCloaked = true;
+ // this.isBadTarget = false;
+ // this.collisionFilter.mask = cat.player | cat.bullet
+ // }
+ // }
+ // //draw body
+ // ctx.beginPath();
+ // const vertices = this.vertices;
+ // ctx.moveTo(vertices[0].x, vertices[0].y);
+ // for (let j = 1, len = vertices.length; j < len; ++j) {
+ // ctx.lineTo(vertices[j].x, vertices[j].y);
+ // }
+ // ctx.lineTo(vertices[0].x, vertices[0].y);
+ // ctx.lineWidth = 1;
+ // ctx.fillStyle = `rgba(255,255,255,${this.alpha * this.alpha})`;
+ // ctx.fill();
+
+
+ // this.suck();
+ // if (this.seePlayer.recall && !(simulation.cycle % this.fireFreq)) {
+ // this.suckCount = 0;
+ // Matter.Body.setAngularVelocity(this, 0.11)
+ // //fire a bullet from each vertex
+ // for (let i = 0, len = this.vertices.length; i < len; i++) {
+ // spawn.bounceBullet(this.vertices[i].x, this.vertices[i].y, 8)
+ // //give the bullet a rotational velocity as if they were attached to a vertex
+ // const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position, this.vertices[i]))), -16)
+ // const who = mob[mob.length - 1]
+ // who.isBlowSuckBullet = true
+ // Matter.Body.setVelocity(who, {
+ // x: this.velocity.x + velocity.x,
+ // y: this.velocity.y + velocity.y
+ // });
+ // }
+ // }
+
+
+ // } else if (this.isNotCloaked) {
+ // this.isNotCloaked = false;
+ // this.isBadTarget = true;
+ // this.collisionFilter.mask = cat.bullet; //can't touch player or walls
+ // }
+ // };
+ // },
+ // blowSuckBoss(x, y, radius = 80, isSpawnBossPowerUp = true) {
+ // mobs.spawn(x, y, 10, radius, "transparent"); //rgb(60,60,85)
+ // let me = mob[mob.length - 1];
+ // me.isBoss = true;
+ // Matter.Body.setDensity(me, 0.0022 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ // me.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+
+ // me.accelMag = 0.0001 * simulation.accelScale;
+ // me.fireFreq = Math.floor(180 * simulation.CDScale)
+ // me.frictionStatic = 0;
+ // me.friction = 0;
+ // me.frictionAir = 0.005;
+ // me.memory = 420;
+ // me.repulsionRange = 1000000; //squared
+ // // spawn.shield(me, x, y, 1);
+ // // spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
+
+ // me.onDeath = function() {
+ // if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // };
+ // me.onDamage = function() {};
+ // me.suck = function() {
+ // for (let i = 0; i < mob.length; i++) {
+ // if (mob[i].isBlowSuckBullet) {
+ // const unit = Vector.normalise(Vector.sub(this.position, mob[i].position))
+ // const mag = Vector.mult(unit, 0.0008 * mob[i].mass)
+ // mob[i].force.x += mag.x
+ // mob[i].force.y += mag.y
+ // }
+ // }
+ // }
+ // me.do = function() {
+ // this.seePlayerCheck();
+ // this.checkStatus();
+ // this.attraction();
+ // // this.repulsion();
+ // this.suck();
+
+ // if (this.seePlayer.recall && !(simulation.cycle % this.fireFreq)) {
+ // this.suckCount = 0;
+ // Matter.Body.setAngularVelocity(this, 0.11)
+ // //fire a bullet from each vertex
+ // for (let i = 0, len = this.vertices.length; i < len; i++) {
+ // spawn.bounceBullet(this.vertices[i].x, this.vertices[i].y, 8)
+ // //give the bullet a rotational velocity as if they were attached to a vertex
+ // const velocity = Vector.mult(Vector.perp(Vector.normalise(Vector.sub(this.position, this.vertices[i]))), -16)
+ // const who = mob[mob.length - 1]
+ // who.isBlowSuckBullet = true
+ // Matter.Body.setVelocity(who, {
+ // x: this.velocity.x + velocity.x,
+ // y: this.velocity.y + velocity.y
+ // });
+ // }
+ // }
+ // };
+ // },
+ grenadierBoss(x, y, radius = 95) {
+ mobs.spawn(x, y, 6, radius, "rgb(0,235,255)");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+
+ me.accelMag = 0.0001 * simulation.accelScale;
+ me.fireFreq = Math.floor(360 * simulation.CDScale)
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.035;
+ me.memory = 420;
+ me.repulsionRange = 1200000; //squared
+ // spawn.shield(me, x, y, 1);
+ spawn.spawnOrbitals(me, radius + 50, 1);
+ spawn.spawnOrbitals(me, radius + 125, 1);
+ spawn.spawnOrbitals(me, radius + 200, 1);
+ Matter.Body.setDensity(me, 0.004 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ me.onDeath = function () { //helps collisions functions work better after vertex have been changed
+ setTimeout(() => { //fix mob in place, but allow rotation
+ for (let i = 0, len = 6; i < len; i++) {
+ const speed = 2.25 * simulation.accelScale;
+ const angle = 2 * Math.PI * i / len
+ spawn.grenade(this.position.x, this.position.y, 170 * simulation.CDScale);
+ const who = mob[mob.length - 1]
+ Matter.Body.setVelocity(who, {
+ x: speed * Math.cos(angle),
+ y: speed * Math.sin(angle)
+ });
+ }
+ }, 200);
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ }
+ me.grenadeLimiter = 0
+ me.onDamage = function () {
+ if (this.grenadeLimiter < 240 && this.health > 0) {
+ this.grenadeLimiter += 60
+ spawn.grenade(this.position.x, this.position.y, 80 + Math.floor(60 * Math.random()));
+ who = mob[mob.length - 1]
+ const velocity = Vector.mult(Vector.normalise(Vector.sub(player.position, who.position)), 3 * Math.sqrt(simulation.accelScale) + 4 * Math.random())
+ Matter.Body.setVelocity(who, {
+ x: this.velocity.x + velocity.x,
+ y: this.velocity.y + velocity.y
+ });
+ }
+ };
+ me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.do = function () {
+ // this.armor();
+ if (this.grenadeLimiter > 1) this.grenadeLimiter--
+ this.seePlayerCheck();
+ this.checkStatus();
+ this.attraction();
+ };
+ },
+ grenadier(x, y, radius = 35 + Math.ceil(Math.random() * 20)) {
+ mobs.spawn(x, y, 3, radius, "rgb(0,235,255)"); //rgb(255,100,200)
+ let me = mob[mob.length - 1];
+ me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front
+ me.isVerticesChange = true
+ // Matter.Body.rotate(me, Math.PI)
+ // me.stroke = "transparent"; //used for drawSneaker
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.memory = 60 //140;
+ me.fireFreq = 0.0055 + Math.random() * 0.0015;
+ me.noseLength = 0;
+ me.fireAngle = 0;
+ me.accelMag = 0.0006 * simulation.accelScale;
+ me.frictionAir = 0.05;
+ me.torque = 0.0001 * me.inertia * (Math.random() > 0.5 ? -1 : 1)
+ me.fireDir = {
+ x: 0,
+ y: 0
+ };
+ me.onDeath = function () { //helps collisions functions work better after vertex have been changed
+ spawn.grenade(this.position.x, this.position.y, 200 * simulation.CDScale);
+ // mob[mob.length - 1].collisionFilter.category = 0
+ mob[mob.length - 1].collisionFilter.mask = cat.player | cat.map;
+ }
+ // spawn.shield(me, x, y);
+ me.do = function () {
+ this.seePlayerCheck();
+ this.checkStatus();
+
+ const setNoseShape = () => {
+ const mag = this.radius + this.radius * this.noseLength;
+ this.vertices[1].x = this.position.x + Math.cos(this.angle) * mag;
+ this.vertices[1].y = this.position.y + Math.sin(this.angle) * mag;
+ };
+ //throw a mob/bullet at player
+ if (this.seePlayer.recall) {
+ //set direction to turn to fire
+ if (!(simulation.cycle % this.seePlayerFreq)) {
+ this.fireDir = Vector.normalise(Vector.sub(this.seePlayer.position, this.position));
+ // this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 1600; //gives the bullet an arc
+ }
+ //rotate towards fireAngle
+ const angle = this.angle + Math.PI / 2;
+ // c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
+ //rotate towards fireAngle
+ const dot = Vector.dot({
+ x: Math.cos(angle),
+ y: Math.sin(angle)
+ }, this.fireDir)
+ const threshold = 0.03;
+ if (dot > threshold) {
+ this.torque += 0.000004 * this.inertia;
+ } else if (dot < -threshold) {
+ this.torque -= 0.000004 * this.inertia;
+ } else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) {
+ //fire
+ spawn.grenade(this.vertices[1].x, this.vertices[1].y);
+ const v = 5 * simulation.accelScale;
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + this.fireDir.x * v + Math.random(),
+ y: this.velocity.y + this.fireDir.y * v + Math.random()
+ });
+ this.noseLength = 0;
+ // recoil
+ this.force.x -= 0.005 * this.fireDir.x * this.mass;
+ this.force.y -= 0.005 * this.fireDir.y * this.mass;
+ }
+ if (this.noseLength < 1.5) this.noseLength += this.fireFreq;
+ setNoseShape();
+ } else if (this.noseLength > 0.1) {
+ this.noseLength -= this.fireFreq / 2;
+ setNoseShape();
+ }
+ };
+ },
+ grenade(x, y, lifeSpan = 90 + Math.ceil(60 / simulation.accelScale), pulseRadius = Math.min(550, 250 + simulation.difficulty * 3), size = 3) {
+ mobs.spawn(x, y, 4, size, "rgb(215,0,190)"); //rgb(215,80,190)
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.onHit = function () {
+ this.explode(this.mass);
+ };
+ Matter.Body.setDensity(me, 0.00004); //normal is 0.001
+
+ me.lifeSpan = lifeSpan;
+ me.timeLeft = me.lifeSpan;
+ // me.g = 0.0002; //required if using this.gravity
+ me.frictionAir = 0;
+ me.restitution = 0.8;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.onDeath = function () {
+ //damage player if in range
+ if (Vector.magnitude(Vector.sub(player.position, this.position)) < pulseRadius && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage
+ m.damage(0.015 * simulation.dmgScale);
+ }
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: pulseRadius,
+ color: "rgba(255,0,220,0.3)",
+ time: simulation.drawTime
+ });
+ };
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.map | cat.body | cat.player
+ // me.collisionFilter.mask = 0
+ me.do = function () {
+ this.timeLimit();
+ ctx.beginPath(); //draw explosion outline
+ ctx.arc(this.position.x, this.position.y, pulseRadius * (1.01 - this.timeLeft / this.lifeSpan), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay
+ ctx.fillStyle = "rgba(255,0,220,0.05)";
+ ctx.fill();
+ };
+ },
+ shieldingBoss(x, y, radius = 200) {
+ mobs.spawn(x, y, 9, radius, "rgb(150, 150, 255)");
+ let me = mob[mob.length - 1];
+ setTimeout(() => { //fix mob in place, but allow rotation
+ me.constraint = Constraint.create({
+ pointA: {
+ x: me.position.x,
+ y: me.position.y
+ },
+ bodyB: me,
+ stiffness: 0.0001,
+ damping: 1
+ });
+ Composite.add(engine.world, me.constraint);
+ }, 2000); //add in a delay in case the level gets flipped left right
+
+ Matter.Body.rotate(me, Math.random() * 2 * Math.PI)
+ // me.stroke = "rgb(220,220,255)"
+ me.isBoss = true;
+ me.cycle = 0
+ me.maxCycles = 110;
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 1;
+ // me.homePosition = { x: x, y: y };
+ spawn.shield(me, x, y, 1);
+ spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
+
+ Matter.Body.setDensity(me, 0.0045); //extra dense //normal is 0.001 //makes effective life much larger
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
+ };
+ me.onDamage = function () {
+ this.cycle = 0
+ };
+ me.damageReduction = 0.35 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.do = function () {
+ Matter.Body.rotate(this, 0.003) //gently spin around
+ this.checkStatus();
+ ctx.beginPath(); //draw cycle timer
+ ctx.moveTo(this.vertices[this.vertices.length - 1].x, this.vertices[this.vertices.length - 1].y)
+ const phase = (this.vertices.length + 1) * this.cycle / this.maxCycles
+ if (phase > 1) ctx.lineTo(this.vertices[0].x, this.vertices[0].y)
+ for (let i = 1; i < phase - 1; i++) {
+ ctx.lineTo(this.vertices[i].x, this.vertices[i].y)
+ }
+ ctx.lineWidth = 5
+ ctx.strokeStyle = "rgb(255,255,255)"
+ ctx.stroke();
+
+ this.cycle++
+ if (this.cycle > this.maxCycles) {
+ this.cycle = 0
+ ctx.beginPath();
+ for (let i = 0; i < mob.length; i++) {
+ if (!mob[i].isShielded && !mob[i].shield && mob[i].isDropPowerUp && mob[i].alive && !mob[i].isBoss) {
+ ctx.moveTo(this.position.x, this.position.y)
+ ctx.lineTo(mob[i].position.x, mob[i].position.y)
+ spawn.shield(mob[i], mob[i].position.x, mob[i].position.y, 1, true);
+ // me.damageReduction = 0.075 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ mob[mob.length - 1].damageReduction = 0.5 * 0.075 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) //shields are extra strong
+ }
+ }
+ if (!this.isShielded && this.alive) spawn.shield(this, this.position.x, this.position.y, 1, true);
+ ctx.lineWidth = 20
+ ctx.strokeStyle = "rgb(200,200,255)"
+ ctx.stroke();
+ }
+ };
+ },
+ timeSkipBoss(x, y, radius = 50) {
+ mobs.spawn(x, y, 15, radius, "transparent");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.eventHorizon = 0; //set in mob loop
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.005;
+ me.accelMag = 0.00008 + 0.00002 * simulation.accelScale
+ spawn.shield(me, x, y, 1);
+ spawn.spawnOrbitals(me, radius + 50 + 100 * Math.random())
+
+ Matter.Body.setDensity(me, 0.0025); //extra dense //normal is 0.001 //makes effective life much larger
+ me.damageReduction = 0.07 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.startingDamageReduction = me.damageReduction
+ me.isInvulnerable = false
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // requestAnimationFrame(() => { simulation.timePlayerSkip(120) }); //wrapping in animation frame prevents errors, probably
+ };
+ me.onDamage = function () {
+ //find side of mob closest to player
+ //causes lag for foam,laser too many seekers //maybe scale chance with dmg
+ // const where = Vector.add(this.position, Vector.mult(Vector.normalise(Vector.sub(m.pos, this.position)), this.radius + 10))
+ // spawn.seeker(where.x, where.y); //give the bullet a rotational velocity as if they were attached to a vertex
+ };
+ me.do = function () {
+ this.seePlayerByHistory(60);
+ this.attraction();
+ this.checkStatus();
+ this.eventHorizon = 950 + 250 * Math.sin(simulation.cycle * 0.005)
+ if (!simulation.isTimeSkipping) {
+ if (Vector.magnitude(Vector.sub(this.position, m.pos)) < this.eventHorizon) {
+ this.attraction();
+ this.damageReduction = this.startingDamageReduction
+ this.isInvulnerable = false
+ // if (!(simulation.cycle % 15)) requestAnimationFrame(() => {
+ // simulation.timePlayerSkip(5)
+ // // simulation.loop(); //ending with a wipe and normal loop fixes some very minor graphical issues where things are draw in the wrong locations
+ // }); //wrapping in animation frame prevents errors, probably
+
+ //
+ // simulation.timePlayerSkip(1)
+ // m.walk_cycle += m.flipLegs * m.Vx //makes the legs look like they are moving fast
+ // }); //wrapping in animation frame prevents errors, probably
+ requestAnimationFrame(() => {
+ simulation.timePlayerSkip(1)
+ }); //wrapping in animation frame prevents errors, probably
+
+ m.walk_cycle += m.flipLegs * m.Vx //makes the legs look like they are moving fast
+
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
+ ctx.fillStyle = "#fff";
+ ctx.globalCompositeOperation = "destination-in"; //in or atop
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over";
+ ctx.beginPath();
+ ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI);
+ // ctx.stroke();
+ ctx.clip();
+ } else {
+ this.damageReduction = 0
+ this.isInvulnerable = true
+ //prevents other things from being drawn later on in the draw cycle
+ requestAnimationFrame(() => {
+ simulation.camera();
+ ctx.beginPath(); //gets rid of already draw shapes
+ ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI, false); //part you can't see
+ ctx.fillStyle = document.body.style.backgroundColor;
+ ctx.fill();
+ ctx.restore();
+ })
+ }
+ }
+ };
+ },
+ streamBoss(x, y, radius = 110) {
+ mobs.spawn(x, y, 5, radius, "rgb(245,180,255)");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ // me.accelMag = 0.00023 * simulation.accelScale;
+ me.accelMag = 0.00008 * simulation.accelScale;
+ // me.fireFreq = Math.floor(30 * simulation.CDScale)
+ me.canFire = false;
+ me.closestVertex1 = 0;
+ me.closestVertex2 = 1;
+ me.cycle = 0
+ me.frictionStatic = 0;
+ me.friction = 0;
+ me.frictionAir = 0.022;
+ me.memory = 240;
+ me.repulsionRange = 1200000; //squared
+ spawn.shield(me, x, y, 1);
+ spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random())
+
+ Matter.Body.setDensity(me, 0.01); //extra dense //normal is 0.001 //makes effective life much larger
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ // this.vertices = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //helps collisions functions work better after vertex have been changed
+ };
+ me.onDamage = function () { };
+ me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.do = function () {
+ // this.armor();
+ this.seePlayerCheck();
+ this.checkStatus();
+ this.attraction();
+ this.repulsion();
+
+ this.cycle++
+ if (this.seePlayer.recall && ((this.cycle % 15) === 0)) {
+ if (this.canFire) {
+ if (this.cycle > 100) {
+ this.cycle = 0
+ this.canFire = false
+ // Matter.Body.setAngularVelocity(this, 0.1)
+ // const forceMag = 0.01 * this.mass;
+ // const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ // this.force.x -= 2 * forceMag * Math.cos(angle);
+ // this.force.y -= 2 * forceMag * Math.sin(angle); // - 0.0007 * this.mass; //antigravity
+ }
+ spawn.seeker(this.vertices[this.closestVertex1].x, this.vertices[this.closestVertex1].y, 6)
+ Matter.Body.setDensity(mob[mob.length - 1], 0.000001); //normal is 0.001
+ const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[this.closestVertex1])), -10)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + velocity.x,
+ y: this.velocity.y + velocity.y
+ });
+ spawn.seeker(this.vertices[this.closestVertex2].x, this.vertices[this.closestVertex2].y, 6)
+ Matter.Body.setDensity(mob[mob.length - 1], 0.000001); //normal is 0.001
+ const velocity2 = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[this.closestVertex2])), -10)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + velocity2.x,
+ y: this.velocity.y + velocity2.y
+ });
+ } else if (this.cycle > 210) {
+ this.cycle = 0
+ this.canFire = true
+
+ //find closest 2 vertexes
+ let distance2 = Infinity
+ for (let i = 0; i < this.vertices.length; i++) {
+ const d = Vector.magnitudeSquared(Vector.sub(this.vertices[i], player.position))
+ if (d < distance2) {
+ distance2 = d
+ this.closestVertex2 = this.closestVertex1
+ this.closestVertex1 = i
+ }
+ }
+ if (this.closestVertex2 === this.closestVertex1) {
+ this.closestVertex2++
+ if (this.closestVertex2 === this.vertices.length) this.closestVertex2 = 0
+ }
+ }
+ }
+ };
+ },
+ seeker(x, y, radius = 8, sides = 6) {
+ //bullets
+ mobs.spawn(x, y, sides, radius, "rgb(255,0,255)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ me.onHit = function () {
+ this.explode(this.mass * 20);
+ };
+ Matter.Body.setDensity(me, 0.000015); //normal is 0.001
+ me.timeLeft = 420 //* (0.8 + 0.4 * Math.random());
+ me.accelMag = 0.00017 * simulation.accelScale; //* (0.8 + 0.4 * Math.random())
+ me.frictionAir = 0.01 //* (0.8 + 0.4 * Math.random());
+ me.restitution = 0.5;
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isMobBullet = true;
+ me.showHealthBar = false;
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
+ me.do = function () {
+ // this.seePlayer.yes = false;
+ this.alwaysSeePlayer()
+ this.attraction();
+ this.timeLimit();
+ };
+ },
+ spawner(x, y, radius = 55 + Math.ceil(Math.random() * 50)) {
+ mobs.spawn(x, y, 4, radius, "rgb(255,150,0)");
+ let me = mob[mob.length - 1];
+ me.g = 0.0004; //required if using this.gravity
+ me.leaveBody = false;
+ // me.isDropPowerUp = false;
+ me.onDeath = function () { //run this function on death
+ for (let i = 0; i < Math.ceil(this.mass * 0.15 + Math.random() * 2.5); ++i) {
+ spawn.spawns(this.position.x + (Math.random() - 0.5) * radius * 2.5, this.position.y + (Math.random() - 0.5) * radius * 2.5);
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + (Math.random() - 0.5) * 15,
+ y: this.velocity.x + (Math.random() - 0.5) * 15
+ });
+ }
+ };
+ spawn.shield(me, x, y);
+ me.do = function () {
+ this.gravity();
+ this.seePlayerCheck();
+ this.checkStatus();
+ this.attraction();
+ };
+ },
+ spawns(x, y, radius = 15) {
+ mobs.spawn(x, y, 4, radius, "rgb(255,0,0)");
+ let me = mob[mob.length - 1];
+ me.onHit = function () { //run this function on hitting player
+ this.explode();
+ };
+ // me.stroke = "transparent"
+ me.collisionFilter.mask = cat.player | cat.bullet | cat.body | cat.map | cat.mob
+ me.showHealthBar = false;
+ Matter.Body.setDensity(me, 0.0001); //normal is 0.001
+ me.g = 0.00002; //required if using this.gravity
+ me.accelMag = 0.00012 * simulation.accelScale;
+ // me.memory = 30;
+ me.isDropPowerUp = false
+ me.leaveBody = false;
+ me.seePlayerFreq = Math.floor((80 + 50 * Math.random()));
+ me.frictionAir = 0.004;
+ me.do = function () {
+ this.gravity();
+ this.seePlayerCheck();
+ this.checkStatus();
+ this.attraction();
+
+ // this.alwaysSeePlayer();
+ // this.checkStatus();
+ // this.attraction();
+ };
+ },
+ // exploder(x, y, radius = 40 + Math.ceil(Math.random() * 50)) {
+ // mobs.spawn(x, y, 4, radius, "rgb(255,0,0)");
+ // let me = mob[mob.length - 1];
+ // me.onHit = function() { //run this function on hitting player
+ // this.explode();
+ // };
+ // me.g = 0.0003; //required if using this.gravity
+ // me.seePlayerFreq = 50 + Math.floor(Math.random() * 20)
+ // me.do = function() {
+ // this.gravity();
+ // if (!(simulation.cycle % this.seePlayerFreq)) {
+ // if (
+ // this.distanceToPlayer2() < this.seeAtDistance2 &&
+ // Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 &&
+ // Matter.Query.ray(body, this.position, this.playerPosRandomY()).length === 0 &&
+ // !m.isCloak
+ // ) {
+ // this.foundPlayer();
+ // } else if (this.seePlayer.recall) {
+ // for (let i = 0; i < 20; i++) {
+ // let history = m.history[(m.cycle - 30 * i) % 600]
+ // if (Matter.Query.ray(map, this.position, history.position).length === 0) {
+ // this.seePlayer.recall = this.memory + Math.round(this.memory * Math.random()); //seconds before mob falls a sleep
+ // this.seePlayer.position.x = history.position.x;
+ // this.seePlayer.position.y = history.position.y;
+
+ // ctx.beginPath();
+ // ctx.moveTo(this.position.x, this.position.y);
+ // ctx.lineTo(history.position.x, history.position.y);
+ // ctx.lineWidth = 5;
+ // ctx.strokeStyle = "#000";
+ // ctx.stroke();
+
+ // break
+ // }
+ // }
+ // this.lostPlayer();
+ // }
+ // }
+ // this.checkStatus();
+ // this.attraction();
+ // };
+ // },
+ exploder(x, y, radius = 40 + Math.ceil(Math.random() * 50)) {
+ mobs.spawn(x, y, 4, radius, "rgb(255,0,0)");
+ let me = mob[mob.length - 1];
+ me.onHit = function () {
+ //run this function on hitting player
+ this.explode();
+ };
+ me.g = 0.0004; //required if using this.gravity
+ me.do = function () {
+ this.gravity();
+ this.seePlayerCheck();
+ this.checkStatus();
+ this.attraction();
+ };
+ },
+ snakeSpitBoss(x, y, radius = 50) {
+ let angle = Math.PI
+ const tailRadius = 300
+
+ const color1 = "rgb(235,180,255)"
+ mobs.spawn(x + tailRadius * Math.cos(angle), y + tailRadius * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)"
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ me.accelMag = 0.0001 + 0.0004 * Math.sqrt(simulation.accelScale)
+ // me.accelMag = 0.0004 + 0.0002 * Math.sqrt(simulation.accelScale)
+ me.memory = 250;
+ me.laserRange = 500;
+ Matter.Body.setDensity(me, 0.0022 + 0.00022 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ me.startingDamageReduction = 0.14 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.damageReduction = 0
+ me.isInvulnerable = true
+
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (this.id === mob[i].snakeHeadID && mob[i].alive) mob[i].death()
+ }
+ };
+ };
+ me.canFire = false;
+ me.closestVertex1 = 0;
+ me.cycle = 0
+ me.do = function () {
+ // this.armor();
+ this.seePlayerByHistory(40)
+ this.checkStatus();
+ this.attraction();
+ this.cycle++
+ if (this.seePlayer.recall && ((this.cycle % 10) === 0)) {
+ if (this.canFire) {
+ if (this.cycle > 120) {
+ this.cycle = 0
+ this.canFire = false
+ // Matter.Body.setAngularVelocity(this, 0.1)
+ // const forceMag = 0.01 * this.mass;
+ // const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
+ // this.force.x -= 2 * forceMag * Math.cos(angle);
+ // this.force.y -= 2 * forceMag * Math.sin(angle); // - 0.0007 * this.mass; //antigravity
+ }
+ spawn.seeker(this.vertices[this.closestVertex1].x, this.vertices[this.closestVertex1].y, 6)
+ Matter.Body.setDensity(mob[mob.length - 1], 0.000001); //normal is 0.001
+ const velocity = Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.closestVertex1], this.position)), 15)
+ Matter.Body.setVelocity(mob[mob.length - 1], {
+ x: this.velocity.x + velocity.x,
+ y: this.velocity.y + velocity.y
+ });
+ // spawn.seeker(this.vertices[this.closestVertex2].x, this.vertices[this.closestVertex2].y, 6)
+ // Matter.Body.setDensity(mob[mob.length - 1], 0.000001); //normal is 0.001
+ // const velocity2 = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[this.closestVertex2])), -10)
+ // Matter.Body.setVelocity(mob[mob.length - 1], {
+ // x: this.velocity.x + velocity2.x,
+ // y: this.velocity.y + velocity2.y
+ // });
+ } else if (this.cycle > 200) {
+ this.cycle = 0
+ this.canFire = true
+
+ //find closest 2 vertexes
+ let distance2 = Infinity
+ for (let i = 0; i < this.vertices.length; i++) {
+ const d = Vector.magnitudeSquared(Vector.sub(this.vertices[i], player.position))
+ if (d < distance2) {
+ distance2 = d
+ // this.closestVertex2 = this.closestVertex1
+ this.closestVertex1 = i
+ }
+ }
+ // if (this.closestVertex2 === this.closestVertex1) {
+ // this.closestVertex2++
+ // if (this.closestVertex2 === this.vertices.length) this.closestVertex2 = 0
+ // }
+ }
+ }
+ if (this.isInvulnerable) {
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 20;
+ ctx.strokeStyle = "rgba(255,255,255,0.7)";
+ ctx.stroke();
+ }
+ };
+ //extra space to give head room
+ angle -= 0.07
+ let previousTailID = 0
+ const nodes = Math.min(10 + Math.ceil(0.6 * simulation.difficulty), 60)
+ for (let i = 0; i < nodes; ++i) {
+ angle -= 0.1
+ spawn.snakeBody(x + tailRadius * Math.cos(angle), y + tailRadius * Math.sin(angle), i === 0 ? 25 : 20);
+ if (i < 4) mob[mob.length - 1].snakeHeadID = me.id
+ mob[mob.length - 1].previousTailID = previousTailID
+ previousTailID = mob[mob.length - 1].id
+ }
+ const damping = 1
+ const stiffness = 1
+ this.constrain2AdjacentMobs(nodes, stiffness, false, damping);
+ for (let i = mob.length - 1, len = i - nodes; i > len; i--) { //set alternating colors
+ if (i % 2) {
+ mob[i].fill = "#778"
+ } else {
+ mob[i].fill = color1
+ }
+ }
+ //constraint with first 3 mobs in line
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - nodes],
+ bodyB: mob[mob.length - 1 - nodes],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - nodes + 1],
+ bodyB: mob[mob.length - 1 - nodes],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - nodes + 2],
+ bodyB: mob[mob.length - 1 - nodes],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ },
+ dragonFlyBoss(x, y, radius = 42) { //snake boss with a laser head
+ let angle = Math.PI
+ const tailRadius = 300
+ mobs.spawn(x + tailRadius * Math.cos(angle), y + tailRadius * Math.sin(angle), 8, radius, "#000"); //"rgb(55,170,170)"
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ Matter.Body.setDensity(me, 0.00165 + 0.00011 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ me.startingDamageReduction = 0.14 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.damageReduction = 0
+ me.isInvulnerable = true
+
+ me.accelMag = 0.00008 + 0.00045 * Math.sqrt(simulation.accelScale)
+ me.memory = 250;
+ me.seePlayerFreq = 13
+ me.flapRate = 0.4
+ me.flapArc = 0.2 //don't go past 1.57 for normal flaps
+ me.wingLength = 150
+ me.ellipticity = 0.3
+ me.angleOff = 0.4
+
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (this.id === mob[i].snakeHeadID && mob[i].alive) mob[i].death()
+ }
+ };
+ me.do = function () {
+ this.seePlayerByHistory(40)
+ this.checkStatus();
+ this.attraction();
+
+ let a //used to set the angle of wings
+ if (this.isInvulnerable) {
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 12;
+ ctx.strokeStyle = "rgba(255,255,255,0.9)";
+ ctx.stroke();
+ const sub = Vector.sub(this.position, this.snakeBody1.position)
+ a = Math.atan2(sub.y, sub.x)
+ } else {
+ a = Math.atan2(this.velocity.y, this.velocity.x)
+ }
+
+ ctx.fillStyle = `hsla(${160 + 40 * Math.random()}, 100%, ${25 + 25 * Math.random() * Math.random()}%, 0.9)`; //"rgba(0,235,255,0.3)"; // ctx.fillStyle = `hsla(44, 79%, 31%,0.4)`; //"rgba(0,235,255,0.3)";
+ this.wing(a + Math.PI / 2 + this.angleOff + this.flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingLength, this.ellipticity)
+ this.wing(a - Math.PI / 2 - this.angleOff - this.flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingLength, this.ellipticity)
+ this.wing(a - Math.PI / 2 + this.angleOff + this.flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingLength, this.ellipticity)
+ this.wing(a + Math.PI / 2 - this.angleOff - this.flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingLength, this.ellipticity)
+ };
+
+ angle -= 0.07
+ let previousTailID = 0
+ const nodes = Math.min(10 + Math.ceil(0.6 * simulation.difficulty), 60)
+ for (let i = 0; i < nodes; ++i) {
+ angle -= 0.1
+ spawn.snakeBody(x + tailRadius * Math.cos(angle), y + tailRadius * Math.sin(angle), i === 0 ? 25 : 20);
+ const who = mob[mob.length - 1]
+ who.fill = `hsl(${160 + 40 * Math.random()}, 100%, ${5 + 25 * Math.random() * Math.random()}%)`
+ if (i < 4) who.snakeHeadID = me.id
+ if (i === 0) me.snakeBody1 = who //track this segment, so the difference in position between this segment and the head can be used to angle the wings
+ who.previousTailID = previousTailID
+ previousTailID = who.id
+ }
+ const damping = 1
+ const stiffness = 1
+ this.constrain2AdjacentMobs(nodes, stiffness, false, damping);
+ //constraint with first few mobs in tail
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - nodes],
+ bodyB: mob[mob.length - 1 - nodes],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - nodes + 1],
+ bodyB: mob[mob.length - 1 - nodes],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - nodes + 2],
+ bodyB: mob[mob.length - 1 - nodes],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ },
+ snakeBody(x, y, radius = 10) {
+ mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)");
+ let me = mob[mob.length - 1];
+ me.collisionFilter.mask = cat.bullet | cat.player //| cat.mob //| cat.body
+ me.damageReduction = 0.028
+ Matter.Body.setDensity(me, 0.0001); //normal is 0.001
+
+ // me.accelMag = 0.0007 * simulation.accelScale;
+ me.leaveBody = Math.random() < 0.33 ? true : false;
+ me.showHealthBar = false;
+ me.isDropPowerUp = false;
+ me.frictionAir = 0;
+ me.isSnakeTail = true;
+ me.stroke = "transparent"
+ me.onDeath = function () {
+ setTimeout(() => {
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (this.id === mob[i].previousTailID && mob[i].alive) mob[i].death()
+ if (this.snakeHeadID === mob[i].id) {
+ mob[i].isInvulnerable = false
+ mob[i].damageReduction = mob[i].startingDamageReduction
+ }
+ }
+ }, 500);
+ };
+ me.do = function () {
+ this.checkStatus();
+ };
+ // me.doActive = function() {
+ // this.checkStatus();
+ // this.alwaysSeePlayer();
+ // this.attraction();
+ // };
+ },
+ tetherBoss(x, y, constraint, radius = 90) {
+ // constrained mob boss for the towers level
+ // often has a ring of mobs around it
+ mobs.spawn(x, y, 8, radius, "rgb(0,60,80)");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ Matter.Body.setDensity(me, 0.0005 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.startingDamageReduction = me.damageReduction
+ me.isInvulnerable = false
+ me.nextHealthThreshold = 0.75
+ me.invulnerableCount = 0
+ me.g = 0.0001; //required if using this.gravity
+ me.accelMag = 0.0012 + 0.0013 * simulation.accelScale;
+ me.memory = 20;
+ me.repulsionRange = 1800 * 1800
+
+ cons[cons.length] = Constraint.create({
+ pointA: { x: constraint.x, y: constraint.y },
+ bodyB: me,
+ stiffness: 0.00012
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+
+ spawn.shield(me, x, y, 1);
+ setTimeout(() => { spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random()) }, 100); //have to wait a sec so the tether constraint doesn't attach to an orbital
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ this.removeCons(); //remove constraint
+ me.babies(0.05 * simulation.difficulty + 1)
+ };
+ me.babies = function (len) {
+ const delay = Math.max(3, Math.floor(15 - len / 2))
+ let i = 0
+ let spawnFlutters = () => {
+ if (i < len) {
+ if (!(simulation.cycle % delay) && !simulation.paused && !simulation.isChoosing && m.alive) {
+ // const phase = i / len * 2 * Math.PI
+ // const where = Vector.add(this.position, Vector.mult({ x: Math.cos(phase), y: Math.sin(phase) }, radius * 1.5))
+ const unit = Vector.normalise(Vector.sub(player.position, this.position))
+ const velocity = Vector.mult(unit, 10 + 10 * Math.random())
+ const where = Vector.add(this.position, Vector.mult(unit, radius * 1.2))
+ spawn.allowShields = false
+ spawn.flutter(where.x, where.y, Math.floor(9 + 8 * Math.random()))
+ const who = mob[mob.length - 1]
+ Matter.Body.setDensity(who, 0.01); //extra dense //normal is 0.001 //makes effective life much larger
+ Matter.Body.setVelocity(who, velocity);
+ Matter.Body.setAngle(who, Math.atan2(velocity.y, velocity.x))
+
+ this.alertNearByMobs();
+ spawn.allowShields = true
+ i++
+ }
+ requestAnimationFrame(spawnFlutters);
+ }
+ }
+ requestAnimationFrame(spawnFlutters);
+ }
+ me.onDamage = function () {
+ if (this.health < this.nextHealthThreshold && this.alive) {
+ this.health = this.nextHealthThreshold - 0.01
+ this.nextHealthThreshold = Math.floor(this.health * 4) / 4
+ this.invulnerableCount = 90 + Math.floor(30 * Math.random())
+ this.isInvulnerable = true
+ this.damageReduction = 0
+ }
+ };
+ me.do = function () {
+ this.gravity();
+ if (this.isInvulnerable) {
+ this.repulsion();
+ this.invulnerableCount--
+ if (this.invulnerableCount < 0) {
+ this.isInvulnerable = false
+ this.damageReduction = this.startingDamageReduction
+ this.frictionAir = 0.05
+ me.babies(0.07 * simulation.difficulty + 2)
+ if (this.radius > 15) {
+ const scale = 0.88;
+ Matter.Body.scale(this, scale, scale);
+ this.radius *= scale;
+ }
+ }
+ //draw invulnerable
+ ctx.beginPath();
+ let vertices = this.vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.lineTo(vertices[0].x, vertices[0].y);
+ ctx.lineWidth = 13 + 5 * Math.random();
+ ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
+ ctx.stroke();
+ } else {
+ this.seePlayerCheck();
+ this.checkStatus();
+ this.attraction();
+ }
+ };
+ },
+ shield(target, x, y, chance = Math.min(0.02 + simulation.difficulty * 0.005, 0.2) + tech.duplicationChance(), isExtraShield = false) {
+ if (this.allowShields && Math.random() < chance) {
+ mobs.spawn(x, y, 9, target.radius + 30, "rgba(220,220,255,0.9)");
+ let me = mob[mob.length - 1];
+ me.stroke = "rgb(220,220,255)";
+ Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion
+ me.shield = true;
+ me.damageReduction = 0.05 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.isUnblockable = true
+ me.isExtraShield = isExtraShield //this prevents spamming with tech.isShieldAmmo
+ me.collisionFilter.category = cat.mobShield
+ me.collisionFilter.mask = cat.bullet;
+ consBB[consBB.length] = Constraint.create({
+ bodyA: me,
+ bodyB: target, //attach shield to target
+ stiffness: 0.4,
+ damping: 0.1
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+
+ me.onDamage = function () {
+ //make sure the mob that owns the shield can tell when damage is done
+ this.alertNearByMobs();
+ this.fill = `rgba(220,220,255,${0.3 + 0.6 * this.health})`
+ };
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+
+ me.shieldTargetID = target.id
+ target.isShielded = true;
+ target.shieldID = me.id
+ me.onDeath = function () {
+ //clear isShielded status from target
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].id === this.shieldTargetID) mob[i].isShielded = false;
+ }
+ };
+ me.do = function () {
+ this.checkStatus();
+ };
+
+ mob.unshift(me); //move shield to the front of the array, so that mob is behind shield graphically
+
+ //swap order of shield and mob, so that mob is behind shield graphically
+ // mob[mob.length - 1] = mob[mob.length - 2];
+ // mob[mob.length - 2] = me;
+ }
+ },
+ groupShield(targets, x, y, radius, stiffness = 0.4) {
+ const nodes = targets.length
+ mobs.spawn(x, y, 9, radius, "rgba(220,220,255,0.9)");
+ let me = mob[mob.length - 1];
+ me.stroke = "rgb(220,220,255)";
+ Matter.Body.setDensity(me, 0.00001) //very low density to not mess with the original mob's motion
+ me.frictionAir = 0;
+ me.shield = true;
+ me.damageReduction = 0.075 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+ me.collisionFilter.category = cat.mobShield
+ me.collisionFilter.mask = cat.bullet;
+ for (let i = 0; i < nodes; ++i) {
+ mob[mob.length - i - 2].isShielded = true;
+ //constrain to all mob nodes in group
+ consBB[consBB.length] = Constraint.create({
+ bodyA: me,
+ bodyB: mob[mob.length - i - 2],
+ stiffness: stiffness,
+ damping: 0.1
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ me.onDamage = function () {
+ this.alertNearByMobs(); //makes sure the mob that owns the shield can tell when damage is done
+ this.fill = `rgba(220,220,255,${0.3 + 0.6 * this.health})`
+ };
+ me.onDeath = function () {
+ //clear isShielded status from target
+ for (let j = 0; j < targets.length; j++) {
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].id === targets[j]) mob[i].isShielded = false;
+ }
+ }
+ };
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ mob[mob.length - 1] = mob[mob.length - 1 - nodes];
+ mob[mob.length - 1 - nodes] = me;
+ me.do = function () {
+ this.checkStatus();
+ };
+ },
+ spawnOrbitals(who, radius, chance = Math.min(0.25 + simulation.difficulty * 0.005)) {
+ if (Math.random() < chance) {
+ // simulation.difficulty = 50
+ const len = Math.floor(Math.min(15, 3 + Math.sqrt(simulation.difficulty))) // simulation.difficulty = 40 on hard mode level 10
+ const speed = (0.003 + 0.004 * Math.random() + 0.002 * Math.sqrt(simulation.difficulty)) * ((Math.random() < 0.5) ? 1 : -1)
+ const offSet = 6.28 * Math.random()
+ for (let i = 0; i < len; i++) spawn.orbital(who, radius, i / len * 2 * Math.PI + offSet, speed)
+ }
+ },
+ orbital(who, radius, phase, speed) {
+ // for (let i = 0, len = 7; i < len; i++) spawn.orbital(me, radius + 250, 2 * Math.PI / len * i)
+ mobs.spawn(who.position.x, who.position.y, 8, 12, "rgb(255,0,150)");
+ let me = mob[mob.length - 1];
+ me.stroke = "transparent";
+ Matter.Body.setDensity(me, 0.01); //normal is 0.001
+ me.leaveBody = false;
+ me.isDropPowerUp = false;
+ me.isBadTarget = true;
+ me.isUnstable = true; //dies when blocked
+ me.showHealthBar = false;
+ me.isOrbital = true;
+ // me.isShielded = true
+ me.collisionFilter.category = cat.mobBullet;
+ me.collisionFilter.mask = cat.bullet; //cat.player | cat.map | cat.body
+ me.do = function () {
+ //if host is gone
+ if (!who || !who.alive) {
+ this.death();
+ return
+ }
+ //set orbit
+ const time = simulation.cycle * speed + phase
+ const orbit = {
+ x: Math.cos(time),
+ y: Math.sin(time)
+ }
+ Matter.Body.setPosition(this, Vector.add(Vector.add(who.position, who.velocity), Vector.mult(orbit, radius)))
+ //damage player
+ if (Matter.Query.collides(this, [player]).length > 0 && !(m.isCloak && tech.isIntangible) && m.immuneCycle < m.cycle) {
+ m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles
+ const dmg = 0.03 * simulation.dmgScale
+ m.damage(dmg);
+ simulation.drawList.push({ //add dmg to draw queue
+ x: this.position.x,
+ y: this.position.y,
+ radius: Math.sqrt(dmg) * 200,
+ color: simulation.mobDmgColor,
+ time: simulation.drawTime
+ });
+ this.death();
+ }
+ };
+ },
+ orbitalBoss(x, y, radius = 70) {
+ const nodeBalance = Math.random()
+ const nodes = Math.min(15, Math.floor(2 + 4 * nodeBalance + 0.75 * Math.sqrt(simulation.difficulty)))
+ mobs.spawn(x, y, nodes, radius, "rgb(255,0,150)");
+ let me = mob[mob.length - 1];
+ me.isBoss = true;
+ Matter.Body.setDensity(me, 0.0017 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
+ me.damageReduction = 0.1 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
+
+ me.stroke = "transparent"; //used for drawGhost
+ me.seeAtDistance2 = 2000000;
+ me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map
+ me.memory = Infinity;
+ me.frictionAir = 0.04;
+ me.accelMag = 0.0002 + 0.00015 * simulation.accelScale
+ spawn.shield(me, x, y, 1);
+
+ const rangeInnerVsOuter = Math.random()
+ let speed = (0.006 + 0.001 * Math.sqrt(simulation.difficulty)) * ((Math.random() < 0.5) ? 1 : -1)
+ let range = radius + 350 + 200 * rangeInnerVsOuter + nodes * 7
+ for (let i = 0; i < nodes; i++) spawn.orbital(me, range, i / nodes * 2 * Math.PI, speed)
+ const orbitalIndexes = [] //find indexes for all the current nodes
+ for (let i = 0; i < nodes; i++) orbitalIndexes.push(mob.length - 1 - i)
+ // add orbitals for each orbital
+ range = Math.max(60, 100 + 100 * Math.random() - nodes * 3 - rangeInnerVsOuter * 80)
+ speed = speed * (1.25 + 2 * Math.random())
+ const subNodes = Math.max(2, Math.floor(6 - 5 * nodeBalance + 0.5 * Math.sqrt(simulation.difficulty)))
+ for (let j = 0; j < nodes; j++) {
+ for (let i = 0, len = subNodes; i < len; i++) spawn.orbital(mob[orbitalIndexes[j]], range, i / len * 2 * Math.PI, speed)
+ }
+ for (let i = 0, len = 3 + 0.5 * Math.sqrt(simulation.difficulty); i < len; i++) spawn.spawnOrbitals(me, radius + 40 + 10 * i, 1);
+
+ me.onDeath = function () {
+ powerUps.spawnBossPowerUp(this.position.x, this.position.y)
+ };
+ me.do = function () {
+ this.seePlayerByHistory();
+ this.checkStatus();
+ this.attraction();
+ };
+ },
+ //complex constrained mob templates**********************************************************************
+ //*******************************************************************************************************
+ allowShields: true,
+ nodeGroup(
+ x,
+ y,
+ spawn = "striker",
+ nodes = Math.min(2 + Math.ceil(Math.random() * (simulation.difficulty + 2)), 8),
+ //Math.ceil(Math.random() * 3) + Math.min(4,Math.ceil(simulation.difficulty/2)),
+ radius = Math.ceil(Math.random() * 10) + 18, // radius of each node mob
+ sideLength = Math.ceil(Math.random() * 100) + 70, // distance between each node mob
+ stiffness = Math.random() * 0.03 + 0.005
+ ) {
+ this.allowShields = false; //don't want shields on individual group mobs
+ const angle = 2 * Math.PI / nodes
+ let targets = []
+ for (let i = 0; i < nodes; ++i) {
+ let whoSpawn = spawn;
+ if (spawn === "random") {
+ whoSpawn = this.fullPickList[Math.floor(Math.random() * this.fullPickList.length)];
+ } else if (spawn === "randomList") {
+ whoSpawn = this.pickList[Math.floor(Math.random() * this.pickList.length)];
+ }
+ this[whoSpawn](x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius);
+ targets.push(mob[mob.length - 1].id) //track who is in the group, for shields
+ }
+ if (Math.random() < 0.3) {
+ this.constrain2AdjacentMobs(nodes, stiffness * 2, true);
+ } else {
+ this.constrainAllMobCombos(nodes, stiffness);
+ }
+ //spawn shield for entire group
+ if (nodes > 2 && Math.random() < 0.998) {
+ this.groupShield(targets, x, y, sideLength + 2.5 * radius + nodes * 6 - 25);
+ }
+ this.allowShields = true;
+ },
+ lineGroup(
+ x,
+ y,
+ spawn = "striker",
+ nodes = Math.min(3 + Math.ceil(Math.random() * simulation.difficulty + 2), 8),
+ //Math.ceil(Math.random() * 3) + Math.min(4,Math.ceil(simulation.difficulty/2)),
+ radius = Math.ceil(Math.random() * 10) + 17,
+ l = Math.ceil(Math.random() * 80) + 30,
+ stiffness = Math.random() * 0.06 + 0.01
+ ) {
+ this.allowShields = false; //don't want shields on individual group mobs
+ for (let i = 0; i < nodes; ++i) {
+ let whoSpawn = spawn;
+ if (spawn === "random") {
+ whoSpawn = this.fullPickList[Math.floor(Math.random() * this.fullPickList.length)];
+ } else if (spawn === "randomList") {
+ whoSpawn = this.pickList[Math.floor(Math.random() * this.pickList.length)];
+ }
+ this[whoSpawn](x + i * radius + i * l, y, radius);
+ }
+ this.constrain2AdjacentMobs(nodes, stiffness);
+ this.allowShields = true;
+ },
+ //constraints ************************************************************************************************
+ //*************************************************************************************************************
+ constrainAllMobCombos(nodes, stiffness) {
+ //runs through every combination of last 'num' bodies and constrains them
+ for (let i = 1; i < nodes + 1; ++i) {
+ for (let j = i + 1; j < nodes + 1; ++j) {
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - i],
+ bodyB: mob[mob.length - j],
+ stiffness: stiffness
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ }
+ },
+ constrain2AdjacentMobs(nodes, stiffness, loop = false, damping = 0) {
+ //runs through every combination of last 'num' bodies and constrains them
+ for (let i = 0; i < nodes - 1; ++i) {
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - i - 1],
+ bodyB: mob[mob.length - i - 2],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ if (nodes > 2) {
+ for (let i = 0; i < nodes - 2; ++i) {
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - i - 1],
+ bodyB: mob[mob.length - i - 3],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ }
+ //optional connect the tail to head
+ if (loop && nodes > 3) {
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - 1],
+ bodyB: mob[mob.length - nodes],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - 2],
+ bodyB: mob[mob.length - nodes],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ consBB[consBB.length] = Constraint.create({
+ bodyA: mob[mob.length - 1],
+ bodyB: mob[mob.length - nodes + 1],
+ stiffness: stiffness,
+ damping: damping
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ }
+ },
+ constraintPB(x, y, bodyIndex, stiffness) {
+ cons[cons.length] = Constraint.create({
+ pointA: {
+ x: x,
+ y: y
+ },
+ bodyB: body[bodyIndex],
+ stiffness: stiffness
+ });
+ Composite.add(engine.world, cons[cons.length - 1]);
+ },
+ constraintBB(bodyIndexA, bodyIndexB, stiffness) {
+ consBB[consBB.length] = Constraint.create({
+ bodyA: body[bodyIndexA],
+ bodyB: body[bodyIndexB],
+ stiffness: stiffness
+ });
+ Composite.add(engine.world, consBB[consBB.length - 1]);
+ },
+ // body and map spawns ******************************************************************************
+ //**********************************************************************************************
+ wireHead() {
+ //not a mob, just a graphic for level 1
+ const breakingPoint = 1300
+ mobs.spawn(breakingPoint, -100, 0, 7.5, "transparent");
+ let me = mob[mob.length - 1];
+ me.collisionFilter.category = cat.body;
+ me.collisionFilter.mask = cat.map;
+ me.inertia = Infinity;
+ me.g = 0.0004; //required for gravity
+ me.restitution = 0;
+ me.stroke = "transparent"
+ me.freeOfWires = false;
+ me.frictionStatic = 1;
+ me.friction = 1;
+ me.frictionAir = 0.01;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.isBadTarget = true;
+ me.isUnblockable = true;
+
+ me.do = function () {
+ let wireX = -50;
+ let wireY = -1000;
+ if (this.freeOfWires) {
+ this.gravity();
+ } else {
+ if (m.pos.x > breakingPoint) {
+ this.freeOfWires = true;
+ this.fill = "#000"
+ this.force.x += -0.003;
+ player.force.x += 0.06;
+ // player.force.y -= 0.15;
+ }
+
+ //player is extra heavy from wires
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x,
+ y: player.velocity.y + 0.3
+ })
+
+ //player friction from the wires
+ if (m.pos.x > 700 && player.velocity.x > -2) {
+ let wireFriction = 0.75 * Math.min(0.6, Math.max(0, 100 / (breakingPoint - m.pos.x)));
+ if (!m.onGround) wireFriction *= 3
+ Matter.Body.setVelocity(player, {
+ x: player.velocity.x - wireFriction,
+ y: player.velocity.y
+ })
+ }
+ //move to player
+ Matter.Body.setPosition(this, {
+ x: m.pos.x + (42 * Math.cos(m.angle + Math.PI)),
+ y: m.pos.y + (42 * Math.sin(m.angle + Math.PI))
+ })
+ }
+ //draw wire
+ ctx.beginPath();
+ ctx.moveTo(wireX, wireY);
+ ctx.quadraticCurveTo(wireX, 0, this.position.x, this.position.y);
+ if (!this.freeOfWires) ctx.lineTo(m.pos.x + (30 * Math.cos(m.angle + Math.PI)), m.pos.y + (30 * Math.sin(m.angle + Math.PI)));
+ ctx.lineCap = "butt";
+ ctx.lineWidth = 15;
+ ctx.strokeStyle = "#000";
+ ctx.stroke();
+ ctx.lineCap = "round";
+ };
+ },
+ wireKnee() {
+ //not a mob, just a graphic for level 1
+ const breakingPoint = 1425
+ mobs.spawn(breakingPoint, -100, 0, 2, "transparent");
+ let me = mob[mob.length - 1];
+ //touch nothing
+ me.collisionFilter.category = cat.body;
+ me.collisionFilter.mask = cat.map;
+ me.g = 0.0003; //required for gravity
+ // me.restitution = 0;
+ me.stroke = "transparent"
+ // me.inertia = Infinity;
+ me.restitution = 0;
+ me.freeOfWires = false;
+ me.frictionStatic = 1;
+ me.friction = 1;
+ me.frictionAir = 0.01;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.isBadTarget = true;
+ me.isUnblockable = true;
+
+ me.do = function () {
+ let wireX = -50 - 20;
+ let wireY = -1000;
+
+ if (this.freeOfWires) {
+ this.gravity();
+ } else {
+ if (m.pos.x > breakingPoint) {
+ this.freeOfWires = true;
+ this.force.x -= 0.0004;
+ this.fill = "#222";
+ }
+ //move mob to player
+ m.calcLeg(0, 0);
+ Matter.Body.setPosition(this, {
+ x: m.pos.x + m.flipLegs * m.knee.x - 5,
+ y: m.pos.y + m.knee.y
+ })
+ }
+ //draw wire
+ ctx.beginPath();
+ ctx.moveTo(wireX, wireY);
+ ctx.quadraticCurveTo(wireX, 0, this.position.x, this.position.y);
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = "#222";
+ ctx.lineCap = "butt";
+ ctx.stroke();
+ ctx.lineCap = "round";
+ };
+ },
+ wireKneeLeft() {
+ //not a mob, just a graphic for level 1
+ const breakingPoint = 1400
+ mobs.spawn(breakingPoint, -100, 0, 2, "transparent");
+ let me = mob[mob.length - 1];
+ //touch nothing
+ me.collisionFilter.category = cat.body;
+ me.collisionFilter.mask = cat.map;
+ me.g = 0.0003; //required for gravity
+ // me.restitution = 0;
+ me.stroke = "transparent"
+ // me.inertia = Infinity;
+ me.restitution = 0;
+ me.freeOfWires = false;
+ me.frictionStatic = 1;
+ me.friction = 1;
+ me.frictionAir = 0.01;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.isBadTarget = true;
+ me.isUnblockable = true;
+
+ me.do = function () {
+ let wireX = -50 - 35;
+ let wireY = -1000;
+
+ if (this.freeOfWires) {
+ this.gravity();
+ } else {
+ if (m.pos.x > breakingPoint) {
+ this.freeOfWires = true;
+ this.force.x += -0.0003;
+ this.fill = "#333";
+ }
+ //move mob to player
+ m.calcLeg(Math.PI, -3);
+ Matter.Body.setPosition(this, {
+ x: m.pos.x + m.flipLegs * m.knee.x - 5,
+ y: m.pos.y + m.knee.y
+ })
+ }
+ //draw wire
+ ctx.beginPath();
+ ctx.moveTo(wireX, wireY);
+ ctx.quadraticCurveTo(wireX, 0, this.position.x, this.position.y);
+ ctx.lineWidth = 5;
+ ctx.lineCap = "butt";
+ ctx.strokeStyle = "#333";
+ ctx.stroke();
+ ctx.lineCap = "round";
+ };
+ },
+ wireFoot() {
+ //not a mob, just a graphic for level 1
+ const breakingPoint = 1350
+ mobs.spawn(breakingPoint, -100, 0, 2, "transparent");
+ let me = mob[mob.length - 1];
+ //touch nothing
+ me.collisionFilter.category = cat.body;
+ me.collisionFilter.mask = cat.map;
+ me.g = 0.0003; //required for gravity
+ me.restitution = 0;
+ me.stroke = "transparent"
+ // me.inertia = Infinity;
+ me.freeOfWires = false;
+ // me.frictionStatic = 1;
+ // me.friction = 1;
+ me.frictionAir = 0.01;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.isBadTarget = true;
+ me.isUnblockable = true;
+
+ me.do = function () {
+ let wireX = -50 + 16;
+ let wireY = -1000;
+
+ if (this.freeOfWires) {
+ this.gravity();
+ } else {
+ if (m.pos.x > breakingPoint) {
+ this.freeOfWires = true;
+ this.force.x += -0.0006;
+ this.fill = "#111";
+ }
+ //move mob to player
+ m.calcLeg(0, 0);
+ Matter.Body.setPosition(this, {
+ x: m.pos.x + m.flipLegs * m.foot.x - 5,
+ y: m.pos.y + m.foot.y - 1
+ })
+ }
+ //draw wire
+ ctx.beginPath();
+ ctx.moveTo(wireX, wireY);
+ ctx.quadraticCurveTo(wireX, 0, this.position.x, this.position.y);
+ ctx.lineWidth = 5;
+ ctx.lineCap = "butt";
+ ctx.strokeStyle = "#111";
+ ctx.stroke();
+ ctx.lineCap = "round";
+ };
+ },
+ wireFootLeft() {
+ //not a mob, just a graphic for level 1
+ const breakingPoint = 1325
+ mobs.spawn(breakingPoint, -100, 0, 2, "transparent");
+ let me = mob[mob.length - 1];
+ //touch nothing
+ me.collisionFilter.category = cat.body;
+ me.collisionFilter.mask = cat.map;
+ me.g = 0.0003; //required for gravity
+ me.restitution = 0;
+ me.stroke = "transparent"
+ // me.inertia = Infinity;
+ me.freeOfWires = false;
+ // me.frictionStatic = 1;
+ // me.friction = 1;
+ me.frictionAir = 0.01;
+ me.isDropPowerUp = false;
+ me.showHealthBar = false;
+ me.isBadTarget = true;
+ me.isUnblockable = true;
+
+ me.do = function () {
+ let wireX = -50 + 26;
+ let wireY = -1000;
+
+ if (this.freeOfWires) {
+ this.gravity();
+ } else {
+ if (m.pos.x > breakingPoint) {
+ this.freeOfWires = true;
+ this.force.x += -0.0005;
+ this.fill = "#222";
+ }
+ //move mob to player
+ m.calcLeg(Math.PI, -3);
+ Matter.Body.setPosition(this, {
+ x: m.pos.x + m.flipLegs * m.foot.x - 5,
+ y: m.pos.y + m.foot.y - 1
+ })
+ }
+ //draw wire
+ ctx.beginPath();
+ ctx.moveTo(wireX, wireY);
+ ctx.quadraticCurveTo(wireX, 0, this.position.x, this.position.y);
+ ctx.lineWidth = 5;
+ ctx.strokeStyle = "#222";
+ ctx.lineCap = "butt";
+ ctx.stroke();
+ ctx.lineCap = "round";
+ };
+ },
+ boost(x, y, height = 1000) {
+ spawn.mapVertex(x + 50, y + 35, "120 40 -120 40 -50 -40 50 -40");
+ level.addQueryRegion(x, y - 20, 100, 20, "boost", [
+ [player], body, mob, powerUp, bullet
+ ], -1.21 * Math.sqrt(Math.abs(height)));
+ },
+ blockDoor(x, y, blockSize = 60) {
+ spawn.mapRect(x, y - 290, 40, 60); // door lip
+ spawn.mapRect(x, y, 40, 50); // door lip
+ for (let i = 0; i < 4; ++i) {
+ spawn.bodyRect(x + 5, y - 260 + i * blockSize + i * 3, 30, blockSize);
+ }
+ },
+ debris(x, y, width, number = Math.floor(2 + Math.random() * 9)) {
+ for (let i = 0; i < number; ++i) {
+ if (Math.random() < 0.15) {
+ powerUps.chooseRandomPowerUp(x + Math.random() * width, y);
+ } else {
+ const size = 18 + Math.random() * 25;
+ spawn.bodyRect(x + Math.random() * width, y, size * (0.6 + Math.random()), size * (0.6 + Math.random()), 1);
+ // body[body.length] = Bodies.rectangle(x + Math.random() * width, y, size * (0.6 + Math.random()), size * (0.6 + Math.random()));
+ }
+ }
+ },
+ // bodyRect(x, y, width, height, chance = 1, properties = { friction: 0.05, frictionAir: 0.001 }) {
+ // if (Math.random() < chance) body[body.length] = Bodies.rectangle(x + width / 2, y + height / 2, width, height, properties);
+ // },
+ // bodyVertex(x, y, vector, properties) { //adds shape to body array
+ // body[body.length] = Matter.Bodies.fromVertices(x, y, Vertices.fromPath(vector), properties);
+ // },
+ bodyRect(x, y, width, height, chance = 1, properties = { friction: 0.05, frictionAir: 0.001 }) { //this is the command that adds blocks to the world in the middle of a level
+ if (Math.random() < chance) {
+ body[body.length] = Bodies.rectangle(x + width / 2, y + height / 2, width, height, properties);
+ const who = body[body.length - 1]
+ who.collisionFilter.category = cat.body;
+ who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
+ Composite.add(engine.world, who); //add to world
+ who.classType = "body"
+ }
+ },
+ bodyVertex(x, y, vector, properties) { //this is the command that adds blocks to the world in the middle of a level
+ body[body.length] = Matter.Bodies.fromVertices(x, y, Vertices.fromPath(vector), properties);
+ const who = body[body.length - 1]
+ who.collisionFilter.category = cat.body;
+ who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
+ Composite.add(engine.world, who); //add to world
+ who.classType = "body"
+ },
+ mapRect(x, y, width, height, properties) { //adds rectangle to map array
+ map[map.length] = Bodies.rectangle(x + width / 2, y + height / 2, width, height, properties);
+ },
+ mapVertex(x, y, vector, properties) { //adds shape to map array
+ map[map.length] = Matter.Bodies.fromVertices(x, y, Vertices.fromPath(vector), properties);
+ },
+ mapRectNow(x, y, width, height, properties, isRedrawMap = true) { //adds rectangle to map array in the middle of a level
+ map[map.length] = Bodies.rectangle(x + width / 2, y + height / 2, width, height, properties);
+ const who = map[map.length - 1]
+ who.collisionFilter.category = cat.map;
+ who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(who, true); //make static
+ Composite.add(engine.world, who); //add to world
+ if (isRedrawMap) simulation.draw.setPaths()
+ },
+ mapVertexNow(x, y, vector, properties, isRedrawMap = true) { //adds shape to map array in the middle of a level
+ map[map.length] = Matter.Bodies.fromVertices(x, y, Vertices.fromPath(vector), properties);
+ const who = map[map.length - 1]
+ who.collisionFilter.category = cat.map;
+ who.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
+ Matter.Body.setStatic(who, true); //make static
+ Composite.add(engine.world, who); //add to world
+ if (isRedrawMap) simulation.draw.setPaths() //this is a bit slow on processing so maybe it's better to run after you spawn several different shapes
+ },
+ //complex map templates
+ spawnBuilding(x, y, w, h, leftDoor, rightDoor, walledSide) {
+ this.mapRect(x, y, w, 25); //roof
+ this.mapRect(x, y + h, w, 35); //ground
+ if (walledSide === "left") {
+ this.mapRect(x, y, 25, h); //wall left
+ } else {
+ this.mapRect(x, y, 25, h - 150); //wall left
+ if (leftDoor) {
+ this.bodyRect(x + 5, y + h - 150, 15, 150, this.propsFriction); //door left
+ }
+ }
+ if (walledSide === "right") {
+ this.mapRect(x - 25 + w, y, 25, h); //wall right
+ } else {
+ this.mapRect(x - 25 + w, y, 25, h - 150); //wall right
+ if (rightDoor) {
+ this.bodyRect(x + w - 20, y + h - 150, 15, 150, this.propsFriction); //door right
+ }
+ }
+ },
+ spawnStairs(x, y, num, w, h, stepRight) {
+ w += 50;
+ if (stepRight) {
+ for (let i = 0; i < num; i++) {
+ this.mapRect(x - (w / num) * (1 + i), y - h + (i * h) / num, w / num + 50, h - (i * h) / num + 50);
+ }
+ } else {
+ for (let i = 0; i < num; i++) {
+ this.mapRect(x + (i * w) / num, y - h + (i * h) / num, w / num + 50, h - (i * h) / num + 50);
+ }
+ }
+ },
+ //pre-made property options*************************************************************************************
+ //*************************************************************************************************************
+ //Object.assign({}, propsHeavy, propsBouncy, propsNoRotation) //will combine properties into a new object
+ propsFriction: {
+ friction: 0.5,
+ frictionAir: 0.02,
+ frictionStatic: 1
+ },
+ propsFrictionMedium: {
+ friction: 0.15,
+ frictionStatic: 1
+ },
+ propsBouncy: {
+ friction: 0,
+ frictionAir: 0,
+ frictionStatic: 0,
+ restitution: 1
+ },
+ propsSlide: {
+ friction: 0.003,
+ frictionStatic: 0.4,
+ restitution: 0,
+ density: 0.002
+ },
+ propsLight: {
+ density: 0.001
+ },
+ propsOverBouncy: {
+ friction: 0,
+ frictionAir: 0,
+ frictionStatic: 0,
+ restitution: 1.05
+ },
+ propsHeavy: {
+ density: 0.01 //default density is 0.001
+ },
+ propsIsNotHoldable: {
+ isNotHoldable: true
+ },
+ propsNoRotation: {
+ inertia: Infinity //prevents rotation
+ },
+ propsHoist: {
+ inertia: Infinity, //prevents rotation
+ frictionAir: 0.001,
+ friction: 0.0001,
+ frictionStatic: 0,
+ restitution: 0,
+ isNotHoldable: true
+ // density: 0.0001
+ },
+ propsDoor: {
+ density: 0.001, //default density is 0.001
+ friction: 0,
+ frictionAir: 0.03,
+ frictionStatic: 0,
+ restitution: 0
+ },
+ sandPaper: {
+ friction: 1,
+ frictionStatic: 1,
+ restitution: 0
+ }
+};
\ No newline at end of file
diff --git a/ngon/js/tech.js b/ngon/js/tech.js
new file mode 100644
index 00000000..ed3614e7
--- /dev/null
+++ b/ngon/js/tech.js
@@ -0,0 +1,11769 @@
+const tech = {
+ totalCount: null,
+ setupAllTech() {
+ tech.damage = 1
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ tech.tech[i].isLost = false
+ tech.tech[i].isBanished = false
+ tech.tech[i].remove();
+ tech.tech[i].count = 0
+ if (tech.tech[i].isJunk) {
+ tech.tech[i].frequency = 0
+ } else if (tech.tech[i].frequencyDefault) {
+ tech.tech[i].frequency = tech.tech[i].frequencyDefault
+ } else {
+ tech.tech[i].frequency = 2
+ }
+ }
+ //remove lore if it's your first time playing since it's confusing
+ //also remove lore if cheating
+ lore.techCount = 0;
+ if (simulation.isCheating || localSettings.runCount < 1) { //simulation.isCommunityMaps ||
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isLore) {
+ tech.tech[i].frequency = 0;
+ tech.tech[i].count = 0;
+ }
+ }
+ }
+ // tech.removeJunkTechFromPool();
+ // tech.removeLoreTechFromPool();
+ // tech.addLoreTechToPool();
+ tech.extraMaxHealth = 0;
+ tech.totalCount = 0;
+ tech.junkCount = 0 //tech.countJunkTech();
+ simulation.updateTechHUD();
+ simulation.updateGunHUD();
+ },
+ removeTech(index = 'random') {
+ if (index === 'random') {
+ const have = [] //find which tech you have
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].count > 0 && !tech.tech[i].isNonRefundable) have.push(i)
+ }
+ if (have.length) {
+ index = have[Math.floor(Math.random() * have.length)]
+ } else {
+ return 0 //if none found don't remove any tech
+ }
+ } else if (isNaN(index)) { //find index by name
+ let found = false;
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (index === tech.tech[i].name) {
+ index = i;
+ found = true;
+ break;
+ }
+ }
+ if (!found) return 0 //if name not found don't remove any tech
+ }
+ if (tech.tech[index].count === 0) return 0
+ const totalRemoved = tech.tech[index].count
+ simulation.makeTextLog(`tech .removeTech("${tech.tech[index].name} ")`, 360)
+ tech.tech[index].remove();
+ tech.tech[index].count = 0;
+ tech.totalCount -= totalRemoved
+ tech.countJunkTech();
+ simulation.updateTechHUD();
+ tech.tech[index].isLost = true
+ simulation.updateTechHUD();
+ return totalRemoved //return the total number of tech removed
+ },
+ // onclick="tech.removeTechPaused(${i}, this)" //add this to tech elements in pause menu
+ // removeTechPaused(index, who) {
+ // tech.tech[index].remove();
+ // tech.tech[index].count = 0;
+ // simulation.updateTechHUD();
+ // who.innerHTML = "removed"
+ // // who.style.display = "none"
+ // },
+ // removeLoreTechFromPool() {
+ // for (let i = tech.tech.length - 1; i > 0; i--) {
+ // if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech.splice(i, 1)
+ // }
+ // },
+ addJunkTechToPool(percent) { //percent is number between 0-1
+ //make an array for possible junk tech to add
+ let options = [];
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].isJunk) options.push(i);
+ }
+ if (options.length) {
+ let countNonJunk = 0 // count total non junk tech
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isJunk) countNonJunk += tech.tech[i].frequency
+ }
+ const num = Math.ceil(percent * countNonJunk) //scale number added
+ for (let i = 0; i < num; i++) tech.tech[options[Math.floor(Math.random() * options.length)]].frequency++ //add random array options to tech pool
+ simulation.makeTextLog(`tech .tech.push(${num.toFixed(0)} JUNK )`)
+ return num
+ } else {
+ return 0
+ }
+ },
+ removeJunkTechFromPool(num = 1) {
+ for (let j = 0; j < num; j++) {
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].isJunk && tech.tech[i].frequency > 0 && tech.tech[i].count < tech.tech[i].maxCount) {
+ tech.tech[i].frequency--
+ break
+ }
+ }
+ }
+ },
+ giveRandomJUNK() {
+ const list = []
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].isJunk) list.push(tech.tech[i].name)
+ }
+ let name = list[Math.floor(Math.random() * list.length)]
+ tech.giveTech(name)
+ simulation.makeTextLog(`tech .giveTech("${name} ")`);
+ },
+
+ giveTech(index = 'random') {
+ if (index === 'random') {
+ let options = [];
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isJunk && !tech.tech[i].isLore && !tech.tech[i].isBadRandomOption) options.push(i);
+ }
+ // give a random tech from the tech I don't have
+ if (options.length > 0) {
+ let newTech = options[Math.floor(Math.random() * options.length)]
+ tech.giveTech(newTech)
+ simulation.makeTextLog(`tech .giveTech("${tech.tech[newTech].name} ") //random tech `);
+ }
+ } else {
+ if (isNaN(index)) { //find index by name
+ let found = false;
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (index === tech.tech[i].name) {
+ index = i;
+ found = true;
+ break;
+ }
+ }
+ if (!found) return //if name not found don't give any tech
+ }
+ if (tech.isMetaAnalysis && tech.tech[index].isJunk) {
+ simulation.makeTextLog(`//tech: meta-analysis replaced junk tech with random tech`);
+ tech.giveTech('random')
+ for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x + 40 * Math.random(), m.pos.y + 40 * Math.random(), "research");
+ return
+ }
+
+ if (tech.tech[index].isLost) tech.tech[index].isLost = false; //give specific tech
+ if (tech.isBanish && tech.tech[index].isBanished) tech.tech[index].isBanished = false //stops the bug where you can't gets stacks of tech you take with decoherence, I think
+ tech.tech[index].effect(); //give specific tech
+ tech.tech[index].count++
+ tech.totalCount++ //used in power up randomization
+ tech.countJunkTech();
+ simulation.updateTechHUD();
+ }
+ },
+ junkCount: 0,
+ countJunkTech() {
+ tech.junkCount = 0
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].count > 0 && tech.tech[i].isJunk) tech.junkCount++
+ }
+ },
+ // setTechoNonRefundable(name) {
+ // for (let i = 0; i < tech.tech.length; i++) {
+ // if (tech.tech.name === name) {
+ // tech.tech[i].isNonRefundable = true;
+ // return
+ // }
+ // }
+ // },
+ setCheating() {
+ if (!simulation.isCheating) {
+ simulation.isCheating = true;
+ level.levelAnnounce();
+ lore.techCount = 0;
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isLore) {
+ tech.tech[i].frequency = 0;
+ tech.tech[i].count = 0;
+ }
+ }
+ console.log('cheating')
+ sound.tone(250)
+ sound.tone(300)
+ sound.tone(375)
+ }
+ },
+ haveGunCheck(name, needActive = true) {
+ // if (
+ // !build.isExperimentSelection &&
+ // b.inventory.length > 2 &&
+ // name !== b.guns[b.activeGun].name &&
+ // Math.random() > 2 - b.inventory.length * 0.5
+ // ) {
+ // return false
+ // }
+ // for (i = 0, len = b.inventory.length; i < len; i++) {
+ // if (b.guns[b.inventory[i]].name === name) return true
+ // }
+ // return false
+ if (build.isExperimentSelection || !needActive) {
+ for (i = 0, len = b.inventory.length; i < len; i++) {
+ if (b.guns[b.inventory[i]].name === name) return true
+ }
+ return false
+ } else { //must be holding gun, this is the standard while playing
+ return b.inventory.length > 0 && b.guns[b.activeGun].name === name
+ }
+ },
+ hasExplosiveDamageCheck() {
+ return tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isBoomBotUpgrade || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb)
+ },
+ damage: 1, //used for tech changes to player damage that don't have complex conditions
+ damageFromTech() {
+ let dmg = tech.damage //m.fieldDamage
+ // if (tech.isDivisor) {
+ // for (let i = 0; i < b.inventory.length; i++) {
+ // if (b.guns[b.inventory[i]].ammo % 3 === 0) {
+ // dmg *= 1.44
+ // break
+ // }
+ // }
+ // }
+ if (tech.isDivisor && b.activeGun && b.guns[b.activeGun].ammo % 3 === 0) dmg *= 1.77
+ if (tech.isNoGroundDamage) dmg *= m.onGround ? 0.78 : 1.88
+ if (tech.isDilate) dmg *= 1.5 + 0.6 * Math.sin(m.cycle * 0.0075)
+ if (tech.isGunChoice && tech.buffedGun === b.inventoryGun) dmg *= 1 + 0.31 * b.inventory.length
+ if (powerUps.boost.endCycle > m.cycle) dmg *= 1 + powerUps.boost.damage
+ if (m.coupling && (m.fieldMode === 0 || m.fieldMode === 5)) dmg *= 1 + 0.015 * m.coupling
+ if (m.isSneakAttack && m.sneakAttackCycle + Math.min(120, 0.5 * (m.cycle - m.enterCloakCycle)) > m.cycle) dmg *= 4.33 * (1 + 0.033 * m.coupling)
+ if (tech.deathSkipTime) dmg *= 1 + 0.6 * tech.deathSkipTime
+ if (tech.isTechDebt) dmg *= tech.totalCount > 20 ? Math.pow(0.85, tech.totalCount - 20) : 4 - 0.15 * tech.totalCount // if (tech.isTechDebt) dmg *= Math.min(Math.pow(0.85, tech.totalCount - 20), 4 - 0.15 * tech.totalCount)
+ if (tech.isFlipFlopDamage && tech.isFlipFlopOn) dmg *= 1.555
+ if (tech.isAnthropicDamage && tech.isDeathAvoidedThisLevel) dmg *= 2.3703599
+ if (tech.isDupDamage) dmg *= 1 + Math.min(1, tech.duplicationChance())
+ if (tech.isDamageForGuns) dmg *= 1 + 0.22 * Math.max(0, b.inventory.length - 1)
+ if (tech.isOneGun && b.inventory.length < 2) dmg *= 1.25
+ if (tech.isAcidDmg && m.health > 1) dmg *= 1.35;
+ if (tech.isRerollDamage) dmg *= 1 + Math.max(0, 0.03 * powerUps.research.count)
+ if (tech.isBotDamage) dmg *= 1 + 0.06 * b.totalBots()
+ if (tech.restDamage > 1 && player.speed < 1) dmg *= tech.restDamage
+ if (tech.isLowEnergyDamage) dmg *= 1 + 0.7 * Math.max(0, 1 - m.energy)
+ if (tech.energyDamage) dmg *= 1 + m.energy * 0.22 * tech.energyDamage;
+ if (tech.isDamageFromBulletCount) dmg *= 1 + bullet.length * 0.007
+ if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 2
+ if (tech.isSpeedDamage) dmg *= 1 + Math.min(0.66, player.speed * 0.0165)
+ if (tech.isDamageAfterKillNoRegen && m.lastKillCycle + 300 > m.cycle) dmg *= 1.83
+ if (tech.isAxion && tech.isHarmMACHO) dmg *= 2 - m.defense()
+ if (tech.isHarmDamage && m.lastHarmCycle + 480 > m.cycle) dmg *= 3;
+ if (tech.lastHitDamage && m.lastHit) dmg *= 1 + tech.lastHitDamage * m.lastHit * (2 - m.defense()) // if (!simulation.paused) m.lastHit = 0
+ if (tech.isLowHealthDmg) dmg *= 1 + 0.7 * Math.max(0, 1 - (tech.isEnergyHealth ? m.energy : m.health))
+ return dmg
+ },
+ duplicationChance() {
+ return Math.min(1, Math.max(0, (tech.isPowerUpsVanish ? 0.13 : 0) + (tech.isStimulatedEmission ? 0.17 : 0) + tech.duplication + tech.duplicateChance + 0.05 * tech.isExtraGunField + m.duplicateChance + tech.fieldDuplicate + 0.08 * tech.isDuplicateMobs + tech.cloakDuplication + (tech.isAnthropicTech && tech.isDeathAvoidedThisLevel ? 0.5 : 0)))
+ },
+ isScaleMobsWithDuplication: false,
+ maxDuplicationEvent() {
+ if (tech.is100Duplicate && tech.duplicationChance() > 0.99) {
+ tech.is100Duplicate = false
+ const range = 1300
+ tech.isScaleMobsWithDuplication = true
+ for (let i = 0, len = 9; i < len; i++) {
+ const angle = 2 * Math.PI * i / len
+ spawn.randomLevelBoss(m.pos.x + range * Math.cos(angle), m.pos.y + range * Math.sin(angle), spawn.nonCollideBossList);
+ }
+ spawn.historyBoss(0, 0)
+ spawn.pulsarBoss(level.exit.x, level.exit.y, 70, true)
+ spawn.blockBoss(level.enter.x, level.enter.y)
+ tech.isScaleMobsWithDuplication = false
+ }
+ },
+ setTechFrequency(name, frequency) {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].name === name) tech.tech[i].frequency = frequency
+ }
+ },
+ setBotTechFrequency(f = 0) {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isBotTech) {
+ switch (tech.tech[i].name) {
+ case "dynamo-bot":
+ tech.tech[i].frequency = f
+ break;
+ case "orbital-bot":
+ tech.tech[i].frequency = f
+ break;
+ case "laser-bot":
+ tech.tech[i].frequency = f
+ break;
+ case "boom-bot":
+ tech.tech[i].frequency = f
+ break;
+ case "foam-bot":
+ tech.tech[i].frequency = f
+ break;
+ case "nail-bot":
+ tech.tech[i].frequency = f
+ break;
+ }
+ }
+ }
+ },
+ tech: [{
+ name: "tungsten carbide",
+ description: "+222 maximum health lose health after hard landings ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isSkin: true,
+ allowed() {
+ return !m.isAltSkin
+ },
+ requires: "not skin",
+ effect() {
+ tech.hardLanding = 70
+ tech.isFallingDamage = true;
+ m.setMaxHealth();
+ m.addHealth(2.22 / simulation.healScale)
+ m.skin.tungsten()
+ },
+ remove() {
+ tech.hardLanding = 130
+ tech.isFallingDamage = false;
+ m.setMaxHealth();
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "nitinol",
+ description: "+33% movement and jumping +22% defense ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isSkin: true,
+ allowed() {
+ return !m.isAltSkin
+ },
+ requires: "not skinned",
+ effect() {
+ m.skin.mech();
+ tech.hardLanding = 110
+ tech.squirrelFx += 0.4;
+ tech.squirrelJump += 0.16;
+ m.setMovement()
+ },
+ remove() {
+ tech.hardLanding = 130
+ tech.squirrelFx = 1;
+ tech.squirrelJump = 1;
+ m.setMovement()
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "aperture",
+ description: "every 6 seconds your damage cycles between -10% and +110% damage ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isSkin: true,
+ allowed() {
+ return !m.isAltSkin
+ },
+ requires: "not skinned",
+ effect() {
+ tech.isDilate = true
+ m.skin.dilate()
+ },
+ remove() {
+ tech.isDilate = false
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "diaphragm",
+ description: "every 6 seconds your defense cycles between +8% and +80% defense ",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isSkin: true,
+ allowed() {
+ return tech.isDilate
+ },
+ requires: "aperture",
+ effect() {
+ tech.isDiaphragm = true
+ m.resetSkin();
+ m.skin.dilate2()
+ },
+ remove() {
+ tech.isDiaphragm = false
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "mass-energy equivalence",
+ // description: "energy protects you instead of health √ of defense reduction reduces max energy ",
+ description: "energy protects you instead of health exponentially reduced defense (~ x^0.19) ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isSkin: true,
+ allowed() {
+ return !m.isAltSkin && !tech.isPiezo && !tech.isRewindAvoidDeath && !tech.isAnnihilation //&& !tech.isAmmoFromHealth && !tech.isRewindGun
+ },
+ requires: "not piezoelectricity, CPT, annihilation",
+ effect() {
+ m.health = 0
+ document.getElementById("health").style.display = "none"
+ document.getElementById("health-bg").style.display = "none"
+ document.getElementById("dmg").style.backgroundColor = "#0cf";
+ tech.isEnergyHealth = true;
+ simulation.mobDmgColor = "rgba(0, 255, 255,0.6)" //"#0cf"
+ m.displayHealth();
+ m.lastCalculatedDefense = 0 //this triggers a redraw of the defense bar
+ m.skin.energy();
+ },
+ remove() {
+ if (tech.isEnergyHealth) {
+ tech.isEnergyHealth = false;
+ document.getElementById("health").style.display = "inline"
+ document.getElementById("health-bg").style.display = "inline"
+ document.getElementById("dmg").style.backgroundColor = "#f67";
+ m.health = Math.max(Math.min(m.maxHealth, m.energy), 0.1);
+ simulation.mobDmgColor = "rgba(255,0,0,0.7)"
+ m.displayHealth();
+ m.lastCalculatedDefense = 0 //this triggers a redraw of the defense bar
+ m.resetSkin();
+ }
+ tech.isEnergyHealth = false;
+ }
+ },
+ {
+ name: "1st ionization energy",
+ link: `1st ionization energy `,
+ // description: `after you collect ${powerUps.orb.heal()}+${0.1 * tech.largerHeals} maximum energy `,
+ // descriptionFunction: `convert current and future ${powerUps.orb.heal()} into
give +${10 * tech.largerHeals} maximum energy `,
+ descriptionFunction() {
+ return `convert current and future
into
give +${8 * tech.largerHeals * (tech.isHalfHeals ? 0.5 : 1)} maximum energy `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 4,
+ frequencyDefault: 4,
+ allowed() {
+ return tech.isEnergyHealth
+ },
+ requires: "mass-energy equivalence",
+ effect() {
+ powerUps.healGiveMaxEnergy = true; //tech.healMaxEnergyBonus given from heal power up
+ powerUps.heal.color = "#ff0" //"#0ae"
+ for (let i = 0; i < powerUp.length; i++) { //find active heal power ups and adjust color live
+ if (powerUp[i].name === "heal") powerUp[i].color = powerUps.heal.color
+ }
+ },
+ remove() {
+ powerUps.healGiveMaxEnergy = false;
+ // tech.healMaxEnergyBonus = 0
+ powerUps.heal.color = "#0eb"
+ for (let i = 0; i < powerUp.length; i++) { //find active heal power ups and adjust color live
+ if (powerUp[i].name === "heal") powerUp[i].color = powerUps.heal.color
+ }
+ }
+ },
+ {
+ name: "CPT symmetry",
+ // description: "charge , parity , and time invert to undo defense rewind (1.5—5) seconds for (66—220) energy ",
+ // description: "after losing health , if you have full energy rewind time for 44 energy per second",
+ descriptionFunction() {
+ return `after losing health , if you have ${(100 * Math.min(100, m.maxEnergy)).toFixed(0)} energy rewind time for 20 energy per second`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isSkin: true,
+ allowed() {
+ return !m.isAltSkin && m.fieldUpgrades[m.fieldMode].name !== "standing wave" && !tech.isRewindField && !tech.isEnergyHealth
+ },
+ requires: "not skinned, standing wave, max energy reduction, retrocausality, mass-energy",
+ effect() {
+ tech.isRewindAvoidDeath = true;
+ m.skin.CPT()
+ },
+ remove() {
+ tech.isRewindAvoidDeath = false;
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "causality bots",
+ link: `causality bots `,
+ description: "when you rewind build scrap bots that protect you for about 9 seconds",
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBotTech: true,
+ allowed() {
+ return tech.isRewindAvoidDeath || tech.isRewindField
+ },
+ requires: "CPT, retrocausality",
+ effect() {
+ tech.isRewindBot++;
+ },
+ remove() {
+ tech.isRewindBot = 0;
+ }
+ },
+ {
+ name: "causality bombs",
+ link: `causality bombs `,
+ description: "when you rewind drop several grenades ", // become invulnerable until they explode
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isRewindAvoidDeath || tech.isRewindField
+ },
+ requires: "CPT, retrocausality",
+ effect() {
+ tech.isRewindGrenade = true;
+ },
+ remove() {
+ tech.isRewindGrenade = false;
+ }
+ },
+ {
+ name: "ternary", //"divisor",
+ descriptionFunction() {
+ return `+77% damage while your current gun has ammo divisible by 3 `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ // divisible: 3, // + Math.floor(6 * Math.random()),
+ effect() {
+ tech.isDivisor = true;
+ },
+ remove() {
+ tech.isDivisor = false;
+ }
+ },
+ {
+ name: "ordnance",
+ description: "double the frequency of finding gun tech spawn a gun and +7% JUNK to tech pool",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isGunTech) tech.tech[i].frequency *= 2
+ }
+ this.refundAmount += tech.addJunkTechToPool(0.07)
+ },
+ refundAmount: 0,
+ remove() {
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "ad hoc",
+ descriptionFunction() {
+ return `spawn a ${powerUps.orb.heal()}, ${powerUps.orb.research(1)}, ${powerUps.orb.ammo(1)}, field , gun , or tech for each of your guns `
+ },
+ maxCount: 1, //random power up
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ allowed() {
+ return b.inventory.length > 1
+ },
+ requires: "at least 2 guns",
+ effect() {
+ for (let i = 0; i < b.inventory.length; i++) {
+ if (Math.random() < 1 / 6) {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun");
+ } else if (Math.random() < 1 / 5) {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "tech");
+ } else if (Math.random() < 1 / 4) {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "field");
+ } else if (Math.random() < 1 / 3) {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "heal");
+ } else if (Math.random() < 1 / 2) {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "ammo");
+ } else {
+ powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "research");
+ }
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "applied science",
+ description: `get a random gun tech for each of your guns `, //spawn ${powerUps.orb.research(1)} and
+ maxCount: 9,
+ count: 0,
+ isNonRefundable: true,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return b.inventory.length > 1
+ },
+ requires: "at least 2 guns",
+ effect() {
+ for (let i = b.inventory.length - 1; i > -1; i--) { //backwards because some tech can remove or add guns
+ const gunTechPool = [] //find gun tech for this gun
+ for (let j = 0, len = tech.tech.length; j < len; j++) {
+ // console.log(j, tech.tech[j].isGunTech, tech.tech[j].allowed(), !tech.tech[j].isJunk, !tech.tech[j].isBadRandomOption, tech.tech[j].count < tech.tech[j].maxCount)
+ const originalActiveGunIndex = b.activeGun //set current gun to active so allowed works
+ b.activeGun = b.inventory[i] //to make the .allowed work for guns that aren't active
+ if (tech.tech[j].isGunTech && tech.tech[j].allowed() && !tech.tech[j].isJunk && !tech.tech[j].isBadRandomOption && tech.tech[j].count < tech.tech[j].maxCount) {
+ const regex = tech.tech[j].requires.search(b.guns[b.inventory[i]].name) //get string index of gun name
+ const not = tech.tech[j].requires.search(' not ') //get string index of ' not '
+ if (regex !== -1 && (not === -1 || not > regex)) gunTechPool.push(j) //look for the gun name in the requirements, but the gun name needs to show up before the word ' not '
+ }
+ b.activeGun = originalActiveGunIndex
+ if (!b.guns[b.activeGun].have) {
+ if (b.inventory.length === 0) {
+ b.activeGun = null
+ } else {
+ b.activeGun = b.inventory[0]
+ }
+ b.inventoryGun = 0;
+ }
+ }
+ if (gunTechPool.length) {
+ const index = Math.floor(Math.random() * gunTechPool.length)
+ tech.giveTech(gunTechPool[index]) // choose from the gun pool
+ tech.tech[gunTechPool[index]].isFromAppliedScience = true //makes it not remove properly under paradigm shift
+ simulation.makeTextLog(`tech .giveTech("${tech.tech[gunTechPool[index]].name} ")`, 360)
+ }
+ }
+ simulation.boldActiveGunHUD();
+ },
+ remove() { }
+ },
+ {
+ name: "arsenal",
+ descriptionFunction() {
+ return `+22% damage per unequipped gun (${(22 * Math.max(0, b.inventory.length - 1)).toFixed(0)}%) `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => b.inventory.length > 1,
+ requires: "at least 2 guns",
+ effect() {
+ tech.isDamageForGuns = true;
+ },
+ remove() {
+ tech.isDamageForGuns = false;
+ }
+ },
+ {
+ name: "active cooling",
+ descriptionFunction() {
+ return `+28% fire rate per unequipped gun (${(28 * Math.max(0, b.inventory.length - 1)).toFixed(0)}%) `
+ }, // but not including your equipped gun ` },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => b.inventory.length > 1,
+ requires: "at least 2 guns",
+ effect() {
+ tech.isFireRateForGuns = true;
+ b.setFireCD();
+ },
+ remove() {
+ tech.isFireRateForGuns = false;
+ b.setFireCD();
+ }
+ },
+ {
+ name: "pigeonhole principle",
+ descriptionFunction() {
+ let info = ""
+ if (this.count > 0 && Number.isInteger(tech.buffedGun) && b.inventory.length) {
+ let gun = b.guns[b.inventory[tech.buffedGun]].name
+ info = ` this level: +${(31 * Math.max(0, b.inventory.length)).toFixed(0)}% damage for ${gun} `
+ }
+ return `
+ a new gun is chosen to be improved each level
+ +31% damage per gun for the chosen gun ${info}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return b.inventory.length > 1
+ },
+ requires: "at least 2 guns",
+ effect() {
+ tech.isGunChoice = true
+ //switches gun on new level
+ //generalist uses the same chosen gun so they match
+ },
+ remove() {
+ tech.isGunChoice = false;
+ }
+ },
+ {
+ name: "generalist",
+ description: "spawn 7 guns , but you can't switch guns your equipped gun cycles after each level",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return b.inventory.length < b.guns.length - 5 && b.inventory.length > 1
+ },
+ requires: "at least 2 guns, at least 5 unclaimed guns",
+ effect() {
+ tech.isGunCycle = true;
+ for (let i = 0; i < 7; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun");
+ },
+ remove() {
+ if (!this.count) tech.isGunCycle = false; // only set to false if you don't have this tech
+ // if (tech.isGunCycle) {
+ // for (let i = 0; i < 8; i++) {
+ // if (b.inventory.length) b.removeGun(b.guns[b.inventory[b.inventory.length - 1]].name) //remove your last gun
+ // }
+ // tech.isGunCycle = false;
+ // }
+ }
+ },
+ {
+ name: "supply chain",
+ descriptionFunction() {
+ return `double your current ammo +4% JUNK to tech pool`
+ },
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0; i < b.guns.length; i++) {
+ if (b.guns[i].have) b.guns[i].ammo = Math.floor(2 * b.guns[i].ammo)
+ }
+ simulation.makeGunHUD();
+ this.refundAmount += tech.addJunkTechToPool(0.04)
+ },
+ refundAmount: 0,
+ remove() {
+ for (let j = 0; j < this.count; j++) {
+ for (let i = 0; i < b.guns.length; i++) {
+ if (b.guns[i].have) b.guns[i].ammo = Math.floor(0.5 * b.guns[i].ammo)
+ }
+ }
+ simulation.makeGunHUD();
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "logistics",
+ description: `${powerUps.orb.ammo()} give 80% more ammo , but it's only added to your current gun `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isEnergyNoAmmo
+ },
+ requires: "not non-renewables",
+ effect() {
+ tech.isAmmoForGun = true;
+ },
+ remove() {
+ tech.isAmmoForGun = false;
+ }
+ },
+ {
+ name: "cache",
+ link: `cache `,
+ description: `${powerUps.orb.ammo()} give 1500% more ammo , but you can't store any more ammo than that`,
+ // ammo powerups always max out your gun,
+ // but the maximum ammo ti limited
+ // description: `${powerUps.orb.ammo()} give 13x more ammo , but you can't store any more ammo than that`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isEnergyNoAmmo
+ },
+ requires: "not non-renewables",
+ effect() {
+ tech.ammoCap = 15;
+ powerUps.ammo.effect()
+ },
+ remove() {
+ tech.ammoCap = 0;
+ }
+ },
+ {
+ name: "catabolism",
+ descriptionFunction() {
+ return `if you fire while out of ammo spawn ${powerUps.orb.ammo(4)} and ${tech.isEnergyHealth ? "–4 maximum energy " : "–2 maximum health "}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isEnergyNoAmmo
+ },
+ requires: "not non-renewables",
+ effect() {
+ tech.isAmmoFromHealth = true;
+ },
+ remove() {
+ tech.isAmmoFromHealth = false;
+ }
+ },
+ {
+ name: "non-renewables",
+ description: `+78% damage ${powerUps.orb.ammo()} can't spawn `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isAmmoFromHealth && !tech.isBoostReplaceAmmo
+ },
+ requires: "not catabolism, quasiparticles",
+ damage: 1.78,
+ effect() {
+ tech.damage *= this.damage
+ tech.isEnergyNoAmmo = true;
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isEnergyNoAmmo = false;
+ }
+ },
+ {
+ name: "desublimated ammunition",
+ link: `desublimated ammunition `,
+ description: `if crouching alternating shots use no ammo `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.crouchAmmoCount = true
+ },
+ remove() {
+ tech.crouchAmmoCount = false;
+ }
+ },
+ {
+ name: "gun turret",
+ description: "if crouching +66% defense ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isTurret = true
+ },
+ remove() {
+ tech.isTurret = false;
+ }
+ },
+ {
+ name: "dead reckoning",
+ description: "if your speed is 0+50% damage ",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.restDamage += 0.5
+ },
+ remove() {
+ tech.restDamage = 1;
+ }
+ },
+ {
+ name: "kinetic bombardment",
+ description: "far away mobs take more damage up to +33% damage at 3000 displacement",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isFarAwayDmg = true; //used in mob.damage()
+ },
+ remove() {
+ tech.isFarAwayDmg = false;
+ }
+ },
+ {
+ name: "Higgs mechanism",
+ description: "+45% fire rate while firing your position is fixed",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !m.isShipMode && !tech.isAlwaysFire, !tech.isGrapple
+ },
+ requires: "not ship mode, automatic, grappling hook",
+ effect() {
+ tech.isFireMoveLock = true;
+ b.setFireCD();
+ b.setFireMethod();
+ },
+ remove() {
+ if (tech.isFireMoveLock) {
+ tech.isFireMoveLock = false
+ b.setFireCD();
+ b.setFireMethod();
+ }
+ }
+ },
+ {
+ name: "integrated armament",
+ link: `integrated armament `,
+ description: `+25% damage , but new guns replace your current gun and convert gun tech `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return b.inventory.length === 1
+ },
+ requires: "only 1 gun",
+ effect() {
+ tech.isOneGun = true;
+ },
+ remove() {
+ tech.isOneGun = false;
+ }
+ },
+ {
+ name: "mechatronics",
+ descriptionFunction() {
+ let damageTotal = 1
+ for (let i = 0; i < this.damageSoFar.length; i++) damageTotal *= this.damageSoFar[i]
+ let currentDamage = ""
+ if (this.count) currentDamage = `(+${(100 * (damageTotal - 1)).toFixed(0)}%) `
+ return `gain between +7% and +13% damage ` + currentDamage
+ },
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() { return true },
+ requires: "",
+ damage: 1.1,
+ damageSoFar: [], //tracks the random damage upgrades so it can be removed and in descriptionFunction
+ effect() {
+ const damage = (Math.floor((Math.random() * 0.07 + 0.07 + 1) * 100)) / 100
+ tech.damage *= damage
+ this.damageSoFar.push(damage)
+ },
+ remove() {
+ for (let i = 0; i < this.damageSoFar.length; i++) tech.damage /= this.damageSoFar[i]
+ this.damageSoFar.length = 0
+ }
+ },
+ // {
+ // name: "coyote",
+ // description: "",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 1,
+ // frequencyDefault: 1,
+ // allowed() { return true },
+ // requires: "",
+ // effect() { // good with melee builds, content skipping builds
+ // tech.coyoteTime = 120
+ // // simulation.gravity = function() {
+ // // function addGravity(bodies, magnitude) {
+ // // for (var i = 0; i < bodies.length; i++) {
+ // // bodies[i].force.y += bodies[i].mass * magnitude;
+ // // }
+ // // }
+ // // if (!m.isBodiesAsleep) {
+ // // addGravity(powerUp, simulation.g);
+ // // addGravity(body, simulation.g);
+ // // }
+ // // player.force.y += player.mass * simulation.g
+ // // }
+ // },
+ // remove() {
+ // tech.coyoteTime = 5
+ // }
+ // },
+ {
+ name: "Newtons 1st law",
+ description: "defense is proportional to your speed up to +66% defense at 40 speed ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isSpeedHarm = true //max at speed = 40
+ },
+ remove() {
+ tech.isSpeedHarm = false
+ }
+ },
+ {
+ name: "Newtons 2nd law",
+ description: "damage is proportional to your speed up to +66% damage at 40 speed ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isSpeedDamage = true //max at speed = 40
+ },
+ remove() {
+ tech.isSpeedDamage = false
+ }
+ },
+ {
+ name: "microstates",
+ link: `microstates `,
+ description: "for each active bullet or bot +0.7% damage ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isDamageFromBulletCount = true
+ },
+ remove() {
+ tech.isDamageFromBulletCount = false
+ }
+ },
+ {
+ name: "regression",
+ description: "bullet collisions increase vulnerability todamage by +5% for mobs (+0.25% for bosses) ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isLessDamageReduction = true
+ },
+ remove() {
+ tech.isLessDamageReduction = false
+ }
+ },
+ {
+ name: "simulated annealing",
+ description: "+20% damage –20% fire rate ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ damage: 1.2,
+ effect() {
+ tech.damage *= this.damage
+ tech.slowFire = 1.2
+ b.setFireCD();
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.slowFire = 1;
+ b.setFireCD();
+ }
+ },
+ {
+ name: "heuristics",
+ description: "+22% fire rate spawn a gun ",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.fireRate *= 0.78
+ b.setFireCD();
+ powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ },
+ remove() {
+ tech.fireRate = 1;
+ b.setFireCD();
+ }
+ },
+ {
+ name: "anti-shear topology",
+ link: `anti-shear topology `,
+ description: "your bullets last +30% longer ", //drone spore worm flea missile foam wave neutron ice ",
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.bulletsLastLonger += 0.3
+ },
+ remove() {
+ tech.bulletsLastLonger = 1;
+ }
+ },
+ {
+ name: "fracture analysis",
+ description: "if a mob is stunned it takes+400% damage from bullet impacts",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isStunField || tech.oneSuperBall || tech.isCloakStun || tech.isOrbitBotUpgrade || tech.isStun
+ },
+ requires: "a stun effect",
+ effect() {
+ tech.isCrit = true;
+ },
+ remove() {
+ tech.isCrit = false;
+ }
+ },
+ {
+ name: "shear stress",
+ description: "after mobs die they fire a nail at nearby mobs",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath
+ },
+ requires: "no other mob death tech",
+ effect() {
+ tech.nailsDeathMob++
+ },
+ remove() {
+ tech.nailsDeathMob = 0;
+ }
+ },
+ {
+ name: "thermal runaway",
+ description: "after mobs die they explode ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.sporesOnDeath && !tech.nailsDeathMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath
+ },
+ requires: "no other mob death tech",
+ effect() {
+ tech.isExplodeMob = true;
+ },
+ remove() {
+ tech.isExplodeMob = false;
+ }
+ },
+ {
+ name: "zoospore vector",
+ link: `zoospore vector `,
+ descriptionFunction() {
+ return `after mobs die there is a +10% chance they grow ${b.guns[6].nameString('s')}`
+ },
+ // description: "after mobs die they have a +10% chance to grow spores ",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.nailsDeathMob && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath
+ },
+ requires: "no other mob death tech",
+ effect() {
+ tech.sporesOnDeath += 0.1;
+ // if (tech.isSporeWorm) {
+ // for (let i = 0; i < 4; i++) b.worm(m.pos)
+ // } else {
+ // for (let i = 0; i < 8; i++) b.spore(m.pos)
+ // }
+ },
+ remove() {
+ tech.sporesOnDeath = 0;
+ }
+ },
+ {
+ name: "propagator",
+ description: "after mobs die advance time 0.5 seconds+60% damage ",
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.deathSkipTime++
+ },
+ remove() {
+ tech.deathSkipTime = 0
+ }
+ },
+ {
+ name: "collider",
+ descriptionFunction() {
+ return `after mobs die there is a +50% chance to collide power ups to form different power ups `
+ // return `after mobs die there is a +33% chance to convert ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, ${powerUps.orb.research(1)}, tech , field , gun into other types`
+ },
+
+ maxCount: 2,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.collidePowerUps += 0.5
+ },
+ remove() {
+ tech.collidePowerUps = 0
+ }
+ },
+ {
+ name: "bubble fusion",
+ descriptionFunction() {
+ return `after destroying a mob's natural shield spawn 1-2 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isShieldAmmo = true;
+ },
+ remove() {
+ tech.isShieldAmmo = false;
+ }
+ },
+ {
+ name: "reaction inhibitor",
+ description: "-11% maximum mob health ", //health
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true //tech.nailsDeathMob || tech.sporesOnDeath || tech.isExplodeMob || tech.botSpawner || tech.isMobBlockFling || tech.iceIXOnDeath
+ },
+ requires: "", //"any mob death tech",
+ effect() {
+ tech.mobSpawnWithHealth++
+ mobs.setMobSpawnHealth()
+ //set all mobs at full health to 0.85
+ for (let i = 0; i < mob.length; i++) {
+ if (mob.health > mobs.mobSpawnWithHealth) mob.health = mobs.mobSpawnWithHealth
+ }
+ },
+ remove() {
+ tech.mobSpawnWithHealth = 0
+ mobs.setMobSpawnHealth()
+ }
+ },
+ {
+ name: "scrap bots",
+ link: `scrap bots `,
+ description: "after mobs die you have a +33% chance to build scrap bots that operate for 13 seconds",
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBotTech: true,
+ allowed() {
+ return !tech.sporesOnDeath && !tech.nailsDeathMob && !tech.isExplodeMob && !tech.isMobBlockFling && !tech.iceIXOnDeath
+ },
+ requires: "no other mob death tech",
+ effect() {
+ tech.botSpawner += 0.33;
+ },
+ remove() {
+ tech.botSpawner = 0;
+ }
+ },
+ {
+ name: "scrap refit",
+ link: `scrap refit `,
+ description: "after mobs die reset scrap bots to 13 seconds of operation",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.botSpawner
+ },
+ requires: "scrap bots",
+ effect() {
+ tech.isBotSpawnerReset = true;
+ },
+ remove() {
+ tech.isBotSpawnerReset = false;
+ }
+ },
+ {
+ name: "nail-bot",
+ link: `nail-bot `,
+ description: "a bot fires nails at mobs in line of sight",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.nailBotCount++;
+ b.nailBot();
+ },
+ remove() {
+ if (this.count) {
+ tech.nailBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ }
+ },
+ {
+ name: "nail-bot upgrade",
+ link: `nail-bot upgrade `,
+ description: "convert your bots to nail-bots +500% fire rate and +40% nail velocity ",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.nailBotCount > 1 && !b.hasBotUpgrade()
+ },
+ requires: "2 or more nail bots and no other bot upgrade",
+ effect() {
+ tech.isNailBotUpgrade = true
+ b.convertBotsTo("nail-bot")
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'nail') bullet[i].isUpgraded = true
+ }
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("nail-bot", 5)
+ },
+ remove() {
+ if (this.count) {
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'nail') bullet[i].isUpgraded = false
+ }
+ tech.setBotTechFrequency(1)
+ }
+ tech.isNailBotUpgrade = false
+ }
+ },
+ {
+ name: "foam-bot",
+ link: `foam-bot `,
+ description: "a bot fires foam at nearby mobs",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.foamBotCount++;
+ b.foamBot();
+ },
+ remove() {
+ if (this.count) {
+ tech.foamBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ }
+ },
+ {
+ name: "foam-bot upgrade",
+ link: `foam-bot upgrade `,
+ description: "convert your bots to foam-bots +300% foam size and fire rate ",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.foamBotCount > 1 && !b.hasBotUpgrade()
+ },
+ requires: "2 or more foam bots and no other bot upgrade",
+ effect() {
+ tech.isFoamBotUpgrade = true
+ b.convertBotsTo("foam-bot")
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'foam') bullet[i].isUpgraded = true
+ }
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("foam-bot", 5)
+ },
+ remove() {
+ if (this.count) {
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'foam') bullet[i].isUpgraded = false
+ }
+ tech.setBotTechFrequency(1)
+ }
+ tech.isFoamBotUpgrade = false
+ }
+ },
+ {
+ name: "sound-bot",
+ link: `sound-bot `,
+ description: "a bot emits expanding arcs aimed towards nearby mobs",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ tech.soundBotCount++;
+ b.soundBot();
+ },
+ remove() {
+ if (this.count) {
+ tech.soundBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ }
+ },
+ {
+ name: "sound-bot upgrade",
+ link: `sound-bot upgrade `,
+ description: "convert your bots to sound-bots +150% wave fire rate and +150% damage ",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.soundBotCount > 1 && !b.hasBotUpgrade()
+ },
+ requires: "2 or more sound bots and no other bot upgrade",
+ effect() {
+ tech.isSoundBotUpgrade = true
+ b.convertBotsTo("sound-bot")
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'sound') bullet[i].isUpgraded = true
+ }
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("sound-bot", 5)
+ },
+ remove() {
+ if (this.count) {
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'sound') bullet[i].isUpgraded = false
+ }
+ tech.setBotTechFrequency(1)
+ }
+ tech.isSoundBotUpgrade = false
+ }
+ },
+ {
+ name: "boom-bot",
+ link: `boom-bot `,
+ description: "a bot defends the space around you ignites an explosion after hitting a mob",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.boomBotCount++;
+ b.boomBot();
+ },
+ remove() {
+ if (this.count) {
+ tech.boomBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ }
+ },
+ {
+ name: "boom-bot upgrade",
+ link: `boom-bot upgrade `,
+ description: "convert your bots to boom-bots +300% explosion damage and size",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.boomBotCount > 1 && !b.hasBotUpgrade()
+ },
+ requires: "2 or more boom bots and no other bot upgrade",
+ effect() {
+ tech.isBoomBotUpgrade = true
+ b.convertBotsTo("boom-bot")
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'boom') bullet[i].isUpgraded = true
+ }
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("boom-bot", 5)
+ },
+ remove() {
+ if (this.count) {
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'boom') bullet[i].isUpgraded = false
+ }
+ tech.setBotTechFrequency(1)
+ }
+ tech.isBoomBotUpgrade = false
+ }
+ },
+ {
+ name: "laser-bot",
+ link: `laser-bot `,
+ description: "a bot uses energy to emit a laser beam that targets nearby mobs",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return m.maxEnergy > 0.5
+ },
+ requires: "maximum energy above 50",
+ effect() {
+ tech.laserBotCount++;
+ b.laserBot();
+ },
+ remove() {
+ if (this.count) {
+ tech.laserBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ }
+ },
+ {
+ name: "laser-bot upgrade",
+ link: `laser-bot upgrade `,
+ description: "convert your bots to laser-bots +100% damage , efficiency, and range",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.laserBotCount > 1 && !b.hasBotUpgrade()
+ },
+ requires: "2 or more laser bots and no other bot upgrade",
+ effect() {
+ tech.isLaserBotUpgrade = true
+ b.convertBotsTo("laser-bot")
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'laser') bullet[i].isUpgraded = true
+ }
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("laser-bot", 5)
+ },
+ remove() {
+ if (this.count) {
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'laser') bullet[i].isUpgraded = false
+ }
+ tech.setBotTechFrequency(1)
+ }
+ tech.isLaserBotUpgrade = false
+ }
+ },
+ {
+ name: "orbital-bot",
+ link: `orbital-bot `,
+ description: "a bot is locked in orbit around youstuns and damages mobs on contact ",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ b.orbitBot();
+ tech.orbitBotCount++;
+ },
+ remove() {
+ if (this.count) {
+ tech.orbitBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ }
+ },
+ {
+ name: "orbital-bot upgrade",
+ link: `orbital-bot upgrade `,
+ description: "convert your bots to orbital-bots +300% orbital damage and +50% radius ",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.orbitBotCount > 1 && !b.hasBotUpgrade()
+ },
+ requires: "2 or more orbital bots and no other bot upgrade",
+ effect() {
+ tech.isOrbitBotUpgrade = true
+ b.convertBotsTo("orbital-bot")
+ const range = 190 + 120 * tech.isOrbitBotUpgrade
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'orbit') {
+ bullet[i].isUpgraded = true
+ bullet[i].range = range
+ bullet[i].orbitalSpeed = Math.sqrt(0.25 / range)
+ }
+ }
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("orbital-bot", 5)
+ },
+ remove() {
+ if (this.count) {
+ const range = 190 + 100 * tech.isOrbitBotUpgrade
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'orbit') {
+ bullet[i].range = range
+ bullet[i].orbitalSpeed = Math.sqrt(0.25 / range)
+ }
+ }
+ tech.setBotTechFrequency(1)
+ }
+ tech.isOrbitBotUpgrade = false
+ }
+ },
+ {
+ name: "dynamo-bot",
+ link: `dynamo-bot `,
+ description: "a bot damages mobs while it traces your path when it's near generate +8 energy per second",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.dynamoBotCount++;
+ b.dynamoBot();
+ },
+ remove() {
+ if (this.count) {
+ tech.dynamoBotCount -= this.count;
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ }
+ },
+ {
+ name: "dynamo-bot upgrade",
+ link: `dynamo-bot upgrade `,
+ description: "convert your bots to dynamo-bots when it's near generate +24 energy per second",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBotTech: true,
+ allowed() {
+ return tech.dynamoBotCount > 1 && !b.hasBotUpgrade()
+ },
+ requires: "2 or more dynamo bots and no other bot upgrade",
+ effect() {
+ tech.isDynamoBotUpgrade = true
+ b.convertBotsTo("dynamo-bot")
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'dynamo') bullet[i].isUpgraded = true
+ }
+ tech.setBotTechFrequency()
+ tech.setTechFrequency("dynamo-bot", 5)
+ },
+ remove() {
+ if (this.count) {
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType === 'dynamo') bullet[i].isUpgraded = false
+ }
+ tech.setBotTechFrequency(1)
+ }
+ tech.isDynamoBotUpgrade = false
+ }
+ },
+ {
+ name: "perimeter defense",
+ description: "for each permanent bot +6% defense ",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBotTech: true,
+ allowed() {
+ return b.totalBots() > 1
+ },
+ requires: "at least 2 bots",
+ effect() {
+ tech.isBotArmor = true
+ },
+ remove() {
+ tech.isBotArmor = false
+ }
+ },
+ {
+ name: "network effect",
+ description: "for each permanent bot +6% damage ",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBotTech: true,
+ allowed() {
+ return b.totalBots() > 1
+ },
+ requires: "at least 2 bots",
+ effect() {
+ tech.isBotDamage = true
+ },
+ remove() {
+ tech.isBotDamage = false
+ }
+ },
+ {
+ name: "bot fabrication",
+ link: `bot fabrication `,
+ descriptionFunction() {
+ return `after you collect ${powerUps.orb.research(2 + Math.floor(0.1666 * b.totalBots()))}use them to build a random bot (+1 cost every 5 bots) `
+ },
+ // description: `if you collect ${powerUps.orb.research(2)}use them to build a random bot (+1 cost every 5 bots) `,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBotTech: true,
+ allowed() {
+ return powerUps.research.count > 1 || build.isExperimentSelection
+ },
+ requires: "at least 2 research",
+ effect() {
+ tech.isRerollBots = true;
+ powerUps.research.changeRerolls(0)
+ simulation.makeTextLog(`m .research = 0`)
+ },
+ remove() {
+ tech.isRerollBots = false;
+ // this.description = `if you collect ${powerUps.orb.research(2 + Math.floor(0.2 * b.totalBots()))}use them to build a random bot (+1 cost every 5 bots) `
+ }
+ },
+ {
+ name: "ersatz bots",
+ link: `ersatz bots `,
+ description: "double your current permanent bots remove all guns in your inventory",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBotTech: true,
+ // isNonRefundable: true,
+ isBadRandomOption: true,
+ numberOfGunsLost: 0,
+ allowed() {
+ return b.totalBots() > 3 && !build.isExperimentSelection
+ },
+ requires: "NOT EXPERIMENT MODE, at least 4 bots",
+ effect() {
+ this.numberOfGunsLost = b.inventory.length
+ b.removeAllGuns();
+ simulation.makeGunHUD();
+ //double bots
+ for (let i = 0; i < tech.nailBotCount; i++) b.nailBot();
+ tech.nailBotCount *= 2
+ for (let i = 0; i < tech.laserBotCount; i++) b.laserBot();
+ tech.laserBotCount *= 2
+ for (let i = 0; i < tech.foamBotCount; i++) b.foamBot();
+ tech.foamBotCount *= 2
+ for (let i = 0; i < tech.boomBotCount; i++) b.boomBot();
+ tech.boomBotCount *= 2
+ for (let i = 0; i < tech.orbitBotCount; i++) b.orbitBot();
+ tech.orbitBotCount *= 2
+ for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot();
+ tech.dynamoBotCount *= 2
+ for (let i = 0; i < tech.soundBotCount; i++) b.soundBot();
+ tech.soundBotCount *= 2
+ for (let i = 0; i < tech.plasmaBotCount; i++) b.plasmaBot();
+ tech.plasmaBotCount *= 2
+ for (let i = 0; i < tech.missileBotCount; i++) b.missileBot();
+ tech.missileBotCount *= 2
+ },
+ remove() {
+ if (this.count) {
+ //return guns
+ for (let i = 0; i < this.numberOfGunsLost; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun");
+ this.numberOfGunsLost = 0;
+
+ //half all current guns
+ tech.nailBotCount = Math.round(tech.nailBotCount / 2)
+ tech.laserBotCount = Math.round(tech.laserBotCount / 2)
+ tech.foamBotCount = Math.round(tech.foamBotCount / 2)
+ tech.soundBotCount = Math.round(tech.soundBotCount / 2)
+ tech.boomBotCount = Math.round(tech.boomBotCount / 2)
+ tech.orbitBotCount = Math.round(tech.orbitBotCount / 2)
+ tech.dynamoBotCount = Math.round(tech.dynamoBotCount / 2)
+ tech.plasmaBotCount = Math.round(tech.plasmaBotCount / 2)
+ tech.missileBotCount = Math.round(tech.missileBotCount / 2)
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ }
+ },
+ // {
+ // name: "robotics",
+ // description: `spawn 2 random bots quadruple the frequency of finding bot tech `,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 1,
+ // frequencyDefault: 1,
+ // isBotTech: true,
+ // allowed() {
+ // return b.totalBots() > 1 || build.isExperimentSelection
+ // },
+ // requires: "at least 2 bots",
+ // effect: () => {
+ // b.randomBot()
+ // b.randomBot()
+ // for (let i = 0, len = tech.tech.length; i < len; i++) {
+ // if (tech.tech[i].isBotTech) tech.tech[i].frequency *= 4
+ // }
+ // },
+ // remove() {
+ // if (this.count > 0) {
+ // b.removeBot()
+ // b.removeBot()
+ // b.clearPermanentBots();
+ // b.respawnBots();
+ // for (let i = 0, len = tech.tech.length; i < len; i++) {
+ // if (tech.tech[i].isBotTech) tech.tech[i].frequency = Math.ceil(tech.tech[i].frequency / 4)
+ // }
+ // }
+ // }
+ // },
+ {
+ name: "robotics",
+ description: `spawn 2 random bots tech , fields , and guns have +1 bot choice `, //tech have an extra bot tech option
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBotTech: true,
+ allowed() {
+ return b.totalBots() > 1
+ },
+ requires: "at least 2 bots",
+ effect() {
+ tech.isExtraBotOption = true
+ for (let i = 0; i < 2; i++) b.randomBot()
+ },
+ remove() {
+ if (this.count > 0) {
+ for (let i = 0; i < 2; i++) b.removeBot()
+ b.clearPermanentBots();
+ b.respawnBots();
+ }
+ tech.isExtraBotOption = false
+ }
+ },
+ {
+ name: "open-source", //digital fabricator
+ description: `spawn 3 random bots triple the frequency of finding bot tech `,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isBotTech: true,
+ allowed() {
+ return tech.isExtraBotOption
+ },
+ requires: "robotics",
+ effect() {
+ for (let i = 0; i < 3; i++) b.randomBot()
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isBotTech) tech.tech[i].frequency *= 3
+ }
+ },
+ remove() {
+ if (this.count > 0) {
+ for (let i = 0; i < 3; i++) b.removeBot()
+ b.clearPermanentBots();
+ b.respawnBots();
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isBotTech) tech.tech[i].frequency = Math.ceil(tech.tech[i].frequency / 3)
+ }
+ }
+ }
+ },
+ {
+ name: "decorrelation",
+ description: "if your gun or field are unused for 2 seconds+70% defense ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isRewindField
+ },
+ requires: "not retrocausality",
+ effect() {
+ tech.isNoFireDefense = true
+ },
+ remove() {
+ tech.isNoFireDefense = false
+ }
+ },
+ {
+ name: "anticorrelation",
+ description: "if your gun or field are unused for 2 seconds+100% damage ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isRewindField
+ },
+ requires: "not retrocausality",
+ effect() {
+ tech.isNoFireDamage = true
+ },
+ remove() {
+ tech.isNoFireDamage = false
+ }
+ },
+ {
+ name: "mass driver",
+ description: "+300% block collision damage ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return m.fieldMode !== 9 && !tech.isTokamak
+ },
+ requires: "not wormhole, tokamak",
+ effect() {
+ tech.blockDamage = 0.3
+ },
+ remove() {
+ tech.blockDamage = 0.075
+ }
+ },
+ {
+ name: "inflation",
+ link: `inflation `,
+ description: "if holding a block +90% defense after throwing a block it expands 200% ",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.blockDamage > 0.075 || tech.isPrinter) && m.fieldMode !== 8 && m.fieldMode !== 9 && !tech.isTokamak
+ },
+ requires: "mass driver, not pilot wave, tokamak, wormhole",
+ effect() {
+ tech.isAddBlockMass = true
+ },
+ remove() {
+ tech.isAddBlockMass = false
+ }
+ },
+ {
+ name: "restitution",
+ description: "+150% block collision damage after throwing a block it becomes very bouncy ",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.blockDamage > 0.075 || tech.isPrinter) && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && m.fieldUpgrades[m.fieldMode].name !== "wormhole" && !tech.isTokamak
+ },
+ requires: "mass driver, not pilot wave, tokamak, wormhole",
+ effect() {
+ tech.isBlockRestitution = true
+ },
+ remove() {
+ tech.isBlockRestitution = false
+ }
+ },
+ {
+ name: "flywheel",
+ description: "+150% block collision damage after a mob dies its block is flung at mobs",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.blockDamage > 0.075 || tech.isPrinter) && !tech.nailsDeathMob && !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.iceIXOnDeath
+ },
+ requires: "mass driver, no other mob death tech",
+ effect() {
+ tech.isMobBlockFling = true
+ },
+ remove() {
+ tech.isMobBlockFling = false
+ }
+ },
+ // {
+ // name: "fermions",
+ // description: "blocks thrown by you or pilot wave willcollide with intangible mobs, but not you",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return (tech.blockDamage > 0.075 || m.fieldMode === 8) && !tech.isTokamak
+ // },
+ // requires: "mass driver or pilot wave, not tokamak",
+ // effect() {
+ // tech.isBlockBullets = true
+ // },
+ // remove() {
+ // tech.isBlockBullets = false
+ // }
+ // },
+ {
+ name: "buckling",
+ descriptionFunction() {
+ return `if a block you threw kills a mob spawn either ${powerUps.orb.coupling(1)}, ${powerUps.orb.boost(1)}, ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.blockDamage > 0.075 || tech.isPrinter) && m.fieldUpgrades[m.fieldMode].name !== "pilot wave" && !tech.isTokamak
+ },
+ requires: "mass driver, not pilot wave, tokamak",
+ effect() {
+ tech.isBlockPowerUps = true
+ },
+ remove() {
+ tech.isBlockPowerUps = false
+ }
+ },
+ {
+ name: "NOR gate",
+ description: "if flip-flop is OFF become invulnerable to your next collision",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isFlipFlop
+ },
+ requires: "flip-flop",
+ effect() {
+ tech.isFlipFlopHarm = true //do you have this tech
+ },
+ remove() {
+ tech.isFlipFlopHarm = false
+ }
+ },
+ {
+ name: "shape-memory alloy",
+ descriptionFunction() {
+ return `if flip-flop is ON +400 maximum health and +100% ${powerUps.orb.heal()} effect`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isFlipFlop
+ },
+ requires: "flip-flop",
+ effect() {
+ tech.isFlipFlopHealth = true;
+ m.setMaxHealth();
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal") {
+ const oldSize = powerUp[i].size
+ powerUp[i].size = powerUps.heal.size() //update current heals
+ const scale = powerUp[i].size / oldSize
+ Matter.Body.scale(powerUp[i], scale, scale); //grow
+ }
+ }
+ },
+ remove() {
+ tech.isFlipFlopHealth = false;
+ m.setMaxHealth();
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal") {
+ const oldSize = powerUp[i].size
+ powerUp[i].size = powerUps.heal.size() //update current heals
+ const scale = powerUp[i].size / oldSize
+ Matter.Body.scale(powerUp[i], scale, scale); //grow
+ }
+ }
+ }
+ },
+ {
+ name: "flip-flop",
+ link: `flip-flop `,
+ description: `toggle ON and OFF after a collision unlock advanced tech that runs if ON `,
+ nameInfo: " ",
+ addNameInfo() {
+ setTimeout(function () {
+ if (document.getElementById("tech-flip-flop")) {
+ if (tech.isFlipFlopOn) {
+ document.getElementById("tech-flip-flop").innerHTML = ` = ON `
+ m.eyeFillColor = m.fieldMeterColor //'#5af'
+ } else {
+ document.getElementById("tech-flip-flop").innerHTML = ` = OFF `
+ m.eyeFillColor = "transparent"
+ }
+ }
+ }, 100);
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isRelay
+ },
+ requires: "not relay switch",
+ effect() {
+ tech.isFlipFlop = true //do you have this tech?
+ if (!tech.isFlipFlopOn) {
+ tech.isFlipFlopOn = true //what is the state of flip-Flop?
+ }
+ // if (!m.isShipMode) {
+ // m.skin.flipFlop()
+ // }
+ },
+ remove() {
+ tech.isFlipFlop = false
+ if (tech.isFlipFlopOn) {
+ tech.isFlipFlopOn = false //what is the state of flip-Flop?
+ }
+ m.eyeFillColor = 'transparent'
+ // m.resetSkin();
+ }
+ },
+ {
+ name: "NAND gate",
+ description: "if ON +55.5% damage ",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isFlipFlop || tech.isRelay
+ },
+ requires: "ON/OFF tech",
+ effect() {
+ tech.isFlipFlopDamage = true;
+ },
+ remove() {
+ tech.isFlipFlopDamage = false;
+ }
+ },
+ {
+ name: "integrated circuit",
+ description: "if ON +7 power up choices if OFF -1 power up choices ",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.isFlipFlop || tech.isRelay) && !tech.isDeterminism
+ },
+ requires: "ON/OFF tech, not determinism",
+ effect() {
+ tech.isFlipFlopChoices = true //do you have this tech
+ },
+ remove() {
+ tech.isFlipFlopChoices = false
+ }
+ },
+ {
+ name: "transistor",
+ description: "if ON generate +20 energy per second if OFF drain -1 energy per second",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isFlipFlop || tech.isRelay
+ },
+ requires: "ON/OFF tech",
+ effect() {
+ tech.isFlipFlopEnergy = true;
+ },
+ remove() {
+ tech.isFlipFlopEnergy = false;
+ }
+ },
+ // {
+ // name: "decoupling",
+ // link: `decoupling `,
+ // descriptionFunction() {
+ // //(${ m.couplingDescription(this.bonus)})
+ // return `if ON +5 coupling if OFF a dangerous particle slowly chases you`
+ // },
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 3,
+ // frequencyDefault: 3,
+ // bonus: 5, //coupling given
+ // allowed() {
+ // return tech.isFlipFlop || tech.isRelay
+ // },
+ // requires: "ON/OFF tech",
+ // effect() {
+ // tech.isFlipFlopCoupling = true;
+ // if (tech.isFlipFlopOn) {
+ // m.couplingChange(this.bonus)
+ // } else {
+ // for (let i = 0; i < mob.length; i++) {
+ // if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
+ // }
+ // spawn.WIMP()
+ // mob[mob.length - 1].isDecoupling = true //so you can find it to remove
+ // }
+ // },
+ // remove() {
+ // tech.isFlipFlopCoupling = false;
+ // if (this.count) {
+ // if (tech.isFlipFlop || tech.isRelay) {
+ // if (tech.isFlipFlopOn) {
+ // m.couplingChange(-this.bonus)
+ // } else {
+ // for (let i = 0; i < mob.length; i++) {
+ // if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP
+ // }
+ // }
+ // }
+ // }
+ // }
+ // },
+ {
+ name: "relay switch",
+ description: `toggle ON and OFF after picking up a power up unlock advanced tech that runs if ON `,
+ nameInfo: " ",
+ addNameInfo() {
+ setTimeout(function () {
+ if (document.getElementById("tech-switch")) {
+ if (tech.isFlipFlopOn) {
+ document.getElementById("tech-switch").innerHTML = ` = ON `
+ m.eyeFillColor = m.fieldMeterColor //'#5af'
+ } else {
+ document.getElementById("tech-switch").innerHTML = ` = OFF `
+ m.eyeFillColor = "transparent"
+ }
+ }
+ }, 100);
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isFlipFlop
+ },
+ requires: "not flip-flop",
+ effect() {
+ m.isAltSkin = true
+ tech.isRelay = true //do you have this tech?
+ if (!tech.isFlipFlopOn) {
+ tech.isFlipFlopOn = true //what is the state of flip-Flop?
+ }
+ // if (!m.isShipMode) {
+ // m.skin.flipFlop()
+ // }
+ },
+ remove() {
+ tech.isRelay = false
+ if (tech.isFlipFlopOn) {
+ tech.isFlipFlopOn = false //what is the state of flip-Flop?
+ }
+ m.eyeFillColor = 'transparent'
+ // m.resetSkin();
+ }
+ },
+ {
+ name: "lithium-ion",
+ description: "if relay switch is ON +300 maximum energy ",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isRelay
+ },
+ requires: "relay switch",
+ effect() {
+ tech.isRelayEnergy = true
+ m.setMaxEnergy()
+ },
+ remove() {
+ tech.isRelayEnergy = false
+ m.setMaxEnergy()
+ }
+ },
+ {
+ name: "thermocouple",
+ description: "if relay switch is ON condense 4-13 ice IX crystals per second",
+ maxCount: 9,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isRelay
+ },
+ requires: "relay switch",
+ effect() {
+ tech.relayIce++
+ },
+ remove() {
+ tech.relayIce = 0
+ }
+ },
+ {
+ name: "first derivative",
+ descriptionFunction() {
+ return `while your first gun is equipped+15% defense per gun (${(100 * (1 - 0.85 ** b.inventory.length)).toFixed(0)}%) `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isFirstDer = true
+ },
+ remove() {
+ tech.isFirstDer = false;
+ }
+ },
+ {
+ name: "MACHO",
+ description: "a massive but compact object slowly follows you if you are inside the MACHO +60% defense ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isMACHO = true; //this harm reduction comes from the particle toggling tech.isHarmMACHO
+ spawn.MACHO()
+ },
+ remove() {
+ tech.isMACHO = false;
+ tech.isHarmMACHO = false;
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isMACHO) mob[i].alive = false;
+ }
+ }
+ },
+ {
+ name: "axion",
+ description: "while inside the MACHO defense increases damage ",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isMACHO
+ },
+ requires: "MACHO",
+ effect() {
+ tech.isAxion = true
+ },
+ remove() {
+ tech.isAxion = false
+ }
+ },
+ {
+ name: "dark star",
+ description: "mobs inside the MACHO are damaged increase MACHO radius by 15% ",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isMACHO
+ },
+ requires: "MACHO",
+ effect() {
+ tech.isDarkStar = true
+ },
+ remove() {
+ tech.isDarkStar = false
+ }
+ },
+ {
+ name: "ablative drones",
+ description: "after losing health there is a chance to rebuild your broken parts as drones ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.isDroneOnDamage = true;
+ // for (let i = 0; i < 4; i++) b.drone()
+ },
+ remove() {
+ tech.isDroneOnDamage = false;
+ }
+ },
+ {
+ name: "non-Newtonian armor",
+ link: `non-Newtonian armor `,
+ description: "after mob collisions+66% defense for 10 seconds",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isHarmArmor = true;
+ },
+ remove() {
+ tech.isHarmArmor = false;
+ }
+ },
+ {
+ name: "Pauli exclusion",
+ description: `after mob collisions become invulnerable for +3.5 seconds`,
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ m.collisionImmuneCycles += 210;
+ if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage
+ },
+ remove() {
+ m.collisionImmuneCycles = 30;
+ }
+ },
+ {
+ name: "spin–statistics theorem",
+ description: `every 7 seconds become invulnerable for +1.9 seconds`,
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true //m.collisionImmuneCycles > 30
+ },
+ requires: "",
+ effect() {
+ tech.cyclicImmunity += 114;
+ },
+ remove() {
+ tech.cyclicImmunity = 0;
+ }
+ },
+ {
+ name: "refrigerant",
+ descriptionFunction() {
+ return `after losing at least 5% ${tech.isEnergyHealth ? "energy " : "health "}freeze all mobs for 7 seconds`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isHarmFreeze = true;
+ },
+ remove() {
+ tech.isHarmFreeze = false;
+ }
+ },
+ // {
+ // name: "clock gating",
+ // description: `after losing health slow time by 50% +20% defense `,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 1,
+ // frequencyDefault: 1,
+ // allowed() {
+ // return simulation.fpsCapDefault > 45
+ // },
+ // requires: "FPS above 45",
+ // effect() {
+ // tech.isSlowFPS = true;
+ // },
+ // remove() {
+ // tech.isSlowFPS = false;
+ // }
+ // },
+
+ {
+ name: "piezoelectricity",
+ description: "if you collide with a mob generate +2048 energy ", // reduce defense by 15%
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isEnergyHealth
+ },
+ requires: "not mass-energy",
+ effect() {
+ tech.isPiezo = true;
+ // if (simulation.isTextLogOpen) m.energy += 20.48;
+ },
+ remove() {
+ tech.isPiezo = false;
+ }
+ },
+ {
+ name: "ground state",
+ description: "+266 maximum energy –33% passive energy generation",
+ // description: "reduce defense by 66% you no longer passively regenerate energy ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isTimeCrystals
+ },
+ requires: "not time crystals",
+ effect() {
+ tech.isGroundState = true
+ m.setFieldRegen()
+ m.setMaxEnergy()
+ },
+ remove() {
+ tech.isGroundState = false
+ m.setFieldRegen()
+ m.setMaxEnergy()
+ }
+ },
+ {
+ name: "heat engine",
+ description: `+50% damage –50 maximum energy `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "not CPT",
+ damage: 1.5,
+ effect() {
+ tech.damage *= this.damage
+ tech.isMaxEnergyTech = true;
+ m.setMaxEnergy()
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isMaxEnergyTech = false;
+ m.setMaxEnergy()
+ }
+ },
+ {
+ name: "exothermic process",
+ description: "+50% damage after mobs die –20% energy ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ damage: 1.55,
+ effect() {
+ tech.damage *= this.damage
+ tech.isEnergyLoss = true;
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isEnergyLoss = false;
+ }
+ },
+ {
+ name: "Gibbs free energy",
+ description: `for each energy below 100 +0.7% damage `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.isLowEnergyDamage = true;
+ },
+ remove() {
+ tech.isLowEnergyDamage = false;
+ }
+ },
+ {
+ name: "overcharge",
+ description: "+66 maximum energy +6% JUNK to tech pool",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.bonusEnergy += 0.66
+ m.setMaxEnergy()
+ this.refundAmount += tech.addJunkTechToPool(0.06)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.bonusEnergy = 0;
+ m.setMaxEnergy()
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "Maxwells demon",
+ description: "energy above max decays by 30% 1% per second+5% JUNK to tech pool",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.energy > m.maxEnergy || build.isExperimentSelection
+ },
+ requires: "energy above your max",
+ effect() {
+ tech.overfillDrain = 0.99 //70% = 1-(1-0.75)/(1-0.15) //92% = 1-(1-0.75)/(1-0.87)
+ this.refundAmount += tech.addJunkTechToPool(0.05)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.overfillDrain = 0.7
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "inductive charging",
+ description: "if crouched +600% passive energy generation if not crouched energy generation is disabled",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isDamageAfterKillNoRegen
+ },
+ requires: "not parasitism",
+ effect() {
+ tech.isCrouchRegen = true; //only used to check for requirements
+ m.regenEnergy = function () {
+ if (m.immuneCycle < m.cycle && m.crouch && m.fieldCDcycle < m.cycle) m.energy += 7 * m.fieldRegen;
+ if (m.energy < 0) m.energy = 0
+ }
+ },
+ remove() {
+ tech.isCrouchRegen = false;
+ m.regenEnergy = m.regenEnergyDefault
+ }
+ },
+ {
+ name: "energy conservation",
+ description: "4% of damage done recovered as energy ",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.energySiphon += 0.04;
+ },
+ remove() {
+ tech.energySiphon = 0;
+ }
+ },
+ {
+ name: "parasitism",
+ description: "if a mob has died in the last 5 seconds +83% damage , inhibit energy generation",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isCrouchRegen
+ },
+ requires: "not inductive charging",
+ effect() {
+ tech.isDamageAfterKillNoRegen = true;
+ m.regenEnergy = function () {
+ if (m.immuneCycle < m.cycle && (m.lastKillCycle + 300 < m.cycle) && m.fieldCDcycle < m.cycle) m.energy += m.fieldRegen;
+ if (m.energy < 0) m.energy = 0
+ }
+ },
+ remove() {
+ if (this.count) m.regenEnergy = m.regenEnergyDefault
+ tech.isDamageAfterKillNoRegen = false;
+ }
+ },
+ {
+ name: "waste heat recovery",
+ description: "if a mob has died in the last 5 seconds generate 5% of max energy per second",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isEnergyRecovery = true;
+ },
+ remove() {
+ tech.isEnergyRecovery = false;
+ }
+ },
+ {
+ name: "recycling",
+ description: "if a mob has died in the last 5 seconds recover 0.5% of max health per second",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isHealthRecovery = true;
+ },
+ remove() {
+ tech.isHealthRecovery = false;
+ }
+ },
+ {
+ name: "torpor",
+ description: "if a mob has not died in the last 5 seconds +66% defense ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isHarmReduceNoKill = true;
+ },
+ remove() {
+ tech.isHarmReduceNoKill = false;
+ }
+ },
+ {
+ name: "homeostasis",
+ descriptionFunction() {
+ return `for each health below 100 +0.8% defense (${(100 * (Math.max(0, 1 - m.health) * 0.8)).toFixed(0)}%) `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return m.health < 0.6 || build.isExperimentSelection
+ },
+ requires: "health below 60",
+ effect() {
+ tech.isLowHealthDefense = true;
+ },
+ remove() {
+ tech.isLowHealthDefense = false;
+ }
+ },
+ {
+ name: "negative feedback",
+ descriptionFunction() {
+ return `for each ${tech.isEnergyHealth ? "energy " : "health "} below 100 +0.7% damage (${(70 * Math.max(0, 1 - (tech.isEnergyHealth ? m.energy : m.health))).toFixed(0)}%) `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return m.health < 0.6 || build.isExperimentSelection
+ },
+ requires: "health below 60",
+ effect() {
+ tech.isLowHealthDmg = true; //used in mob.damage()
+ },
+ remove() {
+ tech.isLowHealthDmg = false;
+ }
+ },
+ {
+ name: "Zenos paradox",
+ descriptionFunction() {
+ return `+85% defense –5% of current ${tech.isEnergyHealth ? "energy " : "health "} every 5 seconds`
+ },
+ // description: "+85% defense –5% of current health every 5 seconds",
+ // description: "every 5 seconds remove 1/10 of your health reduce defense by 90% ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isZeno = true;
+ },
+ remove() {
+ tech.isZeno = false;
+ }
+ },
+ {
+ name: "antiscience",
+ descriptionFunction() {
+ return `–10 ${tech.isEnergyHealth ? "energy " : "health "} after picking up a tech +66% damage `
+ },
+ // description: "+66% damage –10 health after picking up a tech ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ damage: 1.66,
+ effect() {
+ tech.damage *= this.damage
+ tech.isTechDamage = true;
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isTechDamage = false;
+ }
+ },
+ {
+ name: "ergodicity",
+ descriptionFunction() {
+ return `${powerUps.orb.heal()} have -50% effect+66% damage `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ damage: 1.66,
+ effect() {
+ tech.damage *= this.damage
+ tech.isHalfHeals = true;
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal") {
+ const scale = Math.sqrt(0.5)
+ powerUp[i].size *= scale
+ Matter.Body.scale(powerUp[i], scale, scale); //grow
+ }
+ }
+ },
+ remove() {
+ if (this.count) {
+ tech.damage /= this.damage
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal") {
+ const scale = 1 / Math.sqrt(0.5)
+ powerUp[i].size *= scale
+ Matter.Body.scale(powerUp[i], scale, scale); //grow
+ }
+ }
+ }
+ tech.isHalfHeals = false;
+ }
+ },
+ {
+ name: "fluoroantimonic acid",
+ description: "if your health is above 100 +35% damage ",
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.maxHealth > 1;
+ },
+ requires: "max health above 100",
+ effect() {
+ tech.isAcidDmg = true;
+ },
+ remove() {
+ tech.isAcidDmg = false;
+ }
+ },
+ {
+ name: "induction brake",
+ descriptionFunction() {
+ return `after using ${powerUps.orb.heal()} slow nearby mobs for 15 seconds spawn ${powerUps.orb.heal(4)}`
+ },
+ // description: `after using ${powerUps.orb.heal()} slow nearby mobs for 15 seconds spawn ${powerUps.orb.heal(4)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isPerfectBrake
+ },
+ requires: "not eddy current brake",
+ effect() {
+ tech.isHealBrake = true;
+ for (let i = 0; i < 4; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal");
+ },
+ remove() {
+ tech.isHealBrake = false;
+ }
+ },
+ {
+ name: "adiabatic healing",
+ descriptionFunction() {
+ return `${powerUps.orb.heal()} have +100% effect+4% JUNK to tech pool`
+ },
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return (m.health / m.maxHealth) < 0.7 || build.isExperimentSelection
+ },
+ requires: "under 70% health",
+ effect() {
+ tech.largerHeals++;
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal") {
+ const oldSize = powerUp[i].size
+ powerUp[i].size = powerUps.heal.size() //update current heals
+ const scale = powerUp[i].size / oldSize
+ Matter.Body.scale(powerUp[i], scale, scale); //grow
+ }
+ }
+ this.refundAmount += tech.addJunkTechToPool(0.04)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.largerHeals = 1;
+ for (let i = 0; i < powerUp.length; i++) {
+ if (powerUp[i].name === "heal") {
+ const oldSize = powerUp[i].size
+ powerUp[i].size = powerUps.heal.size() //update current heals
+ const scale = powerUp[i].size / oldSize
+ Matter.Body.scale(powerUp[i], scale, scale); //grow
+ }
+ }
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "quenching",
+ descriptionFunction() {
+ return `after over healing from ${powerUps.orb.heal()} gain max health and lose current health `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isOverHeal = true;
+ },
+ remove() {
+ tech.isOverHeal = false;
+ }
+ },
+ {
+ name: "accretion",
+ descriptionFunction() {
+ return `${powerUps.orb.heal(1)} follow you, even between levels spawn ${powerUps.orb.heal(5)}`
+ },
+ // description: `${powerUps.orb.heal(1)} follow you, even between levels spawn ${powerUps.orb.heal(5)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return m.fieldMode !== 9
+ },
+ requires: "not wormhole",
+ effect() {
+ tech.isHealAttract = true
+ powerUps.setPowerUpMode();
+ for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal");
+ },
+ remove() {
+ tech.isHealAttract = false
+ powerUps.setPowerUpMode();
+ },
+ },
+ {
+ name: "self-assembly",
+ descriptionFunction() {
+ return `at the start of each level for every 25% missing ${tech.isEnergyHealth ? "energy " : "health "} spawn ${powerUps.orb.heal()}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isHealLowHealth = true;
+ },
+ remove() {
+ tech.isHealLowHealth = false;
+ }
+ },
+ {
+ name: "enthalpy",
+ descriptionFunction() {
+ return `doing damage has a small chance to spawn ${powerUps.orb.heal(1)}` //–10% defense
+ },
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.healthDrain += 0.023;
+ },
+ remove() {
+ tech.healthDrain = 0;
+ }
+ },
+ {
+ name: "maintenance",
+ descriptionFunction() {
+ return ` double the frequency of finding healing tech spawn ${powerUps.orb.heal(13)}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0; i < 13; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "heal");
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isHealTech) tech.tech[i].frequency *= 2
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "anthropic principle",
+ nameInfo: " ",
+ addNameInfo() {
+ setTimeout(function () {
+ powerUps.research.changeRerolls(0)
+ }, 1000);
+ },
+ descriptionFunction() {
+ return `once per level, instead of dying use ${powerUps.orb.research(1)} and spawn ${powerUps.orb.heal(5)}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isHealTech: true,
+ allowed() {
+ return powerUps.research.count > 0 || build.isExperimentSelection
+ },
+ requires: "at least 1 research",
+ effect() {
+ tech.isDeathAvoid = true;
+ tech.isDeathAvoidedThisLevel = false;
+ setTimeout(function () {
+ powerUps.research.changeRerolls(0)
+ }, 1000);
+ },
+ remove() {
+ tech.isDeathAvoid = false;
+ }
+ },
+ {
+ name: "weak anthropic principle",
+ description: "after anthropic principle prevents your death +50% duplication chance for that level",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isDeathAvoid
+ },
+ requires: "anthropic principle",
+ effect() {
+ tech.isAnthropicTech = true
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ },
+ remove() {
+ tech.isAnthropicTech = false
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ }
+ },
+ {
+ name: "strong anthropic principle",
+ description: "after anthropic principle prevents your death +137.03599% damage for that level",
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isDeathAvoid
+ },
+ requires: "anthropic principle",
+ effect() {
+ tech.isAnthropicDamage = true
+ },
+ remove() {
+ tech.isAnthropicDamage = false
+ }
+ },
+ {
+ name: "quantum immortality",
+ description: "+30% defense after dying , continue in an alternate reality ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isImmortal = true;
+ },
+ remove() {
+ tech.isImmortal = false;
+ }
+ },
+ {
+ name: "Hilbert space",
+ description: "+99% damage after a collision enter an alternate reality ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isAltRealityTech: true,
+ allowed() {
+ return !tech.isResearchReality && !tech.isSwitchReality
+ },
+ requires: "not Ψ(t) collapse, many-worlds",
+ damage: 1.99,
+ effect() {
+ tech.damage *= this.damage
+ tech.isCollisionRealitySwitch = true;
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isCollisionRealitySwitch = false;
+ }
+ },
+ {
+ name: "many-worlds",
+ // description: "each level is an alternate reality , where you find a tech at the start of each level",
+ description: `on each new level spawn a tech power up and enter an alternate reality `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isAltRealityTech: true,
+ allowed() {
+ return !tech.isResearchReality && !tech.isCollisionRealitySwitch
+ },
+ requires: "not Ψ(t) collapse, Hilbert space",
+ effect() {
+ tech.isSwitchReality = true;
+ },
+ remove() {
+ tech.isSwitchReality = false;
+ }
+ },
+ {
+ name: "Ψ(t) collapse",
+ link: `Ψ(t) collapse `,
+ description: `spawn ${powerUps.orb.research(16)} after you research enter an alternate reality `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isAltRealityTech: true,
+ allowed() {
+ return !tech.isSwitchReality && !tech.isCollisionRealitySwitch && !tech.isJunkResearch
+ },
+ requires: "not many-worlds, Hilbert space, pseudoscience",
+ bonusResearch: 16,
+ effect() {
+ tech.isResearchReality = true;
+ for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + Math.random() * 60, m.pos.y + Math.random() * 60, "research", false);
+ },
+ remove() {
+ tech.isResearchReality = false;
+ if (this.count > 0) powerUps.research.changeRerolls(-this.bonusResearch)
+ }
+ },
+ {
+ name: "decoherence",
+ description: `tech options you don't choose won't reoccur spawn ${powerUps.orb.research(6)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism
+ },
+ requires: "not superdeterminism",
+ bonusResearch: 6,
+ effect() {
+ tech.isBanish = true
+ for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
+ },
+ remove() {
+ if (tech.isBanish) {
+ tech.isBanish = false
+ //reset banish list
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].isBanished) tech.tech[i].isBanished = false
+ }
+ powerUps.research.changeRerolls(-this.bonusResearch)
+ }
+ tech.isBanish = false
+ }
+ },
+ {
+ name: "renormalization",
+ description: `46% chance to spawn ${powerUps.orb.research(1)} after consuming ${powerUps.orb.research(1)}+3% JUNK to tech pool`,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (powerUps.research.count > 3 || build.isExperimentSelection) && !tech.isSuperDeterminism
+ },
+ requires: "at least 4 research, not superdeterminism",
+ effect() {
+ tech.renormalization = true;
+ this.refundAmount += tech.addJunkTechToPool(0.03)
+
+ },
+ refundAmount: 0,
+ remove() {
+ tech.renormalization = false;
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "perturbation theory",
+ description: `if you have no ${powerUps.orb.research(1)} in your inventory+70% fire rate `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return powerUps.research.count === 0
+ },
+ requires: "no research",
+ effect() {
+ tech.isRerollHaste = true;
+ tech.researchHaste = 0.3;
+ b.setFireCD();
+ },
+ remove() {
+ tech.isRerollHaste = false;
+ tech.researchHaste = 1;
+ b.setFireCD();
+ }
+ },
+ {
+ name: "ansatz",
+ description: `after choosing a field , tech , or gun if you have no ${powerUps.orb.research(1)} in your inventory spawn ${powerUps.orb.research(2)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return powerUps.research.count < 1 && !tech.isSuperDeterminism && !tech.isRerollHaste && !tech.isResearchReality
+ },
+ requires: "no research, not superdeterminism, Ψ(t) collapse, perturbation theory",
+ effect() {
+ tech.isAnsatz = true;
+ },
+ remove() {
+ tech.isAnsatz = false;
+ }
+ },
+ {
+ name: "Bayesian statistics",
+ // description: `for each ${powerUps.orb.research(1)} in your inventory+3.8% damage `,
+ descriptionFunction() {
+ return `spawn ${powerUps.orb.research(this.bonusResearch)}+3% damage per ${powerUps.orb.research(1)} (${(3 * powerUps.research.count).toFixed(0)}%) `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return powerUps.research.count > 2 || build.isExperimentSelection
+ },
+ requires: "at least 3 research",
+ bonusResearch: 3,
+ effect() {
+ powerUps.spawnDelay("research", this.bonusResearch)
+ tech.isRerollDamage = true;
+ },
+ remove() {
+ tech.isRerollDamage = false;
+ if (this.count) {
+ powerUps.research.changeRerolls(-this.bonusResearch)
+ }
+ }
+ },
+ {
+ name: "mass production",
+ descriptionFunction() {
+ return `tech always have +3 choices to spawn ${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)} or ${powerUps.orb.research(5)}`
+ },
+ // description: `tech always have +3 choices to spawn ${powerUps.orb.ammo(8)} ${powerUps.orb.heal(8)} or ${powerUps.orb.research(5)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ tech.isMassProduction = true
+ },
+ remove() {
+ tech.isMassProduction = false
+ }
+ },
+ {
+ name: "research",
+ description: `spawn ${powerUps.orb.research(5)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isNonRefundable: true,
+ isMassProduction: true,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ powerUps.spawnDelay("research", 5);
+ },
+ remove() { }
+ },
+ {
+ name: "ammo",
+ description: `spawn ${powerUps.orb.ammo(8)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isNonRefundable: true,
+ isMassProduction: true,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ powerUps.spawnDelay("ammo", 8);
+ },
+ remove() { }
+ },
+ {
+ name: "heals",
+ descriptionFunction() {
+ return `spawn ${powerUps.orb.heal(8)}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isNonRefundable: true,
+ isMassProduction: true,
+ allowed() { return true },
+ requires: "mass production",
+ effect() {
+ powerUps.spawnDelay("heal", 8);
+ },
+ remove() { }
+ },
+ {
+ name: "pseudoscience",
+ description: "when selecting a power up, research 3 times for free , but add 1-4% JUNK to the tech pool",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isResearchReality && !tech.isSuperDeterminism //tech.isResearchBoss || tech.isMetaAnalysis || tech.isRerollBots || tech.isDeathAvoid || tech.isRerollDamage || build.isExperimentSelection
+ },
+ requires: "not Ψ(t) collapse, superdeterminism", //"abiogenesis, meta-analysis, bot fabrication, anthropic principle, or Bayesian statistics, not Ψ(t) collapse",
+ effect() {
+ tech.isJunkResearch = true;
+ },
+ remove() {
+ tech.isJunkResearch = false;
+ }
+ },
+ {
+ name: "brainstorming",
+ description: "tech choices randomize every 1.5 seconds for 10 seconds",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism
+ },
+ requires: "not superdeterminism",
+ effect() {
+ tech.isBrainstorm = true
+ tech.isBrainstormActive = false
+ tech.brainStormDelay = 1800 - simulation.difficultyMode * 100
+ },
+ remove() {
+ tech.isBrainstorm = false
+ tech.isBrainstormActive = false
+ }
+ },
+ {
+ name: "cross-disciplinary",
+ description: "tech have an extra field or gun choice +5% chance to duplicate spawned power ups ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isDeterminism
+ },
+ requires: "not determinism",
+ effect() {
+ tech.isExtraGunField = true;
+ },
+ remove() {
+ tech.isExtraGunField = false;
+ }
+ },
+ {
+ name: "emergence",
+ description: "tech , fields , and guns have +1 choice +8% damage ",
+ // description: "tech , fields , and guns have +2 choices +3% JUNK to tech pool",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isDeterminism
+ },
+ requires: "not determinism",
+ damage: 1.08,
+ effect() {
+ tech.extraChoices += 1;
+ tech.damage *= this.damage
+ // this.refundAmount += tech.addJunkTechToPool(0.03)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.extraChoices = 0;
+ if (this.count > 0) {
+ tech.damage /= this.damage
+ // if (this.refundAmount > 0) tech.removeJunkTechFromPool(this.refundAmount)
+ }
+ }
+ },
+ {
+ name: "path integral",
+ link: `path integral `,
+ description: "your next tech choice has all possible options +5% JUNK to tech pool",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ // isJunk: true,
+ allowed() {
+ return !tech.isDeterminism && !tech.isBrainstorm
+ },
+ requires: "not determinism, brainstorm",
+ effect() {
+ tech.tooManyTechChoices = 1
+ // for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
+ this.refundAmount += tech.addJunkTechToPool(0.05)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.tooManyTechChoices = 0
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "determinism",
+ description: "spawn 5 tech only 1 choice for tech , fields , and guns ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBadRandomOption: true,
+ isNonRefundable: true,
+ allowed() {
+ return !tech.extraChoices && !tech.isExtraGunField && !tech.isFlipFlopChoices
+ },
+ requires: "not emergence, cross-disciplinary, integrated circuit",
+ effect() {
+ tech.isDeterminism = true;
+ //if you change the number spawned also change it in Born rule
+ for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech");
+ },
+ remove() {
+ tech.isDeterminism = false;
+ }
+ },
+ {
+ name: "superdeterminism",
+ description: `spawn 5 tech you can't cancel and ${powerUps.orb.research(1)} no longer spawn `,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBadRandomOption: true,
+ isNonRefundable: true,
+ allowed() {
+ return tech.isDeterminism && !tech.isAnsatz && !tech.isJunkResearch && !tech.isBrainstorm
+ },
+ requires: "determinism, not ansatz, pseudoscience, brainstorming",
+ effect() {
+ tech.isSuperDeterminism = true;
+ //if you change the number spawned also change it in Born rule
+ for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech");
+ },
+ remove() {
+ tech.isSuperDeterminism = false;
+ }
+ },
+ {
+ name: "technical debt",
+ descriptionFunction() {
+ // return `+300% damage –15% damage for each tech you have learned (+${(Math.floor(100 * (Math.min(Math.pow(0.85, tech.totalCount - 20), 4 - 0.15 * tech.totalCount))) - 100)}%) `
+ return `+300% damage –15% damage for each tech you have learned (${(tech.totalCount > 20 ? 100 * (Math.pow(0.85, tech.totalCount - 20) - 1) : 100 * (3 - 0.15 * tech.totalCount)).toFixed(0)}%) `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ tech.isTechDebt = true;
+ },
+ remove() {
+ tech.isTechDebt = false;
+ }
+ },
+ // {
+ // name: "abiogenesis",
+ // // description: `use ${powerUps.orb.research(4)}(or 49% JUNK to the tech pool if you can't) to add a 2nd boss to each level`,
+ // description: `as a level begins spawn a 2nd boss using ${powerUps.orb.research(3)} (+49% JUNK to the tech pool if you can't pay) `,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return (build.isExperimentSelection || powerUps.research.count > 2) && !tech.isDuplicateMobs
+ // },
+ // requires: "at least 3 research, not parthenogenesis",
+ // effect() {
+ // tech.isResearchBoss = true;
+ // },
+ // remove() {
+ // tech.isResearchBoss = false;
+ // }
+ // },
+ {
+ name: "meta-analysis",
+ description: `if you choose a JUNK tech you instead get a random normal tech and spawn ${powerUps.orb.research(2)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.junkCount > 0
+ },
+ requires: "some JUNK tech",
+ effect() {
+ tech.isMetaAnalysis = true
+ },
+ remove() {
+ tech.isMetaAnalysis = false
+ }
+ },
+ {
+ name: "dark patterns",
+ description: "+22% damage +22% JUNK to tech pool",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ damage: 1.22,
+ effect() {
+ tech.damage *= this.damage
+ this.refundAmount += tech.addJunkTechToPool(0.22)
+ },
+ refundAmount: 0,
+ remove() {
+ if (this.count > 0) {
+ tech.damage /= this.damage
+ if (this.refundAmount > 0) tech.removeJunkTechFromPool(this.refundAmount)
+ }
+ }
+ },
+ {
+ name: "exciton",
+ descriptionFunction() {
+ return `after mobs die they have a 14% chance to spawn ${powerUps.orb.boost(1)} that give +${(powerUps.boost.damage * 100).toFixed(0)}% damage for ${(powerUps.boost.duration / 60).toFixed(0)} seconds `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.isBoostPowerUps = true
+ },
+ remove() {
+ tech.isBoostPowerUps = false
+ }
+ },
+ {
+ name: "band gap",
+ descriptionFunction() {
+ return `${powerUps.orb.boost(1)} give +77% damage but their duration is reduced by 1 second`
+ },
+ maxCount: 9,
+ count: 1,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isBoostPowerUps || tech.isBoostReplaceAmmo
+ },
+ requires: "exciton, quasiparticles",
+ effect() {
+ powerUps.boost.duration -= 60
+ powerUps.boost.damage += 0.77
+ },
+ remove() {
+ powerUps.boost.duration = 600
+ powerUps.boost.damage = 1.25
+ }
+ },
+ {
+ name: "eternalism",
+ description: "+24% damage time can't be paused (time can be dilated) ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isPauseSwitchField && !tech.isPauseEjectTech && !tech.isWormHolePause
+ },
+ requires: "not unified field theory, paradigm shift, invariant",
+ damage: 1.24,
+ effect() {
+ tech.damage *= this.damage
+ tech.isNoDraftPause = true
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.isNoDraftPause = false
+ }
+ },
+ {
+ name: "paradigm shift",
+ description: `when paused clicking a tech ejects it with a 20% chance to remove without ejecting `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism && !tech.isNoDraftPause
+ },
+ requires: "not superdeterminism, eternalism",
+ effect() {
+ tech.isPauseEjectTech = true;
+ },
+ remove() {
+ tech.isPauseEjectTech = false;
+ }
+ },
+ {
+ name: "unified field theory",
+ description: `when paused clicking your field cycles itdouble the frequency of finding field tech `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism && !tech.isNoDraftPause
+ },
+ requires: "not superdeterminism, eternalism",
+ effect() {
+ tech.isPauseSwitchField = true;
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isFieldTech) tech.tech[i].frequency *= 2
+ }
+ },
+ remove() {
+ tech.isPauseSwitchField = false;
+ if (this.count > 1) {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isFieldTech) tech.tech[i].frequency /= 2
+ }
+ }
+ }
+ },
+ {
+ name: "field coupling",
+ descriptionFunction() {
+ // return `spawn ${powerUps.orb.coupling(10)} that each give +0.1 coupling ` // ${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per coupling "}
+ return `spawn ${powerUps.orb.coupling(10)}${m.couplingDescription(1)} per ${powerUps.orb.coupling(1)} `
+ },
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ powerUps.spawnDelay("coupling", 10)
+ },
+ remove() {
+ if (this.count) m.couplingChange(-this.count * 10)
+ }
+ },
+ {
+ name: "quintessence",
+ descriptionFunction() {
+ if (this.count) {
+ converted = this.researchUsed * this.couplingToResearch
+ let orbText
+ if (converted > 15) {
+ orbText = `${converted} ${powerUps.orb.coupling()}`
+ } else {
+ orbText = powerUps.orb.coupling(converted)
+ }
+ return `convert ${this.researchUsed} ${powerUps.orb.research(1)} into ${orbText} ${m.couplingDescription(1)} per ${powerUps.orb.coupling(1)} `
+
+ } else {
+ let converted = powerUps.research.count * this.couplingToResearch
+ let orbText
+ if (converted > 15) {
+ orbText = `${converted} ${powerUps.orb.coupling()}`
+ } else {
+ orbText = powerUps.orb.coupling(converted)
+ }
+ return `convert ${powerUps.research.count} ${powerUps.orb.research(1)} into ${orbText} ${m.couplingDescription(1)} per ${powerUps.orb.coupling(1)} `
+ }
+
+
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return powerUps.research.count > 3
+ },
+ requires: "",
+ researchUsed: 0,
+ couplingToResearch: 3,
+ effect() {
+ // let count = 0
+ // while (powerUps.research.count > 0 && powerUps.research.count !== Infinity) {
+ // powerUps.research.changeRerolls(-1)
+ // count += 2.5
+ // this.researchUsed++
+ // }
+ // powerUps.spawnDelay("coupling", Math.floor(count))
+
+ let cycle = () => {
+ if (powerUps.research.count > 0 && powerUps.research.count !== Infinity) {
+ if (m.alive) requestAnimationFrame(cycle);
+ if (!simulation.paused && !simulation.isChoosing) { //&& !(simulation.cycle % 2)
+ powerUps.research.changeRerolls(-1)
+ this.researchUsed++
+ powerUps.spawnDelay("coupling", this.couplingToResearch)
+ }
+ } // else exit delay loop
+
+ }
+ requestAnimationFrame(cycle);
+ },
+ remove() {
+ if (this.count) {
+ m.couplingChange(-this.researchUsed * this.couplingToResearch)
+ powerUps.research.changeRerolls(this.researchUsed)
+ this.researchUsed = 0
+ }
+ }
+ },
+ {
+ name: "virtual particles",
+ descriptionFunction() {
+ return `17% chance after mobs die to spawn ${powerUps.orb.coupling(1)}${m.couplingDescription(1)} per ${powerUps.orb.coupling(1)} `
+ // return `17% chance after mobs die to spawn ${powerUps.orb.coupling(1)} that each give +0.1 coupling ` // ${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per coupling "}
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.isCouplingPowerUps = true //about 20-30 mobs per level so at 16% and 0.1 coupling that's about 25 * 0.16 * 0.1 = 0.4 coupling per level with out duplication
+ },
+ remove() {
+ tech.isCouplingPowerUps = false
+ }
+ },
+ {
+ name: "fine-structure constant",
+ descriptionFunction() {
+ // return `spawn ${this.value} ${powerUps.orb.coupling(1)} that each give +0.1 coupling -0.5 coupling after mob collisions `// ${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per coupling "}
+ return `spawn ${this.value} ${powerUps.orb.coupling(1)}, but lose ${powerUps.orb.coupling(5)} after mob collisions ${m.couplingDescription(1)} per ${powerUps.orb.coupling(1)} `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ value: 60,
+ effect() {
+ tech.isCouplingNoHit = true
+ powerUps.spawnDelay("coupling", this.value)
+ },
+ remove() {
+ if (this.count) m.couplingChange(-this.value)
+ tech.isCouplingNoHit = false
+ }
+ },
+ {
+ name: "residual dipolar coupling",
+ descriptionFunction() {
+ // return `clicking cancel for a field , tech , or gun spawns ${powerUps.orb.coupling(5)}that each give +0.1 coupling `// ${m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per coupling "}
+ return `clicking cancel spawns ${powerUps.orb.coupling(5)}${m.couplingDescription(1)} per ${powerUps.orb.coupling(1)} `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism
+ },
+ requires: "not superdeterminism",
+ effect() {
+ tech.isCancelCouple = true
+ },
+ remove() {
+ tech.isCancelCouple = false
+ }
+ },
+ {
+ name: "commodities exchange",
+ descriptionFunction() {
+ return `clicking cancel for a field , tech , or gun spawns 5-10 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism
+ },
+ requires: "not superdeterminism",
+ effect() {
+ tech.isCancelRerolls = true
+ },
+ remove() {
+ tech.isCancelRerolls = false
+ }
+ },
+ {
+ name: "options exchange",
+ link: `options exchange `,
+ description: `clicking cancel for a field , tech , or gun has a 85% chance to randomize choices `,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isSuperDeterminism //&& (tech.isCancelRerolls || tech.isCancelDuplication)
+ },
+ requires: "not superdeterminism", //futures exchange, commodities exchange,
+ effect() {
+ tech.isCancelTech = true
+ },
+ remove() {
+ tech.isCancelTech = false
+ }
+ },
+ {
+ name: "futures exchange",
+ description: "clicking cancel for a field , tech , or gun gives +4.1% power up duplication chance",
+ // descriptionFunction() {
+ // return `clicking × to cancel a field , tech , or gun gives +${4.9 - 0.15*simulation.difficultyMode}% power up duplication chance`
+ // },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() < 1 && !tech.isSuperDeterminism
+ },
+ requires: "below 100% duplication chance, not superdeterminism",
+ effect() {
+ tech.isCancelDuplication = true //search for tech.duplication to balance
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ },
+ remove() {
+ tech.isCancelDuplication = false
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ }
+ },
+ {
+ name: "replication",
+ description: "+9% chance to duplicate spawned power ups +33% JUNK to tech pool",
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() < 1.
+ },
+ requires: "below 100% duplication chance",
+ effect() {
+ tech.duplicateChance += 0.09
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11);
+ this.refundAmount += tech.addJunkTechToPool(0.33)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.duplicateChance = 0
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "stimulated emission",
+ description: "+17% chance to duplicate spawned power ups , but after a collision eject 1 tech ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() < 1
+ },
+ requires: "below 1% duplication chance",
+ effect() {
+ tech.isStimulatedEmission = true
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.15);
+ },
+ remove() {
+ tech.isStimulatedEmission = false
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ }
+ },
+ {
+ name: "metastability",
+ description: "+13% chance to duplicate spawned power ups duplicates explode with a 4 second half-life ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() < 1
+ },
+ requires: "below 100% duplication chance",
+ effect() {
+ tech.isPowerUpsVanish = true
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11);
+ },
+ remove() {
+ tech.isPowerUpsVanish = false
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ }
+ },
+ {
+ name: "correlated damage",
+ description: "duplication increases damage ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() > 0.15
+ },
+ requires: "duplication chance > 15%",
+ effect() {
+ tech.isDupDamage = true;
+ },
+ remove() {
+ tech.isDupDamage = false;
+ }
+ },
+ {
+ name: "parthenogenesis",
+ description: "+8% chance to duplicate spawned power ups duplication also duplicates mobs ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.duplicationChance() > 0// && !tech.isResearchBoss
+ },
+ requires: "some duplication chance",
+ effect() {
+ tech.isDuplicateMobs = true;
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ },
+ remove() {
+ tech.isDuplicateMobs = false;
+ }
+ },
+ {
+ name: "apomixis",
+ description: `when you reach 100% duplication spawn 11 bosses with 100% more durability `,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isNonRefundable: true,
+ allowed() {
+ return tech.duplicationChance() > 0.5
+ },
+ requires: "duplication chance above 50%",
+ effect() {
+ tech.is100Duplicate = true;
+ tech.maxDuplicationEvent()
+ },
+ remove() {
+ tech.is100Duplicate = false;
+ }
+ },
+ {
+ name: "strange attractor",
+ descriptionFunction() {
+ return `+7% damage removing this increases duplication by +10% `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBadRandomOption: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ damage: 1.07,
+ effect() {
+ tech.damage *= this.damage
+ },
+ remove() {
+ if (this.count > 0 && m.alive) {
+ tech.duplication += 0.1
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ tech.damage /= this.damage
+ this.frequency = 0
+ }
+ }
+ },
+ {
+ name: "null hypothesis",
+ description: `+8% damage removing this spawns ${powerUps.orb.research(15)}`,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBadRandomOption: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ damage: 1.08,
+ effect() {
+ tech.damage *= this.damage
+ },
+ remove() {
+ if (this.count > 0 && m.alive) {
+ tech.damage /= this.damage
+ powerUps.spawnDelay("research", 15)
+ this.frequency = 0
+ }
+ }
+ },
+ {
+ name: "Born rule",
+ description: "remove all current tech spawn new tech to replace them",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return (tech.totalCount > 6)
+ },
+ requires: "more than 6 tech",
+ effect() {
+ //remove active bullets //to get rid of bots
+ for (let i = 0; i < bullet.length; ++i) Matter.Composite.remove(engine.world, bullet[i]);
+ bullet = [];
+ let count = 1 //count tech
+ for (let i = 0, len = tech.tech.length; i < len; i++) { // spawn new tech power ups
+ if (!tech.tech[i].isNonRefundable) count += tech.tech[i].count
+ }
+ if (tech.isDeterminism) count -= 4 //remove the bonus tech
+ if (tech.isSuperDeterminism) count -= 4 //remove the bonus tech
+
+ tech.setupAllTech(); // remove all tech
+ if (simulation.isCheating) tech.setCheating();
+ lore.techCount = 0;
+ // tech.addLoreTechToPool();
+ for (let i = 0; i < count; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "tech"); // spawn new tech power ups
+ //have state is checked in m.death()
+ },
+ remove() { }
+ },
+
+ {
+ name: "Occams razor",
+ descriptionFunction() {
+ return `randomly remove half your tech for each removed +${this.damagePerRemoved * 100}% damage (~${(this.count === 0) ? this.damagePerRemoved * 50 * tech.totalCount : this.damage * 100}%) `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return (tech.totalCount > 6)
+ },
+ requires: "more than 6 tech",
+ // removePercent: 0.5,
+ damagePerRemoved: 0.5,
+ damage: null,
+ effect() {
+ let pool = []
+ for (let i = 0, len = tech.tech.length; i < len; i++) { // spawn new tech power ups
+ if (tech.tech[i].count && !tech.tech[i].isNonRefundable && !tech.tech[i].isFromAppliedScience) pool.push(i)
+ }
+ pool = shuffle(pool); //shuffles order of maps
+ let removeCount = 0
+ for (let i = 0, len = pool.length * this.damagePerRemoved; i < len; i++) removeCount += tech.removeTech(pool[i])
+ this.damage = this.damagePerRemoved * removeCount
+ tech.damage *= (1 + this.damage)
+ },
+ remove() {
+ if (this.count) tech.damage /= (1 + this.damage)
+ }
+ },
+ {
+ name: "exchange symmetry",
+ description: "remove 1 random tech spawn 2 new guns ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return (tech.totalCount > 3) && !tech.isSuperDeterminism
+ },
+ requires: "at least 4 tech, not superdeterminism",
+ effect() {
+ const have = [] //find which tech you have
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].count > 0 && !tech.tech[i].isNonRefundable) have.push(i)
+ }
+ const choose = have[Math.floor(Math.random() * have.length)]
+ simulation.makeTextLog(`tech .removeTech("${tech.tech[choose].name} ")`, 360)
+ for (let i = 0; i < tech.tech[choose].count; i++) {
+ powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ }
+ powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ // powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ tech.tech[choose].remove(); // remove a random tech form the list of tech you have
+ // tech.tech[choose].count = 0;
+ tech.tech[choose].isLost = true
+ simulation.updateTechHUD();
+ },
+ remove() { }
+ },
+ {
+ name: "Monte Carlo method",
+ description: "remove 1 random tech spawn 2 tech ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isNonRefundable: true,
+ isBadRandomOption: true,
+ allowed() {
+ return (tech.totalCount > 3) && tech.duplicationChance() > 0 && !tech.isSuperDeterminism
+ },
+ requires: "some duplication, at least 4 tech, not superdeterminism",
+ effect() {
+ const removeTotal = tech.removeTech()
+ for (let i = 0; i < removeTotal + 1; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "tech");
+ },
+ remove() { }
+ },
+ {
+ name: "reinforcement learning",
+ description: "increase the frequency of finding copies of your current tech by 1000% ",
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.totalCount > 9
+ },
+ requires: "at least 10 tech",
+ effect() {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].count > 0) tech.tech[i].frequency *= 10
+ }
+ },
+ remove() {
+ if (this.count) {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].count > 0 && tech.tech[i].frequency > 1) tech.tech[i].frequency /= 10
+ }
+ }
+ }
+ },
+ // {
+ // name: "backward induction",
+ // descriptionFunction() {
+ // if (build.isExperimentSelection || powerUps.tech.choiceLog.length < 10) return `use ${powerUps.orb.research(2)} to choose all the unchosen tech from your last selection`
+
+ // text = ``
+ // let num = 3
+ // if (tech.extraChoices) num = 5
+ // if (tech.isDeterminism) num = 1
+ // for (let i = 0; i < num; i++) {
+ // const index = powerUps.tech.choiceLog[powerUps.tech.choiceLog.length - i - 1]
+ // if (index !== powerUps.lastTechIndex && tech.tech[index].count < tech.tech[index].maxCount && tech.tech[index].allowed() && tech.tech[index].name !== "backward induction") {
+ // text += `${tech.tech[index].name}, `
+ // }
+ // }
+ // text = text.slice(0, -2);
+ // return `use ${powerUps.orb.research(2)}to choose the unchosentech from your previous selection:${text} `
+ // },
+ // // description: `use ${powerUps.orb.research(2)}to choose all the unchosen tech from your previous tech selection`,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 100,
+ // frequencyDefault: 100,
+ // isNonRefundable: true,
+ // isBadRandomOption: true,
+ // allowed() {
+ // return powerUps.tech.choiceLog.length > 10 && !tech.isDeterminism && powerUps.research.count > 1
+ // },
+ // requires: "NOT EXPERIMENT MODE, rejected an option in the last tech selection, at least 2 research, not determinism",
+ // effect: () => {
+ // powerUps.research.changeRerolls(-2)
+ // let num = 3
+ // if (tech.extraChoices) num = 5
+ // if (tech.isDeterminism) num = 1
+ // for (let i = 0; i < num; i++) {
+ // const index = powerUps.tech.choiceLog[powerUps.tech.choiceLog.length - i - 1]
+ // if (index !== powerUps.lastTechIndex && tech.tech[index].count < tech.tech[index].maxCount && tech.tech[index].allowed() && tech.tech[index].name !== "backward induction") {
+ // tech.giveTech(index)
+ // simulation.makeTextLog(`tech .giveTech("${tech.tech[index].name} ") //backward induction `);
+ // }
+ // }
+ // },
+ // remove() {}
+ // },
+ //**************************************************
+ //************************************************** gun
+ //************************************************** tech
+ //**************************************************
+ {
+ name: "needle ice",
+ description: `after needles impact walls they chip off 1-2 freezing ice IX crystals`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isNeedles || tech.isNeedles) && !tech.needleTunnel
+ },
+ requires: "nail gun, needle gun, not nanowires",
+ effect() {
+ tech.isNeedleIce = true
+ },
+ remove() {
+ tech.isNeedleIce = false
+ }
+ },
+ {
+ name: "nanowires",
+ description: `needles tunnel through blocks and map +20% needle damage `,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return ((tech.haveGunCheck("nail gun") && tech.isNeedles) || (tech.isNeedles && tech.haveGunCheck("shotgun"))) && !tech.isNeedleIce
+ },
+ requires: "nail gun, needle gun, not needle ice",
+ effect() {
+ tech.needleTunnel = true
+ },
+ remove() {
+ tech.needleTunnel = false
+ }
+ },
+ {
+ name: "ceramics",
+ description: `needles and harpoons pierce shields directly damaging shielded mobs`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (!tech.isLargeHarpoon && tech.haveGunCheck("harpoon")) || tech.isNeedles
+ },
+ requires: "needle gun, harpoon, not Bessemer process",
+ effect() {
+ tech.isShieldPierce = true
+ },
+ remove() {
+ tech.isShieldPierce = false
+ }
+ },
+ {
+ name: "needle gun",
+ description: "nail gun and shotgun fire mob piercing needles ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.nailRecoil && !tech.isRicochet) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea)) && !tech.isRivets && !tech.isIncendiary && !tech.isIceCrystals && !tech.isIceShot
+ },
+ requires: "nail gun, shotgun, not ice crystal, rivets, rotary cannon, pneumatic, incendiary, nail-shot, foam-shot, worm-shot, ice-shot",
+ effect() {
+ tech.isNeedles = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") {
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo / 3);
+ b.guns[i].ammoPack = Math.ceil(b.guns[i].defaultAmmoPack / 3);
+ b.guns[i].chooseFireMethod()
+ simulation.updateGunHUD();
+ break
+ }
+ }
+ },
+ remove() {
+ if (tech.isNeedles) {
+ tech.isNeedles = false
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") {
+ b.guns[i].chooseFireMethod()
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 3);
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack;
+ simulation.updateGunHUD();
+ break
+ }
+ }
+ }
+ }
+ },
+ {
+ name: "stress concentration",
+ description: "mobs below 50% durability die after you shoot them near their center with needles or rivets ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isNeedles || tech.isRivets) && !tech.isNailCrit && !tech.isIncendiary
+ },
+ requires: "needles, rivets, not incendiary, supercritical fission",
+ effect() {
+ tech.isCritKill = true
+ },
+ remove() {
+ tech.isCritKill = false
+ }
+ },
+ {
+ name: "rivet gun",
+ description: "nail gun and shotgun slowly lob a heavy rivet ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return ((tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.isRicochet) || (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea)) && !tech.isNeedles && !tech.isIceCrystals && !tech.isIceShot
+ },
+ requires: "nail gun, shotgun, not ice crystal, needles, or pneumatic actuator",
+ effect() {
+ tech.isRivets = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") {
+ b.guns[i].chooseFireMethod()
+ break
+ }
+ }
+ },
+ remove() {
+ if (tech.isRivets) {
+ tech.isRivets = false
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") {
+ b.guns[i].chooseFireMethod()
+ break
+ }
+ }
+ }
+ tech.isRivets = false
+ }
+ },
+ {
+ name: "pneumatic actuator",
+ description: "nail gun takes no time to ramp up to its fastest fire rate ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles && !tech.nailRecoil
+ },
+ requires: "nail gun, not rotary cannon, rivets, or needles",
+ effect() {
+ tech.nailInstantFireRate = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
+ }
+ },
+ remove() {
+ if (tech.nailInstantFireRate) {
+ tech.nailInstantFireRate = false
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
+ }
+ }
+ }
+ },
+ {
+ name: "ice crystal nucleation",
+ link: `ice crystal nucleation `,
+ description: "nail gun uses energy to condense unlimited freezing ice shards ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles // && !tech.isNailRadiation && !tech.isNailCrit
+ },
+ requires: "nail gun, not rivets, needles",
+ effect() {
+ tech.isIceCrystals = true;
+ b.guns[0].ammoPack = Infinity
+ b.guns[0].recordedAmmo = b.guns[i].ammo
+ b.guns[0].ammo = Infinity
+ simulation.updateGunHUD();
+ },
+ remove() {
+ if (tech.isIceCrystals) {
+ tech.isIceCrystals = false;
+ b.guns[0].ammoPack = b.guns[0].defaultAmmoPack;
+ if (b.guns[0].recordedAmmo) b.guns[0].ammo = b.guns[0].recordedAmmo
+ simulation.updateGunHUD();
+ }
+ tech.isIceCrystals = false;
+ if (b.guns[0].ammo === Infinity) b.guns[0].ammo = 0
+ }
+ },
+ {
+ name: "rotary cannon",
+ description: "nail gun has increased muzzle speed , maximum fire rate , accuracy , and recoil ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("nail gun") && !tech.nailInstantFireRate && !tech.isNeedles
+ },
+ requires: "nail gun, not pneumatic actuator, needle gun",
+ effect() {
+ tech.nailRecoil = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
+ }
+ },
+ remove() {
+ if (tech.nailRecoil) {
+ tech.nailRecoil = false
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
+ }
+ }
+ }
+ },
+ {
+ name: "gauge",
+ description: `rivets , needles , super balls , and nails have +30% mass and physical damage `,
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !tech.isFoamMine) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1
+ },
+ requires: "nails, nail gun, rivets, shotgun, super balls, mine",
+ effect() {
+ tech.bulletSize = 1 + 0.25 * Math.pow(this.count + 1, 0.5)
+ },
+ remove() {
+ tech.bulletSize = 1;
+ }
+ },
+ {
+ name: "supercritical fission",
+ description: "if nails , needles , or rivets strike mobs near their center they can explode ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isNailShot || tech.isNeedles || tech.isNailBotUpgrade || tech.haveGunCheck("nail gun") || tech.isRivets || (tech.haveGunCheck("mine") && !(tech.isFoamMine || tech.isSuperMine))) && !tech.isIncendiary && !tech.isCritKill
+ },
+ requires: "nail gun, mine, needles, nails, rivets, not incendiary, stress concentration",
+ effect() {
+ tech.isNailCrit = true
+ },
+ remove() {
+ tech.isNailCrit = false
+ }
+ },
+ {
+ name: "irradiated nails",
+ link: `irradiated nails `,
+ description: "nails , needles , and rivets are radioactive +90% radioactive damage over 3 seconds",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isShieldPierce) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot))
+ },
+ requires: "nail gun, nails, rivets, mine, not ceramic needles",
+ effect() {
+ tech.isNailRadiation = true;
+ },
+ remove() {
+ tech.isNailRadiation = false;
+ }
+ },
+ {
+ name: "6s half-life",
+ link: `6s half-life `,
+ description: "nails , needles , rivets are made of plutonium-238 radioactive damage lasts +3 seconds",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNailRadiation && !tech.isFastRadiation
+ },
+ requires: "nail gun, mine, irradiated nails, not 1s half-life",
+ effect() {
+ tech.isSlowRadiation = true;
+ },
+ remove() {
+ tech.isSlowRadiation = false;
+ }
+ },
+ {
+ name: "1s half-life",
+ link: `1s half-life `,
+ description: "nails , needles , rivets are made of lithium-8 +300% radioactive damage for 1 second ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNailRadiation && !tech.isSlowRadiation
+ },
+ requires: "nail gun, mine, irradiated nails, not 6s half-life",
+ effect() {
+ tech.isFastRadiation = true;
+ },
+ remove() {
+ tech.isFastRadiation = false;
+ }
+ },
+ {
+ name: "spin-statistics",
+ link: `spin-statistics `,
+ description: "after firing the shotgun you are invulnerable shotgun has 50% fewer shots",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("shotgun")
+ },
+ requires: "shotgun",
+ effect() {
+ tech.isShotgunImmune = true;
+
+ //cut current ammo by 1/2
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "shotgun") {
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 0.5);
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * 0.5
+ break;
+ }
+ }
+ simulation.updateGunHUD();
+ },
+ remove() {
+ if (tech.isShotgunImmune) {
+ tech.isShotgunImmune = false;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "shotgun") {
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack;
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 2);
+ break;
+ }
+ }
+ simulation.updateGunHUD();
+ }
+ }
+ },
+ {
+ name: "Newtons 3rd law",
+ description: "+66% shotgun fire rate and recoil ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("shotgun") && !tech.isShotgunReversed
+ },
+ requires: "shotgun, not Noether violation",
+ effect() {
+ tech.isShotgunRecoil = true;
+ },
+ remove() {
+ tech.isShotgunRecoil = false;
+ }
+ },
+ {
+ name: "Noether violation",
+ link: `Noether violation `,
+ description: "+50% shotgun damage shotgun recoil is reversed ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("shotgun")) && !tech.isShotgunRecoil
+ },
+ requires: "shotgun, not Newtons 3rd law",
+ effect() {
+ tech.isShotgunReversed = true;
+ },
+ remove() {
+ tech.isShotgunReversed = false;
+ }
+ },
+ {
+ name: "repeater",
+ description: "shotgun immediately fires again for no ammo -50% shotgun fire rate ",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("shotgun"))
+ },
+ requires: "shotgun, not Newtons 3rd law",
+ effect() {
+ tech.shotgunExtraShots++;
+ },
+ remove() {
+ tech.shotgunExtraShots = 0
+ }
+ },
+ {
+ name: "nail-shot",
+ link: `nail-shot `,
+ description: "shotgun drives a long clip of nails ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles
+ },
+ requires: "shotgun, not incendiary, rivets, foam-shot, worm-shot, ice-shot, needles",
+ effect() {
+ tech.isNailShot = true;
+ },
+ remove() {
+ tech.isNailShot = false;
+ }
+ },
+ {
+ name: "foam-shot",
+ link: `foam-shot `,
+ description: "shotgun sprays sticky foam bubbles",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles
+ },
+ requires: "shotgun, not incendiary, nail-shot, rivet, worm-shot, ice-shot, needle",
+ effect() {
+ tech.isFoamShot = true;
+ },
+ remove() {
+ tech.isFoamShot = false;
+ }
+ },
+ {
+ name: "ice-shot",
+ link: `ice-shot `,
+ description: "shotgun grows freezing ice IX crystals",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIncendiary && !tech.isRivets && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles
+ },
+ requires: "shotgun, not incendiary, nail-shot, rivet, foam-shot, worm-shot",
+ effect() {
+ tech.isIceShot = true;
+ },
+ remove() {
+ tech.isIceShot = false;
+ }
+ },
+ {
+ name: "freezer burn",
+ description: "mobs frozen while below 33% durability die ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isIceShot || tech.relayIce || tech.isNeedleIce || (m.coupling && (m.fieldMode === 3 || m.fieldMode === 0))
+ },
+ requires: "a freeze effect",
+ effect() {
+ tech.isIceKill = true
+ },
+ remove() {
+ tech.isIceKill = false
+ }
+ },
+ {
+ name: "flash freeze",
+ description: "mobs frozen while above 66% durability have their durability reduced to 66% ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isIceShot || tech.relayIce || tech.isNeedleIce || (m.coupling && (m.fieldMode === 3 || m.fieldMode === 0))
+ },
+ requires: "a freeze effect",
+ effect() {
+ tech.isIceMaxHealthLoss = true
+ },
+ remove() {
+ tech.isIceMaxHealthLoss = false
+ }
+ },
+ {
+ name: "crystallizer",
+ description: "after frozen mobs die they shatter into ice IX crystals",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.isIceShot || tech.relayIce || tech.isNeedleIce || (m.coupling && (m.fieldMode === 3 || m.fieldMode === 0))) && !tech.sporesOnDeath && !tech.isExplodeMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.nailsDeathMob
+ },
+ requires: "a localized freeze effect, no other mob death tech",
+ effect() {
+ tech.iceIXOnDeath++
+ },
+ remove() {
+ tech.iceIXOnDeath = 0
+ }
+ },
+ {
+ name: "thermoelectric effect",
+ description: "after killing mobs with ice IX +100 energy ",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.relayIce || tech.isNeedleIce || (m.coupling && (m.fieldMode === 3 || m.fieldMode === 0)) || tech.iceIXOnDeath || tech.isIceShot
+ },
+ requires: "ice IX",
+ effect() {
+ tech.iceEnergy++
+ },
+ remove() {
+ tech.iceEnergy = 0;
+ }
+ },
+ {
+ name: "superfluidity",
+ description: "freeze effects are applied to a small area around the target",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isIceCrystals || tech.isSporeFreeze || (m.fieldMode === 4 && simulation.molecularMode === 2) || tech.relayIce || tech.isNeedleIce || (m.coupling && (m.fieldMode === 3 || m.fieldMode === 0)) || tech.iceIXOnDeath || tech.isIceShot
+ },
+ requires: "a localized freeze effect",
+ effect() {
+ tech.isAoESlow = true
+ },
+ remove() {
+ tech.isAoESlow = false
+ }
+ },
+ {
+ name: "incendiary ammunition",
+ description: "shotgun , rivets , super balls , and drones are loaded with explosives ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("shotgun") && !tech.isNailShot && !tech.isIceShot && !tech.isRivets && !tech.isFoamShot && !tech.isSporeWorm && !tech.isSporeFlea && !tech.isNeedles) || ((tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isSuperBounce && !tech.isFoamBall && !tech.isSuperHarm) || (tech.isRivets && !tech.isNailCrit) || (m.fieldMode === 4 && simulation.molecularMode === 3) || (tech.haveGunCheck("drones") && !tech.isForeverDrones && !tech.isDroneRadioactive && !tech.isDroneTeleport)
+ },
+ requires: "shotgun, super balls, rivets, drones, not irradiated drones, burst drones, polyurethane, Zectron",
+ effect() {
+ tech.isIncendiary = true
+ },
+ remove() {
+ tech.isIncendiary = false;
+ }
+ },
+ {
+ name: "rebound",
+ description: `after they collide with a mob, super balls gain speed , duration , and +33% damage `,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isIncendiary && !tech.isFoamBall
+ },
+ requires: "super balls, not incendiary",
+ effect() {
+ tech.isSuperBounce = true
+ },
+ remove() {
+ tech.isSuperBounce = false
+ }
+ },
+ {
+ name: "Zectron",
+ description: `+75% super ball density and damage , but after colliding with super balls -25% energy `,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isIncendiary && !tech.isBulletTeleport
+ },
+ requires: "super balls not incendiary ammunition, uncertainty principle",
+ effect() {
+ tech.isSuperHarm = true
+ },
+ remove() {
+ tech.isSuperHarm = false
+ }
+ },
+ {
+ name: "polyurethane foam",
+ description: "super balls and harpoons colliding with mobs catalyzes a reaction that yields foam bubbles",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return ((tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.isSuperBounce) || (tech.haveGunCheck("harpoon") && !tech.fragments)
+ },
+ requires: "super balls, harpoon, not fragmentation",
+ effect() {
+ tech.isFoamBall = true;
+ },
+ remove() {
+ tech.isFoamBall = false;
+ }
+ },
+ {
+ name: "autocannon",
+ description: "fire +1 extra super ball balls are quickly released in same direction",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("super balls") && !tech.oneSuperBall
+ },
+ requires: "super balls, but not the tech super ball",
+ effect() {
+ tech.superBallDelay = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
+ }
+ },
+ remove() {
+ if (tech.superBallDelay) {
+ tech.superBallDelay = false;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
+ }
+ }
+ }
+ },
+ {
+ name: "super duper",
+ description: `randomly fire +0 , +1 , +2 , or +3 extra super balls `,
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.oneSuperBall
+ },
+ requires: "super balls, not super ball",
+ effect() {
+ tech.extraSuperBalls += 4
+ },
+ remove() {
+ tech.extraSuperBalls = 0;
+ }
+ },
+ {
+ name: "super ball",
+ description: "fire just 1 large super ball that stuns mobs for 2 second",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("super balls") || tech.isSuperMine) && !tech.extraSuperBalls && !tech.superBallDelay
+ },
+ requires: "super balls, not super duper or autocannon",
+ effect() {
+ tech.oneSuperBall = true;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
+ }
+ },
+ remove() {
+ if (tech.oneSuperBall) {
+ tech.oneSuperBall = false;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "super balls") b.guns[i].chooseFireMethod()
+ }
+ }
+ }
+ },
+ {
+ name: "phase velocity",
+ description: "wave particles propagate faster as solids +40% wave damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("wave") && !tech.isLongitudinal
+ },
+ requires: "wave, not phonon",
+ effect() {
+ tech.isPhaseVelocity = true;
+ },
+ remove() {
+ tech.isPhaseVelocity = false;
+ }
+ },
+ {
+ name: "amplitude",
+ description: "+37% wave damage +37% wave particle amplitude ",
+ isGunTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("wave") || tech.isSoundBotUpgrade
+ },
+ requires: "wave",
+ effect() {
+ tech.waveFrequency *= 0.66
+ tech.wavePacketDamage *= 1.37
+ },
+ remove() {
+ tech.waveFrequency = 0.2
+ tech.wavePacketDamage = 1
+ }
+ },
+ {
+ name: "propagation",
+ description: "–25% wave packet propagation speed +41% wave damage ",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("wave") || tech.isSoundBotUpgrade
+ },
+ requires: "wave",
+ effect() {
+ tech.waveBeamSpeed *= 0.75;
+ tech.waveBeamDamage += 0.27 * 0.41 //this sets base wave damage
+ },
+ remove() {
+ tech.waveBeamSpeed = 11;
+ tech.waveBeamDamage = 0.27 //this sets base wave damage
+ }
+ },
+ {
+ name: "bound state",
+ description: "wave packets reflect backwards 2 times–33% range ",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("wave") && !tech.isLongitudinal
+ },
+ requires: "wave, not phonon",
+ effect() {
+ tech.waveReflections += 2
+ },
+ remove() {
+ tech.waveReflections = 1
+ }
+ },
+ {
+ name: "frequency",
+ description: `wave has unlimited ammo -25% wave damage `,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed: () => tech.haveGunCheck("wave"),
+ requires: "wave",
+ effect() {
+ tech.isInfiniteWaveAmmo = true
+ b.guns[3].savedAmmo = b.guns[3].ammo
+ b.guns[3].ammo = Infinity
+ simulation.updateGunHUD();
+ },
+ remove() {
+ tech.isInfiniteWaveAmmo = false
+ if (this.count > 0 && b.guns[3].savedAmmo !== undefined) {
+ b.guns[3].ammo = b.guns[3].savedAmmo
+ simulation.updateGunHUD();
+ } else if (b.guns[3].ammo === Infinity) {
+ b.guns[3].ammo = 0
+ }
+ }
+ },
+ {
+ name: "phonon", //longitudinal //gravitational wave?
+ description: "waves are low frequency , high damage expanding arcs that propagate through solids ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.haveGunCheck("wave") && !tech.isPhaseVelocity && tech.waveReflections === 1
+ },
+ requires: "wave, not phase velocity, bound state",
+ ammoScale: 6,
+ effect() {
+ tech.isLongitudinal = true;
+ b.guns[3].chooseFireMethod()
+ b.guns[3].ammoPack = b.guns[3].defaultAmmoPack / this.ammoScale
+ if (tech.isInfiniteWaveAmmo) {
+ b.guns[3].savedAmmo = Math.ceil(b.guns[3].savedAmmo / this.ammoScale); //used with low frequency
+ } else {
+ b.guns[3].ammo = Math.ceil(b.guns[3].ammo / this.ammoScale);
+ }
+ simulation.updateGunHUD();
+ },
+ remove() {
+ if (tech.isLongitudinal) {
+ tech.isLongitudinal = false;
+ b.guns[3].chooseFireMethod()
+ b.guns[3].ammoPack = b.guns[3].defaultAmmoPack
+ if (tech.isInfiniteWaveAmmo) {
+ b.guns[3].savedAmmo = Math.ceil(b.guns[3].savedAmmo * this.ammoScale); //used with low frequency
+ } else {
+ b.guns[3].ammo = Math.ceil(b.guns[3].ammo * this.ammoScale);
+ }
+ simulation.updateGunHUD();
+ }
+ tech.isLongitudinal = false;
+ }
+ },
+ {
+ name: "isotropic",
+ description: "waves expand in all directions–40% range and +50% damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return tech.isLongitudinal && tech.haveGunCheck("wave") && !tech.isBulletTeleport
+ },
+ requires: "wave, phonon, not uncertainty principle",
+ effect() {
+ tech.is360Longitudinal = true;
+ b.guns[3].chooseFireMethod()
+ },
+ remove() {
+ tech.is360Longitudinal = false;
+ b.guns[3].chooseFireMethod()
+ }
+ },
+ {
+ name: "mechanical resonance",
+ description: "after a block gets vibrated by a phonon there is a chance it's flung at nearby mobs",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isLongitudinal && tech.haveGunCheck("wave")) || tech.isSoundBotUpgrade
+ },
+ requires: "wave, phonon",
+ effect() {
+ tech.isPhononBlock = true
+ },
+ remove() {
+ tech.isPhononBlock = false
+ }
+ },
+ {
+ name: "sympathetic resonance",
+ description: "after a mob gets vibrated by a phonon a new resonance wave expands",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isLongitudinal && tech.haveGunCheck("wave")) || tech.isSoundBotUpgrade
+ },
+ requires: "wave, phonon",
+ effect() {
+ tech.isPhononWave = true
+ },
+ remove() {
+ tech.isPhononWave = false
+ }
+ },
+ {
+ name: "cruise missile",
+ description: "+100% missile explosive damage , radius–50% missile speed",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("missiles") && tech.missileFireCD === 45) || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount
+ },
+ requires: "missiles, not launch system",
+ effect() {
+ tech.isMissileBig = true
+ },
+ remove() {
+ tech.isMissileBig = false
+ }
+ },
+ {
+ name: "ICBM",
+ description: "+75% missile explosive damage , radius–50% missile speed",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1)) && tech.isMissileBig
+ },
+ requires: "missiles, cruise missile",
+ effect() {
+ tech.isMissileBiggest = true
+ },
+ remove() {
+ tech.isMissileBiggest = false
+ }
+ },
+ {
+ name: "launch system",
+ description: `+500% missile gun fire rate +20% missile ammo per ${powerUps.orb.ammo(1)}`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("missiles") && !tech.isMissileBig
+ },
+ requires: "missiles, not cruise missile",
+ ammoBonus: 1.2,
+ effect() {
+ tech.missileFireCD = 10
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "missiles") {
+ b.guns[i].ammoPack *= this.ammoBonus;
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * this.ammoBonus);
+ simulation.updateGunHUD();
+ break
+ }
+ }
+ },
+ remove() {
+ if (tech.missileFireCD !== 45) {
+ tech.missileFireCD = 45;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "missiles") {
+ b.guns[i].ammoPack = 5;
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo / this.ammoBonus);
+ simulation.updateGunHUD();
+ break
+ }
+ }
+ }
+ }
+ },
+ {
+ name: "missile-bot",
+ link: `missile-bot `,
+ description: `use ${powerUps.orb.research(1)}to trade your missile gun for a bot that fires missiles `,
+ isGunTech: true,
+ isRemoveGun: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return tech.haveGunCheck("missiles", false) && tech.missileFireCD === 45 && (build.isExperimentSelection || powerUps.research.count > 0)
+ },
+ requires: "missiles, not launch system",
+ effect() {
+ tech.missileBotCount++;
+ b.missileBot();
+ if (tech.haveGunCheck("missiles", false)) b.removeGun("missiles") //remove your last gun
+ for (let i = 0; i < 1; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ if (this.count) {
+ tech.missileBotCount = 0;
+ b.clearPermanentBots();
+ b.respawnBots();
+ if (!tech.haveGunCheck("missiles", false)) b.giveGuns("missiles")
+ powerUps.research.changeRerolls(1)
+ }
+ }
+ },
+ {
+ name: "iridium-192",
+ description: "explosions release gamma radiation +100% explosion damage over 4 seconds",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isImmuneExplosion && tech.explosiveRadius === 1 && !tech.isSmallExplosion && !tech.isBlockExplode && !tech.fragments && (tech.haveGunCheck("missiles") || tech.missileBotCount || tech.isIncendiary || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.isPulseLaser || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.isBoomBotUpgrade || tech.isTokamak)
+ },
+ requires: "an explosive damage source, not ammonium nitrate, nitroglycerin, chain reaction, fragmentation, electric armor",
+ effect() {
+ tech.isExplodeRadio = true; //iridium-192
+ },
+ remove() {
+ tech.isExplodeRadio = false;
+ }
+ },
+ {
+ name: "fragmentation",
+ description: "some detonations and collisions eject nails blocks, grenades, missiles, rivets, harpoon ",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return !tech.isExplodeRadio && ((tech.haveGunCheck("harpoon") && !tech.isFoamBall) || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb) || tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount || tech.isRivets || tech.blockDamage > 0.075)
+ },
+ requires: "grenades, missiles, rivets, harpoon, or mass driver, not iridium-192, not polyurethane foam",
+ effect() {
+ tech.fragments++
+ },
+ remove() {
+ tech.fragments = 0
+ }
+ },
+ {
+ name: "ammonium nitrate",
+ description: "+24% explosive damage , radius",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
+ },
+ requires: "an explosive damage source, not iridium-192",
+ effect() {
+ tech.explosiveRadius += 0.24;
+ },
+ remove() {
+ tech.explosiveRadius = 1;
+ }
+ },
+ {
+ name: "nitroglycerin",
+ description: "+66% explosive damage –33% explosive radius ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isExplodeRadio && tech.hasExplosiveDamageCheck() && !tech.isExplosionHarm
+ },
+ requires: "an explosive damage source, not iridium-192, acetone peroxide",
+ effect() {
+ tech.isSmallExplosion = true;
+ },
+ remove() {
+ tech.isSmallExplosion = false;
+ }
+ },
+ {
+ name: "acetone peroxide",
+ description: "+70% explosive radius –33% explosive defense ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isBadRandomOption: true,
+ allowed() {
+ return tech.hasExplosiveDamageCheck() && !tech.isSmallExplosion
+ },
+ requires: "an explosive damage source, not nitroglycerin",
+ effect() {
+ tech.isExplosionHarm = true;
+ },
+ remove() {
+ tech.isExplosionHarm = false;
+ }
+ },
+ {
+ name: "shock wave",
+ description: "mines and sporangium stun for 3-5 secondsexplosions stun for 0.5 seconds",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.haveGunCheck("spores") || tech.haveGunCheck("mine") || (!tech.isExplodeRadio && tech.hasExplosiveDamageCheck())
+ },
+ requires: "mine, spores, an explosive damage source, not iridium-192",
+ effect() {
+ tech.isStun = true;
+ },
+ remove() {
+ tech.isStun = false;
+ }
+ },
+ {
+ name: "shaped charge",
+ description: `use ${powerUps.orb.research(3)} to dynamically reduce all explosions to prevent health loss`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isImmuneExplosion && (build.isExperimentSelection || powerUps.research.count > 2) && (tech.haveGunCheck("missiles") || (m.fieldMode === 4 && simulation.molecularMode === 1) || tech.missileBotCount > 0 || tech.isIncendiary || tech.isPulseLaser || tech.isTokamak || (tech.haveGunCheck("grenades") && !tech.isNeutronBomb))
+ },
+ requires: "an explosive damage source, not rocket propelled grenade",
+ effect() {
+ tech.isSmartRadius = true;
+ for (let i = 0; i < 3; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isSmartRadius = false;
+ if (this.count > 0) powerUps.research.changeRerolls(3)
+ }
+ },
+ // {
+ // name: "electric armor",
+ // // description: "explosions do no defense while your energy is above 98% ",
+ // description: "instead of causing health loss, explosions drain 12 energy and have more knockback",
+ // isGunTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return !tech.isSmartRadius && !tech.isExplodeRadio && tech.hasExplosiveDamageCheck()
+ // },
+ // requires: "an explosive damage source, not iridium-192",
+ // effect() {
+ // tech.isImmuneExplosion = true;
+ // },
+ // remove() {
+ // tech.isImmuneExplosion = false;
+ // }
+ // },
+ {
+ name: "MIRV",
+ description: "fire +1 missile or grenade per shot–12% explosion damage and radius ",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("missiles") || tech.missileBotCount || tech.haveGunCheck("grenades")
+ },
+ requires: "missiles, grenades",
+ effect() {
+ tech.missileCount++;
+ },
+ remove() {
+ tech.missileCount = 1;
+ }
+ },
+ {
+ name: "rocket-propelled grenade",
+ description: "grenades explode on map collisions explosions drain energy , not health ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isVacuumBomb
+ },
+ requires: "grenades, not vacuum bomb",
+ effect() {
+ tech.isImmuneExplosion = true;
+ tech.isRPG = true;
+ b.setGrenadeMode()
+ },
+ remove() {
+ tech.isImmuneExplosion = false;
+ tech.isRPG = false;
+ b.setGrenadeMode()
+ }
+ },
+ {
+ name: "vacuum bomb",
+ description: "grenades fire slower, explode bigger, and suck everything towards them",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isBlockExplode && !tech.isRPG
+ },
+ requires: "grenades, not neutron bomb, chain reaction, RPG",
+ effect() {
+ tech.isVacuumBomb = true;
+ b.setGrenadeMode()
+ },
+ remove() {
+ tech.isVacuumBomb = false;
+ b.setGrenadeMode()
+ }
+ },
+ {
+ name: "chain reaction",
+ description: "+33% grenade radius and damage blocks caught in explosions also explode ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isExplodeRadio && !tech.isNeutronBomb && !tech.isVacuumBomb
+ },
+ requires: "grenades, not iridium-192, neutron bomb, vacuum bomb",
+ effect() {
+ tech.isBlockExplode = true; //chain reaction
+ },
+ remove() {
+ tech.isBlockExplode = false;
+ }
+ },
+ {
+ name: "flame test",
+ description: "after grenades detonate they release a colorful cluster of small explosions ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isCircleExplode && !tech.isPetalsExplode
+ },
+ requires: "grenades, not neutron bomb, pyrotechnics, fireworks",
+ effect() {
+ tech.isClusterExplode = true;
+ },
+ remove() {
+ tech.isClusterExplode = false;
+ }
+ },
+ {
+ name: "pyrotechnics",
+ description: "after grenades detonate they release a colorful circle of explosions ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isClusterExplode && !tech.isPetalsExplode
+ },
+ requires: "grenades, not neutron bomb, flame test, fireworks",
+ effect() {
+ tech.isCircleExplode = true;
+ },
+ remove() {
+ tech.isCircleExplode = false;
+ }
+ },
+ {
+ name: "fireworks",
+ description: "after grenades detonate they release colorful petals of explosions ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.isNeutronBomb && !tech.isClusterExplode && !tech.isCircleExplode
+ },
+ requires: "grenades, not neutron bomb, pyrotechnics, flame test",
+ effect() {
+ tech.isPetalsExplode = true;
+ },
+ remove() {
+ tech.isPetalsExplode = false;
+ }
+ },
+ {
+ name: "neutron bomb",
+ description: "grenades are irradiated with Cf-252 does radioactive damage over time",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("grenades") && !tech.fragments && !tech.isVacuumBomb && !tech.isExplodeRadio && !tech.isBlockExplode && !tech.isClusterExplode && !tech.isPetalsExplode && !tech.isCircleExplode
+ },
+ requires: "grenades, not fragmentation, vacuum bomb, iridium-192, pyrotechnics, fireworks, flame test, chain reaction",
+ effect() {
+ tech.isNeutronBomb = true;
+ b.setGrenadeMode()
+ },
+ remove() {
+ tech.isNeutronBomb = false;
+ b.setGrenadeMode()
+ }
+ },
+ {
+ name: "vacuum permittivity",
+ description: "+20% radioactive range objects in range of the bomb are slowed ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNeutronBomb
+ },
+ requires: "grenades, neutron bomb",
+ effect() {
+ tech.isNeutronSlow = true
+ },
+ remove() {
+ tech.isNeutronSlow = false
+ }
+ },
+ {
+ name: "radioactive contamination",
+ description: "after a mob or shield dies , leftover radiation spreads to a nearby mob",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNailRadiation || tech.isWormholeDamage || tech.isNeutronBomb || tech.isExplodeRadio || tech.isBlockRadiation
+ },
+ requires: "radiation damage source",
+ effect() {
+ tech.isRadioactive = true
+ },
+ remove() {
+ tech.isRadioactive = false
+ }
+ },
+ {
+ name: "nuclear transmutation",
+ description: "+47% radiation damage nail, drone, neutron bomb, iridium, cosmic string, deflect ",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNailRadiation || tech.isWormholeDamage || tech.isNeutronBomb || tech.isExplodeRadio || tech.isBlockRadiation || tech.isDroneRadioactive
+ },
+ requires: "radiation damage source",
+ effect() {
+ tech.radioactiveDamage += 1.47
+ },
+ remove() {
+ tech.radioactiveDamage = 1
+ }
+ },
+ {
+ name: "water shielding",
+ link: `water shielding `,
+ description: "radioactive effects on you are reduced by 75%neutron bomb, drones, explosions, slime ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isNeutronBomb || tech.isDroneRadioactive || tech.isExplodeRadio
+ },
+ requires: "neutron bomb, irradiated drones, iridium-192",
+ effect() {
+ tech.isRadioactiveResistance = true
+ },
+ remove() {
+ tech.isRadioactiveResistance = false
+ }
+ },
+ {
+ name: "ricochet",
+ description: "after nails hit a mob they rebound towards a new mob with +180% damage per bounce",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ // return (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("mines"))
+ return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine || tech.isSuperMine)) || (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot) && !tech.isRivets && !tech.isNeedles)
+ },
+ //
+ requires: "nail gun, not rotary cannon, rivets, or needles",
+ effect() {
+ tech.isRicochet = true
+ },
+ remove() {
+ tech.isRicochet = false
+ }
+ },
+ {
+ name: "booby trap",
+ description: "50% chance to drop a mine from power ups +36% JUNK to tech pool",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine")
+ },
+ requires: "mines",
+ effect() {
+ tech.isMineDrop = true;
+ if (tech.isMineDrop) b.mine(m.pos, {
+ x: 0,
+ y: 0
+ }, 0)
+ this.refundAmount += tech.addJunkTechToPool(0.36)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.isMineDrop = false;
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ {
+ name: "elephants toothpaste",
+ description: "instead of nails mines catalyze a reaction that yields foam bubbles",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine") && !tech.isSuperMine && !tech.isRicochet && !tech.isNailRadiation && !tech.isNailCrit
+ },
+ requires: "mines, not blast ball, ricochet, irradiated nails, supercritical fission",
+ effect() {
+ tech.isFoamMine = true;
+ },
+ remove() {
+ tech.isFoamMine = false;
+ }
+ },
+ {
+ name: "blast ball",
+ descriptionFunction() {
+ return `instead of nails mines fire bouncy balls `
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine") && !tech.isFoamMine && !tech.isRicochet && !tech.isNailRadiation && !tech.isNailCrit
+ },
+ requires: "mines, not elephants toothpaste, ricochet, irradiated nails, supercritical fission",
+ effect() {
+ tech.isSuperMine = true;
+ },
+ remove() {
+ tech.isSuperMine = false;
+ }
+ },
+ {
+ name: "laser-mines",
+ link: `laser-mines `,
+ description: "mines laid while you are crouched use energy to emit 3 unaimed lasers ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine")
+ },
+ requires: "mines",
+ effect() {
+ tech.isLaserMine = true;
+ },
+ remove() {
+ tech.isLaserMine = false;
+ }
+ },
+ {
+ name: "sentry",
+ descriptionFunction() {
+ return `mines fire one ${b.guns[10].nameString()} at a timemines fire 50% more ${b.guns[10].nameString('s')}`
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine")
+ },
+ requires: "mines, not elephants toothpaste",
+ effect() {
+ tech.isMineSentry = true;
+ },
+ remove() {
+ tech.isMineSentry = false;
+ }
+ },
+ {
+ name: "extended magazine",
+ descriptionFunction() {
+ return `sentry mines fire 50% more ${b.guns[10].nameString('s')}`
+ },
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("mine") && tech.isMineSentry
+ },
+ requires: "mines, sentry",
+ effect() {
+ tech.sentryAmmo += 17;
+ },
+ remove() {
+ tech.sentryAmmo = 33;
+ }
+ },
+ {
+ name: "mycelial fragmentation",
+ link: `mycelial fragmentation `,
+ description: "during their growth phase+70% sporangium discharge",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores")
+ },
+ requires: "spores",
+ effect() {
+ tech.isSporeGrowth = true
+ },
+ remove() {
+ tech.isSporeGrowth = false
+ }
+ },
+ {
+ name: "cordyceps",
+ // descriptionFunction() {
+ // return `mobs infected by ${b.guns[6].nameString('s')} have a 5% chance to resurrect and attack other mobs`
+ // },
+ description: "sporangium infect mobs they attach toinfected mobs resurrect and attack other mobs",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores")
+ },
+ requires: "spores",
+ effect() {
+ tech.isZombieMobs = true
+ },
+ remove() {
+ tech.isZombieMobs = false
+ }
+ },
+ {
+ name: "colony",
+ description: "+50% sporangium discharge40% chance to discharge something different",
+ link: `colony `,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores")
+ },
+ requires: "spores",
+ effect() {
+ tech.isSporeColony = true
+ },
+ remove() {
+ tech.isSporeColony = false
+ }
+ },
+ {
+ name: "cryodesiccation",
+ descriptionFunction() {
+ return `+25% sporangium discharge ${b.guns[6].nameString('s')} freeze mobs for 1.5 second`
+ },
+ // description: "+25% sporangium dischargespores freeze mobs for 1.5 second",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldMode === 4 && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
+ },
+ requires: "spores",
+ effect() {
+ tech.isSporeFreeze = true
+ },
+ remove() {
+ tech.isSporeFreeze = false
+ }
+ },
+ {
+ name: "flagella",
+ descriptionFunction() {
+ return `+50% ${b.guns[6].nameString()} acceleration if they can't find a target ${b.guns[6].nameString('s')} follow you`
+ },
+ // description: "+50% spore acceleration if they can't find a target spores follow you",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldMode === 4 && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
+ },
+ requires: "spores",
+ effect() {
+ tech.isSporeFollow = true
+ },
+ remove() {
+ tech.isSporeFollow = false
+ }
+ },
+ {
+ name: "junk DNA",
+ descriptionFunction() {
+ return `+53% ${b.guns[6].nameString()} damage per JUNK tech (${(53 * tech.junkCount).toFixed(0)}%) +50% JUNK to tech pool`
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldMode === 4 && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
+ },
+ requires: "spores",
+ effect() {
+ tech.isJunkDNA = true
+ this.refundAmount += tech.addJunkTechToPool(0.5)
+ },
+ refundAmount: 0,
+ remove() {
+ tech.isJunkDNA = false
+ if (this.count > 0 && this.refundAmount > 0) {
+ tech.removeJunkTechFromPool(this.refundAmount)
+ this.refundAmount = 0
+ }
+ }
+ },
+ // {
+ // name: "junk DNA",
+ // //increase damage by 10% for each JUNK tech percent in the tech pool, remove all JUNK tech,
+ // descriptionFunction() { return `+50% ${b.guns[6].nameString()} damage +15% JUNK to tech pool` },
+ // isGunTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 3,
+ // frequencyDefault: 3,
+ // allowed() {
+ // return tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldMode === 4 && simulation.molecularMode === 0) || tech.isSporeWorm || tech.isSporeFlea
+ // },
+ // requires: "spores",
+ // effect() {
+ // tech.isSporeWorm = true
+ // this.refundAmount += tech.addJunkTechToPool(0.15)
+ // },
+ // refundAmount: 0,
+ // remove() {
+ // tech.isSporeWorm = false
+ // if (this.count > 0 && this.refundAmount > 0) {
+ // tech.removeJunkTechFromPool(this.refundAmount)
+ // this.refundAmount = 0
+ // }
+ // }
+ // },
+ {
+ name: "mutualism",
+ descriptionFunction() {
+ return `+200% ${b.guns[6].nameString()} damage ${b.guns[6].nameString('s')} borrow 1 health until they die `
+ },
+ // description: `+150% ${b.guns[6].name()} damage spores borrow 0.5 health until they die `,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldMode === 4 && simulation.molecularMode === 0)) || tech.isSporeWorm || tech.isSporeFlea
+ },
+ requires: "spores",
+ effect() {
+ tech.isMutualism = true
+ },
+ remove() {
+ tech.isMutualism = false
+ }
+ },
+ {
+ name: "necrophage",
+ description: "if foam , fleas , or worms kill their target they grow 3 copies ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam") || tech.isFoamBall || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isSporeWorm || tech.isSporeFlea || tech.isFoamMine
+ },
+ requires: "foam, spores, worms, fleas",
+ effect() {
+ tech.isSpawnBulletsOnDeath = true
+ },
+ remove() {
+ tech.isSpawnBulletsOnDeath = false;
+ }
+ },
+ {
+ name: "siphonaptera",
+ description: "spores metamorphose into fleas ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldMode === 4 && simulation.molecularMode === 0) || (tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedles && !tech.isNailShot)) && !tech.isSporeWorm
+ },
+ requires: "spores, not worms",
+ effect() {
+ tech.isSporeFlea = true
+ },
+ remove() {
+ tech.isSporeFlea = false
+
+ }
+ },
+ {
+ name: "nematodes",
+ description: "spores metamorphose into worms ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.haveGunCheck("spores") || tech.sporesOnDeath > 0 || (m.fieldMode === 4 && simulation.molecularMode === 0) || (tech.haveGunCheck("shotgun") && !tech.isIncendiary && !tech.isRivets && !tech.isIceShot && !tech.isFoamShot && !tech.isNeedles && !tech.isNailShot)) && !tech.isSporeFlea
+ },
+ requires: "spores, not fleas",
+ effect() {
+ tech.isSporeWorm = true
+ },
+ remove() {
+ tech.isSporeWorm = false
+ }
+ },
+ {
+ name: "K-selection",
+ description: "+37% worm and flea damage ",
+ isGunTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isSporeWorm || tech.isSporeFlea
+ },
+ requires: "spores, shotgun, worms, fleas",
+ effect() {
+ tech.wormSize++
+ },
+ remove() {
+ tech.wormSize = 0
+ }
+ },
+ {
+ name: "path integration",
+ descriptionFunction() {
+ return `drones and ${b.guns[6].nameString("s")} travel with you through levels `
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.isSporeFollow && (tech.haveGunCheck("spores") || (tech.haveGunCheck("shotgun") && tech.isSporeWorm))) || tech.haveGunCheck("drones") || (m.fieldMode === 4 && (simulation.molecularMode === 0 || simulation.molecularMode === 3))
+ },
+ requires: "spores, worms, flagella, drones",
+ effect() {
+ tech.isDronesTravel = true
+ },
+ remove() {
+ tech.isDronesTravel = false
+ }
+ },
+ {
+ name: "reduced tolerances",
+ link: `reduced tolerances `,
+ description: `+66% drones per ${powerUps.orb.ammo()} and energy –40% drone duration `,
+ isGunTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isDroneRadioactive && (tech.haveGunCheck("drones") || (m.fieldMode === 4 && simulation.molecularMode === 3))
+ },
+ requires: "drones, not irradiated drones",
+ effect() {
+ tech.droneCycleReduction = Math.pow(0.6, 1 + this.count)
+ tech.droneEnergyReduction = Math.pow(0.333, 1 + this.count)
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") {
+ const scale = Math.pow(3, this.count + 1)
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * scale
+ }
+ }
+ },
+ remove() {
+ tech.droneCycleReduction = 1
+ tech.droneEnergyReduction = 1
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
+ }
+ }
+ },
+ {
+ name: "delivery drone",
+ description: "if a drone picks up a power up , it becomes larger , faster , and more durable ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldMode === 4 && simulation.molecularMode === 3)
+ },
+ requires: "drones",
+ effect() {
+ tech.isDroneGrab = true
+ },
+ remove() {
+ tech.isDroneGrab = false
+ }
+ },
+ {
+ name: "von Neumann probe", //"drone repair",
+ description: "after a drone expires it will harvest a nearby block to replicate itself",
+ // description: "broken drones repair if the drone gun is activerepairing has a 25% chance to use 1 drone ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("drones")
+ },
+ requires: "drones",
+ effect() {
+ tech.isDroneRespawn = true
+ },
+ remove() {
+ tech.isDroneRespawn = false
+ }
+ },
+ {
+ name: "brushless motor",
+ description: "drones rapidly rush towards their target+33% drone collision damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldMode === 4 && simulation.molecularMode === 3)) && !tech.isDroneRadioactive && !tech.isIncendiary
+ },
+ requires: "drones, molecular assembler, not irradiated drones, incendiary",
+ effect() {
+ tech.isDroneTeleport = true
+ },
+ remove() {
+ tech.isDroneTeleport = false
+ }
+ },
+ {
+ name: "axial flux motor",
+ description: "+66% drones rush frequency+44% drone collision damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isDroneTeleport
+ },
+ requires: "drones, brushless motor",
+ effect() {
+ tech.isDroneFastLook = true
+ },
+ remove() {
+ tech.isDroneFastLook = false
+ }
+ },
+ {
+ name: "irradiated drones",
+ link: `irradiated drones `,
+ description: `the space around drones is irradiated –75% drones per ${powerUps.orb.ammo()} and energy `,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.droneCycleReduction === 1 && !tech.isIncendiary && !tech.isDroneTeleport && (tech.haveGunCheck("drones") || tech.isForeverDrones || (m.fieldMode === 4 && simulation.molecularMode === 3))
+ },
+ requires: "drones, not reduced tolerances, incendiary, torque bursts",
+ effect() {
+ tech.isDroneRadioactive = true
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") {
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack * 0.25
+ b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 0.25)
+ simulation.makeGunHUD();
+ }
+ }
+ },
+ remove() {
+ if (tech.isDroneRadioactive) {
+ tech.isDroneRadioactive = false
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "drones") {
+ b.guns[i].ammoPack = b.guns[i].defaultAmmoPack
+ b.guns[i].ammo = b.guns[i].ammo * 4
+ simulation.makeGunHUD();
+ }
+ }
+ }
+ }
+ },
+ {
+ name: "beta radiation", //"control rod ejection",
+ description: "–50% drone duration+100% drone radiation damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isDroneRadioactive
+ },
+ requires: "drones, irradiated drones",
+ effect() {
+ tech.droneRadioDamage = 2
+ },
+ remove() {
+ tech.droneRadioDamage = 1
+ }
+ },
+ {
+ name: "orthocyclic winding",
+ link: `orthocyclic winding `,
+ description: "+66% drone acceleration+33% radiation damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.isDroneRadioactive
+ },
+ requires: "drones, irradiated drones",
+ effect() {
+ tech.isFastDrones = true
+ },
+ remove() {
+ tech.isFastDrones = false
+ }
+ },
+ {
+ name: "fault tolerance",
+ description: `use ${powerUps.orb.research(2)}to trade your drone gun for 5 drones that last forever `,
+ isGunTech: true,
+ isRemoveGun: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.haveGunCheck("drones", false) && !tech.isDroneRespawn && tech.bulletsLastLonger === 1 && !tech.isDronesTravel && (build.isExperimentSelection || powerUps.research.count > 1)
+ },
+ requires: "drones, not drone repair, anti-shear topology, autonomous navigation",
+ effect() {
+ const num = 5
+ tech.isForeverDrones += num
+ if (tech.haveGunCheck("drones", false)) b.removeGun("drones")
+ //spawn drones
+ if (tech.isDroneRadioactive) {
+ for (let i = 0; i < num * 0.25; i++) {
+ b.droneRadioactive({
+ x: m.pos.x + 30 * (Math.random() - 0.5),
+ y: m.pos.y + 30 * (Math.random() - 0.5)
+ }, 5)
+ bullet[bullet.length - 1].endCycle = Infinity
+ }
+ } else {
+ for (let i = 0; i < num; i++) {
+ b.drone({
+ x: m.pos.x + 30 * (Math.random() - 0.5),
+ y: m.pos.y + 30 * (Math.random() - 0.5)
+ }, 5)
+ bullet[bullet.length - 1].endCycle = Infinity
+ }
+ }
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isForeverDrones = 0
+ if (this.count && !tech.haveGunCheck("drones", false)) b.giveGuns("drones")
+ if (this.count > 0) powerUps.research.changeRerolls(2)
+ }
+ },
+ {
+ name: "surfactant",
+ description: `use ${powerUps.orb.research(2)}to trade your foam gun for 2 foam-bots and foam-bot upgrade `,
+ isGunTech: true,
+ isRemoveGun: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBot: true,
+ isBotTech: true,
+ isNonRefundable: true,
+ requires: "foam gun, not bot upgrades, fractionation, pressure vessel",
+ allowed() {
+ return tech.haveGunCheck("foam", false) && !b.hasBotUpgrade() && !tech.isAmmoFoamSize && !tech.isFoamPressure && (build.isExperimentSelection || powerUps.research.count > 1)
+ },
+ effect() {
+ tech.giveTech("foam-bot upgrade")
+ for (let i = 0; i < 2; i++) {
+ b.foamBot()
+ tech.foamBotCount++;
+ }
+ simulation.makeTextLog(`tech.isFoamBotUpgrade = true`)
+ if (tech.haveGunCheck("foam", false)) b.removeGun("foam")
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ // if (this.count) {
+ // b.clearPermanentBots();
+ // b.respawnBots();
+ // if (!tech.haveGunCheck("foam")) b.giveGuns("foam")
+ // }
+ // if (this.count > 0) powerUps.research.changeRerolls(2)
+ }
+ },
+ {
+ name: "electrostatic induction",
+ description: "foam bubbles are electrically charged causing attraction to nearby mobs ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isBulletTeleport && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine)
+ },
+ requires: "foam, not uncertainty",
+ effect() {
+ tech.isFoamAttract = true
+ },
+ remove() {
+ tech.isFoamAttract = false
+ }
+ },
+ {
+ name: "uncertainty principle",
+ description: "foam , wave , and super ball positions are erratic+53% foam , wave , and super ball damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (!tech.isFoamAttract && (tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine)) || (tech.haveGunCheck("wave") && !tech.is360Longitudinal) || (tech.haveGunCheck("super balls") && !tech.isSuperHarm) || tech.isSoundBotUpgrade
+ },
+ requires: "foam, wave, super balls, not isotropic, electrostatic induction, Zectron",
+ effect() {
+ tech.isBulletTeleport = true
+ },
+ remove() {
+ tech.isBulletTeleport = false;
+ }
+ },
+ {
+ name: "aerogel",
+ description: "–50% foam duration and foam bubbles float +180% foam damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine
+ },
+ requires: "foam",
+ effect() {
+ tech.isFastFoam = true
+ tech.foamGravity = -0.0003
+ },
+ remove() {
+ tech.isFastFoam = false;
+ tech.foamGravity = 0.00008
+ }
+ },
+ {
+ name: "surface tension",
+ description: "+43% foam damage ",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine
+ },
+ requires: "foam",
+ effect() {
+ tech.foamDamage += 0.011 * 0.43
+ },
+ remove() {
+ tech.foamDamage = 0.011;
+ }
+ },
+ {
+ name: "cavitation",
+ description: "25% chance to discharge a huge foam bubble increase foam recoil by 100% ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam") || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isFoamBall || tech.isFoamMine
+ },
+ requires: "foam",
+ effect() {
+ tech.isFoamCavitation = true;
+ b.guns[8].knockBack = 0.001
+ },
+ remove() {
+ tech.isFoamCavitation = false;
+ b.guns[8].knockBack = 0.0005
+ }
+ },
+ {
+ name: "foam fractionation",
+ description: "if you have below 300 ammo +100% foam gun bubble size ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam")
+ },
+ requires: "foam",
+ effect() {
+ tech.isAmmoFoamSize = true
+ },
+ remove() {
+ tech.isAmmoFoamSize = false;
+ }
+ },
+ {
+ name: "ideal gas law",
+ description: `remove all current foam ammo +1200% foam ammo per ${powerUps.orb.ammo(1)}`,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam") && !tech.isEnergyNoAmmo
+ },
+ requires: "foam, not non-renewables",
+ ammoLost: 0,
+ effect() {
+ b.guns[8].ammoPack = b.guns[8].ammoPack * 12;
+ this.ammoLost = b.guns[8].ammo
+ b.guns[8].ammo = 0
+ simulation.updateGunHUD()
+ },
+ remove() {
+ b.guns[8].ammoPack = 24
+ if (this.count) {
+ b.guns[8].ammo += this.ammoLost
+ simulation.updateGunHUD()
+ }
+ }
+ },
+ {
+ name: "pressure vessel",
+ description: "build up charge while firing foam gun after firing discharge foam bubbles",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("foam")
+ },
+ requires: "foam",
+ effect() {
+ tech.isFoamPressure = true;
+ b.guns[8].chooseFireMethod()
+ },
+ remove() {
+ tech.isFoamPressure = false;
+ b.guns[8].chooseFireMethod()
+ }
+ },
+ {
+ name: "capacitor bank",
+ // description: "charge effects build up almost instantly throwing blocks , foam, railgun, pulse, tokamak ",
+ descriptionFunction() {
+ return `charge effects build up almost instantly throwing, ${tech.haveGunCheck("foam", false) ? "foam " : "foam"}, ${tech.isPlasmaBall ? "plasma ball " : "plasma ball"}, ${tech.isRailGun ? "railgun " : "railgun"}, ${tech.isPulseLaser ? "pulse " : "pulse"}, ${tech.isTokamak ? "tokamak " : "tokamak"} `
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.blockDamage > 0.075 || tech.isRailGun || (tech.haveGunCheck("foam") && tech.isFoamPressure) || tech.isTokamak || tech.isPulseLaser || tech.isPlasmaBall
+ },
+ requires: "mass driver, railgun, foam, pressure vessel, pulse, tokamak, plasma ball",
+ effect() {
+ tech.isCapacitor = true;
+ },
+ remove() {
+ tech.isCapacitor = false;
+ }
+ },
+ {
+ name: "Bitter electromagnet",
+ descriptionFunction() {
+ return `railgun charges +33% slower+100% harpoon density and damage `
+ },
+ isGunTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && tech.isRailGun
+ },
+ requires: "harpoon, railgun",
+ effect() {
+ tech.railChargeRate *= 1.06
+ tech.harpoonDensity += 0.007
+ },
+ remove() {
+ tech.railChargeRate = 0.97;
+ tech.harpoonDensity = 0.007
+ }
+ },
+ {
+ name: "railgun",
+ description: `hold fire to charge harpoon and release to launchharpoons can't retract `,
+ // description: `+900% harpoon ammo , but it can't retract +50% harpoon density and damage `,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isGrapple && !tech.isBoostReplaceAmmo
+ },
+ requires: "harpoon, not UHMWPE, induction furnace, grappling hook, quasiparticles",
+ ammoBonus: 9,
+ effect() {
+ tech.isRailGun = true;
+ b.guns[9].chooseFireMethod()
+ b.guns[9].ammoPack = 5;
+ b.guns[9].ammo = b.guns[9].ammo * 6;
+ simulation.updateGunHUD();
+ },
+ remove() {
+ if (tech.isRailGun) {
+ tech.isRailGun = false;
+ b.guns[9].chooseFireMethod()
+ b.guns[9].ammoPack = 1.7;
+ b.guns[9].ammo = Math.ceil(b.guns[9].ammo / 6);
+ simulation.updateGunHUD();
+ }
+ }
+ },
+ {
+ name: "grappling hook",
+ description: `harpoons attach to the map and pull you your rope extends while holding fire `,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isFilament && !tech.isHarpoonPowerUp && !tech.isRailGun && !tech.isFireMoveLock
+ },
+ requires: "harpoon, not railgun, UHMWPE, induction furnace, Higgs mechanism",
+ effect() {
+ tech.isGrapple = true;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
+ }
+ },
+ remove() {
+ if (tech.isGrapple) {
+ tech.isGrapple = false;
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
+ }
+ }
+ }
+ },
+ {
+ name: "bulk modulus",
+ description: `while grappling become invulnerable drain energy `,
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && tech.isGrapple && !tech.isRailEnergy
+ },
+ requires: "grappling hook, not alternator",
+ effect() {
+ tech.isImmuneGrapple = true;
+ },
+ remove() {
+ tech.isImmuneGrapple = false
+ }
+ },
+ {
+ name: "alternator",
+ description: "+90% harpoon energy efficiency",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isImmuneGrapple
+ },
+ requires: "harpoon, not bulk modulus",
+ effect() {
+ tech.isRailEnergy = true;
+ },
+ remove() {
+ tech.isRailEnergy = false;
+ }
+ },
+ {
+ name: "Bessemer process",
+ descriptionFunction() {
+ return `+${(10 * Math.sqrt(b.guns[9].ammo)).toFixed(0)}% harpoon size and damage (1/10 √ harpoon ammo ) `
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isShieldPierce
+ },
+ requires: "harpoon, not ceramics",
+ effect() {
+ tech.isLargeHarpoon = true;
+ },
+ remove() {
+ tech.isLargeHarpoon = false;
+ }
+ },
+ {
+ name: "smelting",
+ descriptionFunction() {
+ return `forge ${this.removeAmmo()} ammo into a new harpoon fire +1 harpoon with each shot`
+ },
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ ammoRemoved: 0,
+ removeAmmo() {
+ return (tech.isRailGun ? 5 : 1) * (2 + 2 * this.count)
+ },
+ allowed() {
+ return tech.haveGunCheck("harpoon") && b.guns[9].ammo >= this.removeAmmo()
+ },
+ requires: "harpoon",
+ effect() {
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "harpoon") {
+ const removeAmmo = this.removeAmmo()
+ this.ammoRemoved += removeAmmo
+ b.guns[i].ammo -= removeAmmo
+ if (b.guns[i].ammo < 0) b.guns[i].ammo = 0
+ simulation.updateGunHUD();
+ tech.extraHarpoons++;
+ break
+ }
+ }
+ },
+ remove() {
+ if (tech.extraHarpoons) {
+ for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
+ if (b.guns[i].name === "harpoon") {
+ b.guns[i].ammo += this.ammoRemoved
+ simulation.updateGunHUD();
+ break
+ }
+ }
+ }
+ this.ammoRemoved = 0
+ tech.extraHarpoons = 0;
+ }
+ },
+ {
+ name: "UHMWPE",
+ descriptionFunction() {
+ return `+${(b.guns[9].ammo * 1.25).toFixed(0)}% harpoon rope length (1/80 of harpoon ammo ) `
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
+ },
+ requires: "harpoon, not grappling hook, railgun",
+ effect() {
+ tech.isFilament = true;
+ },
+ remove() {
+ tech.isFilament = false;
+ }
+ },
+ {
+ name: "induction furnace",
+ description: "after using harpoon to collect a power up +600% harpoon damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("harpoon") && !tech.isRailGun && !tech.isGrapple
+ },
+ requires: "harpoon, not grappling hook, railgun",
+ effect() {
+ tech.isHarpoonPowerUp = true
+ },
+ remove() {
+ tech.isHarpoonPowerUp = false
+ }
+ },
+ {
+ name: "quasiparticles",
+ descriptionFunction() {
+ return `convert current and future ${powerUps.orb.ammo(1)} into ${powerUps.orb.boost(1)} which give +${(powerUps.boost.damage * 100).toFixed(0)}% damage for ${(powerUps.boost.duration / 60).toFixed(0)} seconds`
+ },
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return ((tech.haveGunCheck("wave") && !tech.isInfiniteWaveAmmo) || tech.haveGunCheck("laser") || (tech.haveGunCheck("harpoon") && !tech.isRailGun)) && !tech.isEnergyNoAmmo
+ },
+ requires: "harpoon, laser, wave, frequency, not railgun, non-renewables",
+ effect() {
+ tech.isBoostReplaceAmmo = true
+ for (let i = powerUp.length - 1; i > -1; i--) {
+ if (powerUp[i].name === "ammo") {
+ powerUps.spawn(powerUp[i].position.x + 50 * (Math.random() - 0.5), powerUp[i].position.y + 50 * (Math.random() - 0.5), "boost");
+ Matter.Composite.remove(engine.world, powerUp[i]);
+ powerUp.splice(i, 1);
+ }
+ }
+
+ },
+ remove() {
+ tech.isBoostReplaceAmmo = false
+ }
+ },
+ {
+ name: "optical amplifier",
+ description: "gain 3 random laser gun tech laser only turns off if you have no energy ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isNonRefundable: true,
+ allowed() {
+ return tech.haveGunCheck("laser") && !tech.isPulseLaser
+ },
+ requires: "laser gun, not pulse",
+ effect() {
+ let techGiven = 0
+ for (let j = 0; j < 3; j++) {
+ const names = ["quasiparticles", "lens", "compound lens", "arc length", "infrared diode", "free-electron laser", "dye laser", "relativistic momentum", "specular reflection", "diffraction grating", "diffuse beam", "output coupler", "slow light", "laser-bot", "laser-bot upgrade"]
+ //convert names into indexes
+ const options = []
+ for (let i = 0; i < names.length; i++) {
+ for (let k = 0; k < tech.tech.length; k++) {
+ if (tech.tech[k].name === names[i]) {
+ options.push(k)
+ break
+ }
+ }
+ }
+ //remove options that don't meet requirements
+ for (let i = options.length - 1; i > -1; i--) {
+ const index = options[i]
+ if (!(tech.tech[index].count < tech.tech[index].maxCount) || !tech.tech[index].allowed()) {
+ options.splice(i, 1);
+ }
+ }
+ //pick one option
+ if (options.length) {
+ const index = options[Math.floor(Math.random() * options.length)]
+ simulation.makeTextLog(`tech .giveTech("${tech.tech[index].name} ") //optical amplifier `, 360);
+ tech.giveTech(index)
+ techGiven++
+ }
+ }
+ if (techGiven > 0) {
+ tech.isStuckOn = true
+ } else { //eject if none found
+ simulation.makeTextLog(`0 tech found //optical amplifier `);
+ const loop = () => {
+ if (!simulation.paused && m.alive) {
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].name === this.name) powerUps.ejectTech(i)
+ }
+ return
+ }
+ requestAnimationFrame(loop);
+ }
+ requestAnimationFrame(loop);
+ }
+ },
+ remove() {
+ tech.isStuckOn = false
+ }
+ },
+ {
+ name: "relativistic momentum",
+ description: "lasers push mobs and blocks ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("laser") && !tech.isPulseLaser) || tech.isLaserBotUpgrade || tech.isLaserField
+ },
+ requires: "laser, not pulse",
+ effect() {
+ tech.isLaserPush = true;
+ },
+ remove() {
+ tech.isLaserPush = false;
+ }
+ },
+ {
+ name: "iridescence",
+ // description: "if a laser hits a mob at a low angle of illumination+66% laser damage ",
+ description: "if laser beams hit mobs near their center +100% laser damage ",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.haveGunCheck("laser") && !tech.isPulseLaser) || tech.isLaserBotUpgrade || tech.isLaserMine
+ },
+ requires: "laser, not pulse",
+ effect() {
+ tech.laserCrit += 1;
+ },
+ remove() {
+ tech.laserCrit = 0;
+ }
+ },
+ {
+ name: "lens",
+ description: "+150% laser gun damage if it passes through a revolving 90° arc circular lens", //π / 2
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("laser")
+ },
+ requires: "laser",
+ effect() {
+ tech.isLaserLens = true
+ b.guns[11].chooseFireMethod()
+ // if (this.count > 0) b.guns[11].lensDamageOn += 20 * Math.PI / 180
+ // b.guns[11].arcRange = 0.78
+ },
+ remove() {
+ tech.isLaserLens = false
+ b.guns[11].chooseFireMethod()
+ // b.guns[11].lensDamageOn = 2.5 // 100% + 150%
+ // b.guns[11].arcRange = 0
+ }
+ },
+ {
+ name: "compound lens",
+ description: "+50% laser lens damage +15° lens arc",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("laser") && tech.isLaserLens
+ },
+ requires: "lens",
+ effect() {
+ b.guns[11].arcRange += 15 * Math.PI / 180 / 2
+ b.guns[11].lensDamageOn += 0.5
+ },
+ remove() {
+ b.guns[11].arcRange = 90 * Math.PI / 180 / 2 //0.78 divded by 2 because of how it's drawn
+ b.guns[11].lensDamageOn = 2.5
+ }
+ },
+ {
+ name: "specular reflection",
+ description: "+2 laser beam reflections",
+ isGunTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.isLaserBotUpgrade || tech.isLaserField) && !tech.isWideLaser && !tech.isPulseLaser && !tech.historyLaser
+ },
+ requires: "laser, not diffuse beam, pulse, or slow light",
+ effect() {
+ tech.laserReflections += 2;
+ },
+ remove() {
+ tech.laserReflections = 2;
+ }
+ },
+ {
+ name: "diffraction grating",
+ description: `+1 diverging laser gun beam`,
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.haveGunCheck("laser") && !tech.isWideLaser && !tech.historyLaser
+ },
+ requires: "laser gun, diffuse beam, or slow light",
+ effect() {
+ tech.beamSplitter++
+ b.guns[11].chooseFireMethod()
+ },
+ remove() {
+ if (tech.beamSplitter !== 0) {
+ tech.beamSplitter = 0
+ b.guns[11].chooseFireMethod()
+ }
+ }
+ },
+ {
+ name: "diffuse beam",
+ link: `diffuse beam `,
+ description: "laser gun beam is wider and doesn't reflect +220% laser damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.beamSplitter && !tech.isPulseLaser && !tech.historyLaser
+ },
+ requires: "laser gun, not specular reflection, diffraction grating, slow light, pulse",
+ effect() {
+ if (tech.wideLaser === 0) tech.wideLaser = 3
+ tech.isWideLaser = true;
+ b.guns[11].chooseFireMethod()
+ },
+ remove() {
+ if (tech.isWideLaser) {
+ // tech.wideLaser = 0
+ tech.isWideLaser = false;
+ b.guns[11].chooseFireMethod()
+ }
+ }
+ },
+ {
+ name: "output coupler",
+ description: "+30% laser gun beam width +30% laser damage ",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("laser") && tech.isWideLaser
+ },
+ requires: "laser gun, diffuse beam",
+ effect() {
+ tech.wideLaser += 2
+ b.guns[11].chooseFireMethod()
+ },
+ remove() {
+ if (tech.isWideLaser) {
+ tech.wideLaser = 3
+ } else {
+ tech.wideLaser = 0
+ }
+ b.guns[11].chooseFireMethod()
+ }
+ },
+ {
+ name: "slow light",
+ description: "laser gun beam is spread into your recent past +300% total beam damage ",
+ isGunTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.beamSplitter && !tech.isWideLaser
+ },
+ requires: "laser gun, not specular reflection, diffraction grating, diffuse beam",
+ effect() {
+ // this.description = `add 5 more laser beams into into your past`
+ tech.historyLaser++
+ b.guns[11].chooseFireMethod()
+ },
+ remove() {
+ if (tech.historyLaser) {
+ tech.historyLaser = 0
+ b.guns[11].chooseFireMethod()
+ }
+ }
+ },
+ {
+ name: "infrared diode",
+ description: "+60% laser energy efficiencyinfrared light is outside visual perception ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("laser") || tech.isLaserBotUpgrade || tech.isLaserMine || tech.isLaserField) && !tech.isPulseLaser && tech.laserDrain === 0.0018
+ },
+ requires: "laser, not free-electron, pulse",
+ effect() {
+ tech.laserDrain *= 0.4; //100%-50%
+ tech.laserColor = "transparent" //"rgb(255,0,20,0.02)"
+ // tech.laserColorAlpha = "rgba(255,0,20,0.05)"
+ },
+ remove() {
+ tech.laserDrain = 0.0018;
+ tech.laserColor = "#f02"
+ tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
+ }
+ },
+ {
+ name: "dye laser",
+ description: "+25% laser energy efficiency+25% laser damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.isLaserBotUpgrade || tech.isLaserField) && !tech.isPulseLaser && tech.laserDrain === 0.0018
+ },
+ requires: "laser, not pulse, infrared diode",
+ effect() {
+ tech.laserDrain *= 0.75
+ tech.laserDamage *= 1.25
+ tech.laserColor = "rgb(0, 11, 255)"
+ tech.laserColorAlpha = "rgba(0, 11, 255,0.5)"
+ },
+ remove() {
+ tech.laserDrain = 0.0018;
+ tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.18
+ tech.laserColor = "#f00"
+ tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
+ }
+ },
+ {
+ name: "free-electron laser",
+ description: "–250% laser energy efficiency+200% laser damage ",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return (tech.haveGunCheck("laser") || tech.isLaserMine || tech.isLaserBotUpgrade || tech.isLaserField) && !tech.isPulseLaser && tech.laserDrain === 0.0018
+ },
+ requires: "laser, not pulse, infrared diode",
+ effect() {
+ tech.laserDrain *= 1 + 2.5 //250% more drain
+ tech.laserDamage *= 1 + 2 //190% more damage
+ tech.laserColor = "#83f"
+ tech.laserColorAlpha = "rgba(136, 51, 255,0.5)"
+ },
+ remove() {
+ tech.laserDrain = 0.0018;
+ tech.laserDamage = 0.18; //used in check on pulse and diode: tech.laserDamage === 0.18
+ tech.laserColor = "#f00"
+ tech.laserColorAlpha = "rgba(255, 0, 0, 0.5)"
+ }
+ },
+ {
+ name: "pulse",
+ description: "charge your energy and release it as alaser pulse that initiates an explosion cluster",
+ isGunTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return tech.haveGunCheck("laser") && tech.laserReflections < 3 && !tech.isWideLaser && tech.laserDrain === 0.0018 && !tech.isStuckOn
+ },
+ requires: "laser gun, not specular reflection, diffuse, free-electron laser, optical amplifier",
+ effect() {
+ tech.isPulseLaser = true;
+ b.guns[11].chooseFireMethod()
+ },
+ remove() {
+ if (tech.isPulseLaser) {
+ tech.isPulseLaser = false;
+ b.guns[11].chooseFireMethod()
+ }
+ }
+ },
+ //**************************************************
+ //************************************************** field
+ //************************************************** tech
+ //**************************************************
+ {
+ name: "spherical harmonics",
+ description: "+50% standing wave deflection efficiency shield deflection radius maintains it's maximum range", //standing wave oscillates in a 3rd dimension
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 1 && !tech.isLaserField
+ },
+ requires: "standing wave, not surface plasmons",
+ effect() {
+ tech.harmonics++
+ m.fieldShieldingScale = 1.6 * Math.pow(0.5, (tech.harmonics - 2))
+ m.harmonicShield = m.harmonicAtomic
+ },
+ remove() {
+ tech.harmonics = 2
+ m.fieldShieldingScale = 1.6 * Math.pow(0.5, (tech.harmonics - 2))
+ m.harmonicShield = m.harmonic3Phase
+ }
+ },
+ {
+ name: "surface plasmons",
+ description: "if deflecting drains all your energy emit laser beams that scale with max energy ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 1 && tech.harmonics === 2
+ },
+ requires: "standing wave",
+ effect() {
+ tech.isLaserField = true
+ },
+ remove() {
+ tech.isLaserField = false
+ }
+ },
+ {
+ name: "zero point energy",
+ description: `use ${powerUps.orb.research(2)}+100 maximum energy `,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (m.fieldMode === 1 || m.fieldMode === 8 || m.fieldMode === 6) && (build.isExperimentSelection || powerUps.research.count > 1)
+ },
+ requires: "standing wave, pilot wave, time dilation",
+ effect() {
+ tech.harmonicEnergy = 1
+ m.setMaxEnergy()
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.harmonicEnergy = 0;
+ m.setMaxEnergy()
+ if (this.count > 0) powerUps.research.changeRerolls(2)
+ }
+ },
+ {
+ name: "expansion",
+ description: "using standing wave field expands its radius +40 maximum energy ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 1
+ },
+ requires: "standing wave",
+ effect() {
+ tech.isStandingWaveExpand = true
+ m.setMaxEnergy()
+ // m.fieldShieldingScale = (tech.isStandingWaveExpand ? 0.9 : 1.6) * Math.pow(0.6, (tech.harmonics - 2))
+ },
+ remove() {
+ tech.isStandingWaveExpand = false
+ m.setMaxEnergy()
+ // m.fieldShieldingScale = (tech.isStandingWaveExpand ? 0.9 : 1.6) * Math.pow(0.6, (tech.harmonics - 2))
+ m.harmonicRadius = 1
+ }
+ },
+ {
+ name: "electronegativity",
+ descriptionFunction() {
+ return `+0.22% damage per current stored energy (+${(22 * m.maxEnergy).toFixed(0)}% damage at max energy) `
+ },
+ // description: "+1% damage per 8 stored energy ",
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 1 || m.fieldMode === 9 || m.fieldMode === 8
+ },
+ requires: "standing wave, wormhole, pilot wave",
+ effect() {
+ tech.energyDamage++
+ },
+ remove() {
+ tech.energyDamage = 0;
+ }
+ },
+ {
+ name: "bremsstrahlung",
+ description: "deflecting and thrown blocks do braking damage to mobs",
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 1 || m.fieldMode === 2 || m.fieldMode === 8
+ },
+ requires: "standing wave, perfect diamagnetism, pilot wave",
+ effect() {
+ tech.blockDmg += 5 //if you change this value also update the for loop in the electricity graphics in m.pushMass
+ },
+ remove() {
+ tech.blockDmg = 0;
+ }
+ },
+ {
+ name: "cherenkov radiation", //deflecting and blocks
+ description: "bremsstrahlung's effects are radioactive +250% damage over 3 seconds",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldMode === 1 || m.fieldMode === 2 || m.fieldMode === 8) && tech.blockDmg
+ },
+ requires: "bremsstrahlung",
+ effect() {
+ tech.isBlockRadiation = true
+ },
+ remove() {
+ tech.isBlockRadiation = false;
+ }
+ },
+ {
+ name: "flux pinning",
+ description: "after deflecting a mob it is stunned for up to 4 seconds",
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 2 || m.fieldMode === 1 || m.fieldMode === 4
+ },
+ requires: "a field that can block",
+ effect() {
+ tech.isStunField += 240;
+ },
+ remove() {
+ tech.isStunField = 0;
+ }
+ },
+ {
+ name: "triple point",
+ descriptionFunction() {
+ return `+1.5 second ice IX freeze and spawn ${powerUps.orb.coupling(10)}${m.couplingDescription(1)} per ${powerUps.orb.coupling(1)} `
+ },
+ isFieldTech: true,
+ maxCount: 3,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 2
+ },
+ requires: "perfect diamagnetism",
+ effect() {
+ tech.iceIXFreezeTime += 90
+ powerUps.spawnDelay("coupling", 10)
+ },
+ remove() {
+ tech.iceIXFreezeTime = 150
+ if (this.count) m.couplingChange(-10 * this.count)
+ }
+ },
+ {
+ name: "eddy current brake",
+ description: "perfect diamagnetism slows nearby mobs effect radius scales with stored energy ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 2 && !tech.isHealBrake
+ },
+ requires: "perfect diamagnetism, not induction brake",
+ effect() {
+ tech.isPerfectBrake = true;
+ },
+ remove() {
+ tech.isPerfectBrake = false;
+ }
+ },
+ {
+ name: "Meissner effect",
+ description: "+55% perfect diamagnetism radius +22° perfect diamagnetism circular arc ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 2
+ },
+ requires: "perfect diamagnetism",
+ effect() {
+ tech.isBigField = true;
+ },
+ remove() {
+ tech.isBigField = false;
+ }
+ },
+ {
+ name: "tessellation",
+ description: `use ${powerUps.orb.research(2)}+50% defense `,
+ // description: "use 4 research reduce defense by 50% ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (m.fieldMode === 8 || m.fieldMode === 2 || m.fieldMode === 3) && (build.isExperimentSelection || powerUps.research.count > 3)
+ },
+ requires: "perfect diamagnetism, negative mass, pilot wave",
+ effect() {
+ tech.isFieldHarmReduction = true
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isFieldHarmReduction = false
+ if (this.count > 0) powerUps.research.changeRerolls(2)
+ }
+ },
+ {
+ name: "radiative equilibrium",
+ description: "after losing health +200% damage for 8 seconds",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 8 || m.fieldMode === 3
+ },
+ requires: "negative mass, pilot wave",
+ effect() {
+ tech.isHarmDamage = true;
+ },
+ remove() {
+ tech.isHarmDamage = false;
+ }
+ },
+ {
+ name: "dynamic equilibrium",
+ descriptionFunction() {
+ // return `increase damage by your defense and5% of your last ${tech.isEnergyHealth ? "energy " : "health "} loss (+${(100 * Math.max(5, tech.lastHitDamage) * m.lastHit * (2 - m.defense())).toFixed(0)}% damage) `
+ return `increase damage by your last ${tech.isEnergyHealth ? "energy " : "health "} loss scales with defense (+${(100 * Math.max(5, tech.lastHitDamage) * m.lastHit * (2 - m.defense())).toFixed(0)}% damage) `
+ }, // = +${10*m.defense()}%
+ // descriptionFunction() { return `increase damage by your last ${tech.isEnergyHealth ? "energy " : "health "} loss(${(tech.lastHitDamage).toFixed(0)}%)(${(100*m.lastHit).toFixed(0)} ${tech.isEnergyHealth ? "energy " : "health "})(${2 - m.defense()} defense ) = ${(100*tech.lastHitDamage * m.lastHit * (2 - m.defense())).toFixed(0)}% damage ` }, // = +${10*m.defense()}%
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldMode === 8 || m.fieldMode === 3) && !tech.isCloakHealLastHit
+ },
+ requires: "negative mass, pilot wave, not patch",
+ effect() {
+ tech.lastHitDamage += 4;
+ },
+ remove() {
+ tech.lastHitDamage = 0;
+ }
+ },
+ {
+ name: "neutronium",
+ description: `move and jump 20% slower if your field is active +90% defense `,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 3
+ },
+ requires: "negative mass",
+ effect() {
+ tech.isNeutronium = true
+ tech.baseFx *= 0.8
+ tech.baseJumpForce *= 0.8
+ m.setMovement()
+ },
+ //also removed in m.setHoldDefaults() if player switches into a bad field
+ remove() {
+ tech.isNeutronium = false
+ if (!tech.isFreeWormHole) {
+ tech.baseFx = 0.08
+ tech.baseJumpForce = 10.5
+ m.setMovement()
+ }
+ }
+ },
+ {
+ name: "aerostat",
+ description: `+88% damage while off the ground -22% damage while on the ground `,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 3
+ },
+ requires: "negative mass",
+ effect() {
+ tech.isNoGroundDamage = true
+ },
+ remove() {
+ tech.isNoGroundDamage = false
+ }
+ },
+ {
+ name: "annihilation",
+ description: "after colliding with non-boss mobs they are annihilated and –33% energy ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 3 && !tech.isEnergyHealth
+ },
+ requires: "negative mass, not mass-energy",
+ effect() {
+ tech.isAnnihilation = true
+ },
+ remove() {
+ tech.isAnnihilation = false;
+ }
+ },
+ {
+ name: "inertial mass",
+ description: "negative mass is larger and faster blocks also move horizontally with the field",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 3
+ },
+ requires: "negative mass",
+ effect() {
+ tech.isFlyFaster = true
+ },
+ remove() {
+ tech.isFlyFaster = false;
+ }
+ },
+ // {
+ // name: "Bose Einstein condensate",
+ // description: "use energy to freeze mobs in your field pilot wave, negative mass, time dilation ",
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return m.fieldMode === 8 || m.fieldMode === 3 || (m.fieldMode === 6 && !tech.isRewindField)
+ // },
+ // requires: "pilot wave, negative mass, time dilation, not retrocausality",
+ // effect() {
+ // tech.isFreezeMobs = true
+ // },
+ // remove() {
+ // tech.isFreezeMobs = false
+ // }
+ // },
+ {
+ name: "bot manufacturing",
+ description: `use ${powerUps.orb.research(2)} to build3 random bots `,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBotTech: true,
+ isNonRefundable: true,
+ allowed() {
+ return powerUps.research.count > 1 && (m.fieldMode === 4 || m.fieldMode === 8)
+ },
+ requires: "molecular assembler, pilot wave",
+ effect() {
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ m.energy = 0.01;
+ b.randomBot()
+ b.randomBot()
+ b.randomBot()
+ },
+ remove() { }
+ },
+ {
+ name: "bot prototypes",
+ description: `use ${powerUps.orb.research(3)}to build 2 random bots and upgrade all bots to that type`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ isBotTech: true,
+ isNonRefundable: true,
+ allowed() {
+ return powerUps.research.count > 2 && (m.fieldMode === 4 || m.fieldMode === 8)
+ },
+ requires: "molecular assembler, pilot wave",
+ effect() {
+ for (let i = 0; i < 3; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ //fill array of available bots
+ const notUpgradedBots = []
+ const num = 2
+ notUpgradedBots.push(() => {
+ tech.giveTech("nail-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.nailBot()
+ tech.nailBotCount++;
+ }
+ simulation.makeTextLog(`tech.isNailBotUpgrade = true`)
+ })
+ notUpgradedBots.push(() => {
+ tech.giveTech("foam-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.foamBot()
+ tech.foamBotCount++;
+ }
+ simulation.makeTextLog(`tech.isFoamBotUpgrade = true`)
+ })
+ notUpgradedBots.push(() => {
+ tech.giveTech("sound-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.soundBot()
+ tech.soundBotCount++;
+ }
+ simulation.makeTextLog(`tech.isSoundBotUpgrade = true`)
+ })
+ notUpgradedBots.push(() => {
+ tech.giveTech("boom-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.boomBot()
+ tech.boomBotCount++;
+ }
+ simulation.makeTextLog(`tech.isBoomBotUpgrade = true`)
+ })
+ notUpgradedBots.push(() => {
+ tech.giveTech("laser-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.laserBot()
+ tech.laserBotCount++;
+ }
+ simulation.makeTextLog(`tech.isLaserBotUpgrade = true`)
+ })
+ notUpgradedBots.push(() => {
+ tech.giveTech("orbital-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.orbitBot()
+ tech.orbitBotCount++;
+ }
+ simulation.makeTextLog(`tech.isOrbitalBotUpgrade = true`)
+ })
+ for (let i = 0; i < 2; i++) { //double chance for dynamo-bot, since it's very good for assembler
+ notUpgradedBots.push(() => {
+ tech.giveTech("dynamo-bot upgrade")
+ for (let i = 0; i < num; i++) {
+ b.dynamoBot()
+ tech.dynamoBotCount++;
+ }
+ simulation.makeTextLog(`tech.isDynamoBotUpgrade = true`)
+ })
+ }
+ notUpgradedBots[Math.floor(Math.random() * notUpgradedBots.length)]() //choose random function from the array and run it
+ },
+ remove() { }
+ },
+ // {
+ // name: "mycelium manufacturing",
+ // link: `mycelium manufacturing `,
+ // // description: `use ${powerUps.orb.research(1)}to repurpose molecular assembler excess energy used to grow spores `,
+ // descriptionFunction() { return `use ${powerUps.orb.research(1)}to repurpose molecular assembler excess energy used to grow ${b.guns[6].nameString('s')}` },
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 3,
+ // frequencyDefault: 3,
+ // allowed() {
+ // return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldMode === 4 && !(tech.isMissileField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport)
+ // },
+ // requires: "molecular assembler, no other manufacturing, no drone tech",
+ // effect() {
+ // if (!build.isExperimentSelection) {
+ // for (let i = 0; i < 1; i++) {
+ // if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ // }
+ // }
+ // tech.isSporeField = true;
+ // },
+ // remove() {
+ // tech.isSporeField = false;
+ // if (this.count > 0) powerUps.research.changeRerolls(1)
+ // }
+ // },
+ // {
+ // name: "missile manufacturing",
+ // link: `missile manufacturing `,
+ // description: `use ${powerUps.orb.research(1)}to repurpose molecular assembler excess energy used to construct missiles `,
+ // // description: "use 3 research to repurpose assembler excess energy used to construct missiles ",
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 3,
+ // frequencyDefault: 3,
+ // allowed() {
+ // return (build.isExperimentSelection || powerUps.research.count > 0) && m.maxEnergy > 0.5 && m.fieldMode === 4 && !(tech.isSporeField || tech.isIceField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel)
+ // },
+ // requires: "molecular assembler, no other manufacturing, no drone tech",
+ // effect() {
+ // if (!build.isExperimentSelection) {
+ // for (let i = 0; i < 1; i++) {
+ // if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ // }
+ // }
+ // tech.isMissileField = true;
+ // },
+ // remove() {
+ // tech.isMissileField = false;
+ // if (this.count > 0) powerUps.research.changeRerolls(1)
+ // }
+ // },
+ // {
+ // name: "ice IX manufacturing",
+ // link: `ice IX manufacturing `,
+ // description: `use ${powerUps.orb.research(1)}to repurpose molecular assembler excess energy used to condense ice IX `,
+ // // description: "use 3 research to repurpose assembler excess energy used to condense ice IX ",
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 3,
+ // frequencyDefault: 3,
+ // allowed() {
+ // return (build.isExperimentSelection || powerUps.research.count > 0) && m.fieldMode === 4 && !(tech.isSporeField || tech.isMissileField || tech.isFastDrones || tech.isDroneGrab || tech.isDroneRadioactive || tech.isDroneTeleport || tech.isDronesTravel)
+ // },
+ // requires: "molecular assembler, no other manufacturing, no drone tech",
+ // effect() {
+ // if (!build.isExperimentSelection) {
+ // for (let i = 0; i < 1; i++) {
+ // if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ // }
+ // }
+ // tech.isIceField = true;
+ // },
+ // remove() {
+ // tech.isIceField = false;
+ // if (this.count > 0) powerUps.research.changeRerolls(1)
+ // }
+ // },
+ {
+ name: "additive manufacturing",
+ description: "hold crouch and use your field to print a block with +80% density, damage , and launch speed",
+ // description: "simultaneously fire and activate your field to make molecular assembler print a throwable block +80% block throwing speed",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldMode === 4 || m.fieldMode === 8) && !tech.isTokamak
+ },
+ requires: "molecular assembler, pilot wave, not tokamak",
+ effect() {
+ tech.isPrinter = true;
+ },
+ remove() {
+ if (this.count > 0) m.holdingTarget = null;
+ tech.isPrinter = false;
+ }
+ },
+ {
+ name: "pair production",
+ description: "after picking up a power up +200 energy ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 4 || m.fieldMode === 1 || m.fieldMode === 8
+ },
+ requires: "molecular assembler, pilot wave, standing wave",
+ effect() {
+ tech.isMassEnergy = true // used in m.grabPowerUp
+ m.energy += 2
+ },
+ remove() {
+ tech.isMassEnergy = false;
+ }
+ },
+ {
+ name: "electric generator",
+ description: "after deflecting mobs molecular assembler generates +50 energy ",
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 4
+ },
+ requires: "molecular assembler",
+ effect() {
+ tech.deflectEnergy += 0.5;
+ },
+ remove() {
+ tech.deflectEnergy = 0;
+ }
+ },
+ {
+ name: "combinatorial optimization",
+ description: "+35% damage –35% fire rate ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 5 || m.fieldMode === 6 || m.fieldMode === 7 || m.fieldMode === 8 || m.fieldMode === 4
+ },
+ requires: "cloaking, molecular assembler, plasma torch, pilot wave",
+ damage: 1.35,
+ effect() {
+ tech.damage *= this.damage
+ tech.aimDamage = 1.35
+ b.setFireCD();
+ },
+ remove() {
+ if (this.count) tech.damage /= this.damage
+ tech.aimDamage = 1
+ b.setFireCD();
+ }
+ },
+ {
+ name: "tokamak",
+ description: "throwing a block converts it into energy and a pulsed fusion explosion ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldMode === 5 || m.fieldMode === 4) && !tech.isPrinter
+ },
+ requires: "plasma torch, molecular assembler, not printer",
+ effect() {
+ tech.isTokamak = true;
+ },
+ remove() {
+ tech.isTokamak = false;
+ }
+ },
+ {
+ name: "degenerate matter",
+ description: "if your field is active+75% defense ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldMode === 5 || m.fieldMode === 4 || m.fieldMode === 2 || m.fieldMode === 8)
+ },
+ requires: "molecular assembler, plasma torch, perfect diamagnetism, pilot wave",
+ effect() {
+ tech.isHarmReduce = true
+ },
+ remove() {
+ tech.isHarmReduce = false;
+ }
+ },
+ {
+ name: "plasma-bot",
+ link: `plasma-bot `,
+ description: `use ${powerUps.orb.research(2)}to trade your field for a bot that uses energy to emit plasma `,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ isBot: true,
+ isBotTech: true,
+ allowed() {
+ return m.fieldMode === 5 && !tech.isPlasmaBall && !tech.isExtruder && (build.isExperimentSelection || powerUps.research.count > 1)
+ },
+ requires: "plasma torch, not extruder, plasma ball",
+ effect() {
+ tech.plasmaBotCount++;
+ b.plasmaBot();
+ if (build.isExperimentSelection) {
+ document.getElementById("field-" + m.fieldMode).classList.remove("build-field-selected");
+ document.getElementById("field-0").classList.add("build-field-selected");
+ }
+ m.setField("field emitter")
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ if (this.count > 0) {
+ tech.plasmaBotCount = 0;
+ b.clearPermanentBots();
+ b.respawnBots();
+ if (m.fieldMode === 0) {
+ m.setField("plasma torch")
+ if (build.isExperimentSelection) {
+ document.getElementById("field-0").classList.remove("build-field-selected");
+ document.getElementById("field-" + m.fieldMode).classList.add("build-field-selected");
+ }
+ }
+ powerUps.research.changeRerolls(2)
+ }
+ }
+ },
+ {
+ name: "plasma jet",
+ link: `plasma jet `,
+ description: `use ${powerUps.orb.research(2)}+50% plasma torch range`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (tech.plasmaBotCount || m.fieldMode === 5) && (build.isExperimentSelection || powerUps.research.count > 1) && !tech.isPlasmaBall
+ },
+ requires: "plasma torch, not plasma ball",
+ effect() {
+ tech.isPlasmaRange += 0.5;
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isPlasmaRange = 1;
+ if (this.count > 0) powerUps.research.changeRerolls(this.count * 2)
+ }
+ },
+ {
+ name: "extruder",
+ description: "extrude a thin hot wire of plasma increases damage and energy drain",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 5 && !tech.isPlasmaBall
+ },
+ requires: "plasma torch, not plasma ball",
+ effect() {
+ tech.isExtruder = true;
+ m.fieldUpgrades[m.fieldMode].set()
+ },
+ remove() {
+ tech.isExtruder = false;
+ if (this.count && m.fieldMode === 5) m.fieldUpgrades[m.fieldMode].set()
+ }
+ },
+ {
+ name: "refractory metal",
+ description: "extrude metals at a higher temperature increases effective radius and damage ",
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 5 && tech.isExtruder
+ },
+ requires: "extruder",
+ effect() {
+ tech.extruderRange += 55
+ },
+ remove() {
+ tech.extruderRange = 15
+ }
+ },
+ {
+ name: "plasma ball",
+ description: "grow an expanding ball of plasma increases damage and energy drain",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 5 && !tech.isExtruder && tech.isPlasmaRange === 1
+ },
+ requires: "plasma torch, not extruder, plasma jet",
+ effect() {
+ tech.isPlasmaBall = true;
+ m.fieldUpgrades[m.fieldMode].set()
+ },
+ remove() {
+ tech.isPlasmaBall = false;
+ if (this.count && m.fieldMode === 5) m.fieldUpgrades[m.fieldMode].set()
+ }
+ },
+ {
+ name: "corona discharge",
+ description: "increase the range and frequency of plasma ball's electric arc ",
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 5 && tech.isPlasmaBall
+ },
+ requires: "plasma ball",
+ effect() {
+ tech.plasmaDischarge += 0.03
+ },
+ remove() {
+ tech.plasmaDischarge = 0.01 //default chance per cycle of a discharge
+ }
+ },
+ {
+ name: "retrocausality",
+ description: "time dilation uses energy to rewind yourhealth , velocity , and position up to 10 seconds",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return m.fieldMode === 6 && !m.isShipMode && !tech.isRewindAvoidDeath && !tech.isTimeSkip
+ },
+ requires: "time dilation, not CPT symmetry",
+ effect() {
+ tech.isRewindField = true;
+ m.fieldUpgrades[6].set()
+ m.wakeCheck();
+ },
+ remove() {
+ tech.isRewindField = false;
+ if (this.count) m.fieldUpgrades[6].set()
+ }
+ },
+ {
+ name: "frame-dragging", //"non-inertial frame",
+ description: "when not moving time dilation stops time +33% defense ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 1,
+ frequencyDefault: 1,
+ allowed() {
+ return m.fieldMode === 6
+ },
+ requires: "time dilation",
+ effect() {
+ tech.isTimeStop = true;
+ m.fieldHarmReduction = 0.66; //33% reduction
+ },
+ remove() {
+ tech.isTimeStop = false;
+ if (m.fieldMode === 6) m.fieldHarmReduction = 1;
+ }
+ },
+ {
+ name: "Lorentz transformation",
+ description: `use ${powerUps.orb.research(3)}+50% movement , jumping , and fire rate `,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (m.fieldMode === 6 || m.fieldMode === 8) && (build.isExperimentSelection || powerUps.research.count > 2)
+ },
+ requires: "time dilation or pilot wave",
+ effect() {
+ tech.isFastTime = true
+ m.setMovement();
+ b.setFireCD();
+ for (let i = 0; i < 3; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isFastTime = false
+ m.setMovement();
+ b.setFireCD();
+ if (this.count > 0) powerUps.research.changeRerolls(3)
+ }
+ },
+ {
+ name: "time crystals",
+ // description: "+150% passive energy generation ${}",
+ descriptionFunction() {
+ return `+150% passive energy generation(+${(150 * m.fieldRegen * 60).toFixed(1)} energy per second) `
+ },
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return !tech.isGroundState && (m.fieldMode === 6 || m.fieldMode === 8)
+ },
+ requires: "time dilation or pilot wave, not ground state",
+ effect() {
+ tech.isTimeCrystals = true
+ m.setFieldRegen()
+ this.descriptionFunction = function () {
+ return `+150% passive energy generation(+${(60 * m.fieldRegen * 60).toFixed(1)} energy per second) `
+ }
+ },
+ remove() {
+ tech.isTimeCrystals = false
+ m.setFieldRegen()
+ this.descriptionFunction = function () {
+ return `+150% passive energy generation(+${(150 * m.fieldRegen * 60).toFixed(1)} energy per second) `
+ }
+ }
+ },
+ {
+ name: "no-cloning theorem",
+ // descriptionFunction() { return `+45% chance to duplicate spawned power ups after a mob dies –2% duplication (${tech.duplicationChance()}) ` },
+ description: `+45% chance to duplicate spawned power ups after a mob dies –2% duplication `,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldMode === 6 || m.fieldMode === 7)
+ },
+ requires: "cloaking, time dilation",
+ effect() {
+ tech.cloakDuplication = 0.45
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.4);
+ },
+ remove() {
+ tech.cloakDuplication = 0
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ }
+ },
+ {
+ name: "metamaterial absorber", //quantum eraser
+ descriptionFunction() {
+ return `for each mob left alive after you exit a level there is a 17% chance to spawn a random power up `
+ },
+ // descriptionFunction() {
+ // return `for each mob left alive after you exit a level `
+ // },
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return (m.fieldMode === 7) && !tech.cloakDuplication
+ },
+ requires: "cloaking",
+ effect() {
+ tech.isQuantumEraser = true
+ },
+ remove() {
+ tech.isQuantumEraser = false
+ }
+ },
+ {
+ name: "symbiosis",
+ descriptionFunction() {
+ return `after a boss dies spawn ${powerUps.orb.research(3)}${powerUps.orb.heal(3)} and a tech after a mob dies –0.5 maximum ${tech.isEnergyHealth ? "energy " : "health "}`
+ },
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 7 //|| m.fieldMode === 6
+ },
+ requires: "cloaking",
+ effect() {
+ tech.isAddRemoveMaxHealth = true
+ },
+ remove() {
+ tech.isAddRemoveMaxHealth = false
+ }
+ },
+ {
+ name: "boson composite",
+ link: `boson composite `,
+ description: "while cloaked you are intangible to blocks and mobs, but mobs drain energy ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 7
+ },
+ requires: "metamaterial cloaking",
+ effect() {
+ tech.isIntangible = true;
+ },
+ remove() {
+ if (tech.isIntangible) {
+ tech.isIntangible = false;
+ player.collisionFilter.mask = cat.body | cat.map | cat.mob | cat.mobBullet | cat.mobShield //normal collisions
+ }
+ }
+ },
+ {
+ name: "patch",
+ link: `patch `,
+ description: "after cloaking recover 75% of your last health loss using that much energy ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 7 && !tech.lastHitDamage && !tech.isEnergyHealth
+ },
+ requires: "metamaterial cloaking, not dynamic equilibrium, mass-energy",
+ effect() {
+ tech.isCloakHealLastHit = true;
+ },
+ remove() {
+ tech.isCloakHealLastHit = false;
+ }
+ },
+ {
+ name: "dazzler",
+ link: `dazzler `,
+ description: "after decloaking stun nearby mobs and drain –15 energy ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 7
+ },
+ requires: "metamaterial cloaking",
+ effect() {
+ tech.isCloakStun = true;
+ },
+ remove() {
+ tech.isCloakStun = false;
+ }
+ },
+ // {
+ // name: "ambush",
+ // description: "metamaterial cloaking field damage effect is increased from 333% to 555% ",
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return m.fieldMode === 7
+ // },
+ // requires: "metamaterial cloaking",
+ // effect() {
+ // tech.sneakAttackDmg = 6.55 //555% + 100%
+ // },
+ // remove() {
+ // tech.sneakAttackDmg = 4.33 //333% + 100%
+ // }
+ // },
+ {
+ name: "dynamical systems",
+ description: `use ${powerUps.orb.research(2)}+35% damage `,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (m.fieldMode === 5 || m.fieldMode === 7 || m.fieldMode === 8) && (build.isExperimentSelection || powerUps.research.count > 1)
+ },
+ requires: "cloaking, pilot wave, or plasma torch",
+ damage: 1.35,
+ effect() {
+ tech.damage *= this.damage
+ tech.isCloakingDamage = true
+ for (let i = 0; i < 2; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.isCloakingDamage = false
+ if (this.count > 0) {
+ tech.damage /= this.damage
+ powerUps.research.changeRerolls(2)
+ }
+ }
+ },
+ {
+ name: "WIMPs",
+ description: `at the end of each level spawn ${powerUps.orb.research(4)} and a dangerous particle that slowly chases you`,
+ isFieldTech: true,
+ maxCount: 9,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 9 || m.fieldMode === 8 || m.fieldMode === 6
+ },
+ requires: "wormhole, pilot wave, time dilation",
+ effect() {
+ tech.wimpCount++
+ spawn.WIMP()
+ for (let j = 0, len = 4; j < len; j++) powerUps.spawn(level.exit.x + 100 * (Math.random() - 0.5), level.exit.y - 100 + 100 * (Math.random() - 0.5), "research", false)
+ },
+ remove() {
+ tech.wimpCount = 0
+ }
+ },
+ {
+ name: "vacuum fluctuation",
+ description: `use ${powerUps.orb.research(3)}+11% chance to duplicate spawned power ups `,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 3,
+ frequencyDefault: 3,
+ allowed() {
+ return (m.fieldMode === 8 || m.fieldMode === 3 || m.fieldMode === 6 || m.fieldMode === 9) && (build.isExperimentSelection || powerUps.research.count > 2)
+ },
+ requires: "wormhole, time dilation, negative mass, pilot wave",
+ effect() {
+ tech.fieldDuplicate = 0.11
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11);
+ for (let i = 0; i < 3; i++) {
+ if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1)
+ }
+ },
+ remove() {
+ tech.fieldDuplicate = 0
+ powerUps.setPowerUpMode(); //needed after adjusting duplication chance
+ if (this.count > 0) powerUps.research.changeRerolls(3)
+ }
+ },
+ // {
+ // name: "Penrose process",
+ // description: "after a block falls into a wormhole +50 energy ",
+ // isFieldTech: true,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // frequencyDefault: 2,
+ // allowed() {
+ // return m.fieldMode === 9
+ // },
+ // requires: "wormhole",
+ // effect() {
+ // tech.isWormholeEnergy = true
+ // },
+ // remove() {
+ // tech.isWormholeEnergy = false
+ // }
+ // },
+ {
+ name: "transdimensional worms",
+ link: `transdimensional worms `,
+ description: "after a block falls into a wormhole spawn a worm ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 9
+ },
+ requires: "wormhole",
+ effect() {
+ tech.isWormholeWorms = true
+ },
+ remove() {
+ tech.isWormholeWorms = false
+ }
+ },
+ {
+ name: "geodesics",
+ description: `your bullets can traverse wormholes spawn 2 guns and ${powerUps.orb.ammo(4)}`,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 9
+ },
+ requires: "wormhole",
+ effect() {
+ tech.isWormHoleBullets = true
+ for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x + 200 * (Math.random() - 0.5), m.pos.y + 200 * (Math.random() - 0.5), "gun");
+ for (let i = 0; i < 4; i++) powerUps.spawn(m.pos.x + 200 * (Math.random() - 0.5), m.pos.y + 200 * (Math.random() - 0.5), "ammo");
+ },
+ remove() {
+ if (tech.isWormHoleBullets) {
+ for (let i = 0; i < 2; i++) {
+ if (b.inventory.length) b.removeGun(b.guns[b.inventory[b.inventory.length - 1]].name) //remove your last gun
+ }
+ tech.isWormHoleBullets = false;
+ }
+ }
+ },
+ {
+ name: "cosmic string",
+ description: "after tunneling through mobs with a wormhole stun them and do radioactive damage ",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 9
+ },
+ requires: "wormhole",
+ effect() {
+ tech.isWormholeDamage = true
+ },
+ remove() {
+ tech.isWormholeDamage = false
+ }
+ },
+ {
+ name: "invariant",
+ description: "while placing your wormhole use energy to pause time",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 9 && !tech.isNoDraftPause
+ },
+ requires: "wormhole, not eternalism",
+ effect() {
+ tech.isWormHolePause = true
+ },
+ remove() {
+ if (tech.isWormHolePause && m.isBodiesAsleep) m.wakeCheck();
+ tech.isWormHolePause = false
+ }
+ },
+ {
+ name: "charmed baryons",
+ description: `–33% movement and jumping wormholes drain zero energy `,
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 9 && !tech.isWormholeMapIgnore
+ },
+ requires: "wormhole, not affine connection",
+ effect() {
+ tech.isFreeWormHole = true
+ tech.baseFx *= 0.66
+ tech.baseJumpForce *= 0.66
+ m.setMovement()
+ },
+ //also removed in m.setHoldDefaults() if player switches into a bad field
+ remove() {
+ tech.isFreeWormHole = false
+ if (!tech.isNeutronium) {
+ tech.baseFx = 0.08
+ tech.baseJumpForce = 10.5
+ m.setMovement()
+ }
+ }
+ },
+ {
+ name: "affine connection",
+ description: "wormholes can tunnel through anything for +200% energy drain",
+ isFieldTech: true,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ allowed() {
+ return m.fieldMode === 9 && !tech.isFreeWormHole
+ },
+ requires: "wormhole, not charmed baryons",
+ effect() {
+ tech.isWormholeMapIgnore = true
+ },
+ remove() {
+ tech.isWormholeMapIgnore = false
+ }
+ },
+ //**************************************************
+ //************************************************** experimental
+ //************************************************** modes
+ //**************************************************
+ // {
+ // name: "-ship-",
+ // description: "experiment: fly around with no legs aim with the keyboard",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isNonRefundable: true,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection && !m.isShipMode && m.fieldUpgrades[m.fieldMode].name !== "negative mass"
+ // },
+ // requires: "",
+ // effect() {
+ // m.shipMode()
+ // },
+ // remove() {}
+ // },
+ // {
+ // name: "-quantum leap-",
+ // description: "experiment: every 20 seconds become an alternate version of yourself",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection
+ // },
+ // requires: "",
+ // interval: undefined,
+ // effect() {
+ // this.interval = setInterval(() => {
+ // if (!build.isExperimentSelection) {
+ // m.switchWorlds()
+ // simulation.trails()
+ // }
+ // }, 20000); //every 20 seconds
+
+ // },
+ // remove() {
+ // if (this.count > 0) clearTimeout(this.interval);
+ // }
+ // },
+ // {
+ // name: "-shields-",
+ // description: "experiment: every 5 seconds all mobs gain a shield",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection
+ // },
+ // requires: "",
+ // effect() {
+ // this.interval = setInterval(() => {
+ // if (!build.isExperimentSelection) {
+ // for (let i = 0; i < mob.length; i++) {
+ // if (!mob[i].isShielded && !mob[i].shield && mob[i].isDropPowerUp) spawn.shield(mob[i], mob[i].position.x, mob[i].position.y, 1, true);
+ // }
+ // }
+ // }, 5000); //every 5 seconds
+ // },
+ // interval: undefined,
+ // remove() {
+ // if (this.count > 0) clearTimeout(this.interval);
+ // }
+ // },
+ // {
+ // name: "-Fourier analysis-",
+ // description: "experiment: your aiming is random",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection && !m.isShipMode
+ // },
+ // requires: "not ship",
+ // effect() {
+ // m.look = () => {
+ // m.angle = 2 * Math.sin(m.cycle * 0.0133) + Math.sin(m.cycle * 0.013) + 0.5 * Math.sin(m.cycle * 0.031) + 0.33 * Math.sin(m.cycle * 0.03)
+ // const scale = 0.8;
+ // m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ // m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+ // m.transX += (m.transSmoothX - m.transX) * 0.07;
+ // m.transY += (m.transSmoothY - m.transY) * 0.07;
+ // }
+ // },
+ // remove() {
+ // if (this.count > 0) m.look = m.lookDefault()
+ // }
+ // },
+ // {
+ // name: "-panopticon-",
+ // description: "experiment: mobs can always see you",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection
+ // },
+ // requires: "",
+ // effect() {
+ // this.interval = setInterval(() => {
+ // if (!build.isExperimentSelection) {
+ // for (let i = 0; i < mob.length; i++) {
+ // if (!mob[i].shield && mob[i].isDropPowerUp) {
+ // mob[i].locatePlayer()
+ // mob[i].seePlayer.yes = true;
+ // }
+ // }
+ // }
+ // }, 1000); //every 1 seconds
+ // },
+ // interval: undefined,
+ // remove() {
+ // if (this.count > 0) clearTimeout(this.interval);
+ // }
+ // },
+ // {
+ // name: "-decomposers-",
+ // description: "experiment: after they die mobs leave behind spawns",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isBadRandomOption: true,
+ // isExperimentalMode: true,
+ // allowed() {
+ // return build.isExperimentSelection
+ // },
+ // requires: "",
+ // effect() {
+ // tech.deathSpawns = 0.2
+ // },
+ // remove() {
+ // tech.deathSpawns = 0
+ // }
+ // },
+
+
+
+ //**************************************************
+ //************************************************** JUNK
+ //************************************************** tech
+ //**************************************************
+ // {
+ // name: "junk",
+ // description: "",
+ // maxCount: 9,
+ // count: 0,
+ // frequency: 0,
+ // isNonRefundable: true,
+ // isJunk: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+
+ // },
+ // remove() {}
+ // },
+ {
+ name: "swap meet",
+ description: "normal tech become JUNK and JUNK become normal tech ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ tech.tech[i].isJunk = !tech.tech[i].isJunk
+ if (tech.tech[i].isJunk) { } else { }
+
+ if (tech.tech[i].frequency > 0) {
+ tech.tech[i].frequency = 0
+ } else {
+ tech.tech[i].frequency = 2
+ }
+ }
+ },
+ remove() { }
+ },
+ // {
+ // name: "pocket dimension",
+ // description: "rotate tech descriptions into a higher spacial dimension",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isJunk: true,
+ // isNonRefundable: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+ // document.getElementById("choose-grid").classList.add("flipX");
+ // },
+ // remove() {}
+ // },
+ {
+ name: "random",
+ link: `random `,
+ delay: 333,
+ descriptionFunction() {
+ const delay = 333
+ const loop = () => {
+ if ((simulation.isChoosing) && m.alive && !build.isExperimentSelection) {
+ const dmg = Math.floor(27 * Math.random()) * 0.01
+ this.text = `+${(dmg * 100).toFixed(0).padStart(2, '0')}% damage `
+ this.damage = 1 + dmg
+ if (document.getElementById(`damage-JUNK-id${this.id}`)) document.getElementById(`damage-JUNK-id${this.id}`).innerHTML = this.text
+ setTimeout(() => {
+ loop()
+ }, delay);
+ }
+ }
+ setTimeout(() => {
+ loop()
+ }, delay);
+ this.id++
+ return `${this.text} `
+ },
+ maxCount: 3,
+ count: 0,
+ frequency: 1,
+ isJunk: true,
+ allowed() {
+ return !build.isExperimentSelection
+ },
+ requires: "NOT EXPERIMENT MODE",
+ damage: 0,
+ effect() {
+ tech.damage *= this.damage
+ },
+ remove() {
+ if (this.count > 0) tech.damage /= this.damage
+ }
+ },
+ {
+ name: "boost",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return !build.isExperimentSelection
+ },
+ requires: "NOT EXPERIMENT MODE",
+ effect() {
+ powerUps.spawnDelay("boost", this.spawnCount)
+ },
+ remove() { },
+ id: 0,
+ text: "",
+ delay: 100,
+ spawnCount: 0,
+ descriptionFunction() {
+ let count = 9999 * Math.random()
+ const loop = () => {
+ if ((simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0) //simulation.paused ||
+ count += 4.5
+ const waves = 2 * Math.sin(count * 0.0133) + Math.sin(count * 0.013) + 0.5 * Math.sin(count * 0.031) + 0.33 * Math.sin(count * 0.03)
+ this.spawnCount = Math.floor(100 * Math.abs(waves))
+ this.text = `spawn ${this.spawnCount.toLocaleString(undefined, { minimumIntegerDigits: 3 })} ${powerUps.orb.boost(1)} that give +${(powerUps.boost.damage * 100).toFixed(0)}% damage for ${(powerUps.boost.duration / 60).toFixed(0)} seconds`
+ if (document.getElementById(`boost-JUNK-id${this.id}`)) document.getElementById(`boost-JUNK-id${this.id}`).innerHTML = this.text
+ setTimeout(() => {
+ loop()
+ }, this.delay);
+ }
+ }
+ setTimeout(() => {
+ loop()
+ }, this.delay);
+ this.id++
+ return `${this.text} `
+ },
+ },
+ {
+ name: "placebo",
+ description: "+777% damage +777% defense ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ if (Math.random() < 0.1) tech.damage *= 8.77
+ },
+ remove() { }
+ },
+ {
+ name: "universal healthcare",
+ description: "make your damage negative",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.damage *= -1
+ },
+ remove() { }
+ },
+ // {
+ // name: "synchrotron",
+ // descriptionFunction() {
+ // return `power ups change into a different flavor after a boss dies`
+ // },
+ // maxCount: 3,
+ // count: 0,
+ // frequency: 1,
+ // frequencyDefault: 1,
+ // allowed: () => true,
+ // requires: "",
+ // effect() {
+ // },
+ // remove() {
+ // }
+ // },
+ {
+ name: "return",
+ description: "return to the start of the game reduce combat difficulty by 2 levels ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ level.difficultyDecrease(simulation.difficultyMode * 2)
+ level.onLevel = 0
+ simulation.clearNow = true //end current level
+ },
+ remove() { }
+ },
+ {
+ name: "panpsychism",
+ description: "awaken all blocks blocks have a chance to spawn power ups",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ setInterval(() => {
+ for (let i = body.length - 1; i > -1; i--) {
+ if (!body[i].isNotHoldable) {
+ Matter.Composite.remove(engine.world, body[i]);
+ spawn.blockMob(body[i].position.x, body[i].position.y, body[i], 0);
+ if (!body[i].isAboutToBeRemoved) mob[mob.length - 1].isDropPowerUp = true
+ body.splice(i, 1);
+ }
+ }
+ }, 6000);
+ },
+ remove() { }
+ },
+ {
+ name: "meteor shower",
+ description: "take a shower, but meteors instead of water",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ setInterval(() => {
+
+ fireBlock = function (xPos, yPos) {
+ const index = body.length
+ spawn.bodyRect(xPos, yPos, 20 + 50 * Math.random(), 20 + 50 * Math.random());
+ const bodyBullet = body[index]
+ Matter.Body.setVelocity(bodyBullet, {
+ x: 5 * (Math.random() - 0.5),
+ y: 10 * (Math.random() - 0.5)
+ });
+ bodyBullet.isAboutToBeRemoved = true
+ setTimeout(() => { //remove block
+ for (let i = 0; i < body.length; i++) {
+ if (body[i] === bodyBullet) {
+ Matter.Composite.remove(engine.world, body[i]);
+ body.splice(i, 1);
+ }
+ }
+ }, 4000 + Math.floor(9000 * Math.random()));
+ }
+ fireBlock(player.position.x + 600 * (Math.random() - 0.5), player.position.y - 500 - 500 * Math.random());
+ // for (let i = 0, len = Math.random(); i < len; i++) {
+ // }
+
+ }, 1000);
+ },
+ remove() { }
+ },
+ {
+ name: "startle response",
+ description: `if a threat is nearby, activate a ${powerUps.orb.boost(1)} and lock your mouse until you press escape`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ // tech.damage *= 1.33
+ setInterval(() => {
+ if (powerUps.boost.endCycle < m.cycle && !simulation.paused && m.alive) {
+ for (let i = 0; i < mob.length; i++) {
+ if (mob[i].distanceToPlayer2() < 400000) { //650
+ canvas.requestPointerLock();
+ powerUps.boost.effect();
+ break
+ }
+ }
+ }
+ }, 2000);
+ },
+ remove() { }
+ },
+ {
+ name: "closed timelike curve",
+ description: "spawn 5 field power ups, but every 12 seconds teleport a second into your future or past",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "field");
+
+ function loop() {
+ if (!simulation.paused && m.alive) {
+ if (!(simulation.cycle % 720)) {
+ requestAnimationFrame(() => {
+ if ((simulation.cycle % 1440) > 720) { //kinda alternate between each option
+ m.rewind(60)
+ m.energy += 0.4 //to make up for lost energy
+ } else {
+ simulation.timePlayerSkip(60)
+ }
+ }); //wrapping in animation frame prevents errors, probably
+ }
+ }
+ requestAnimationFrame(loop);
+ }
+ requestAnimationFrame(loop);
+ },
+ remove() { }
+ },
+ // {
+ // name: "translate",
+ // description: "translate n-gon into a random language",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isJunk: true,
+ // isNonRefundable: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+ // // generate a container
+ // const gtElem = document.createElement('div')
+ // gtElem.id = "gtElem"
+ // gtElem.style.visibility = 'hidden' // make it invisible
+ // document.body.append(gtElem)
+
+ // // generate a script to run after creation
+ // function initGT() {
+ // // create a new translate element
+ // new google.translate.TranslateElement({ pageLanguage: 'en', layout: google.translate.TranslateElement.InlineLayout.HORIZONTAL }, 'gtElem')
+ // // ok now since it's loaded perform a funny hack to make it work
+ // const langSelect = document.getElementsByClassName("goog-te-combo")[0]
+ // // select a random language. It takes a second for all langauges to load, so wait a second.
+ // setTimeout(() => {
+ // langSelect.selectedIndex = Math.round(langSelect.options.length * Math.random())
+ // // simulate a click
+ // langSelect.dispatchEvent(new Event('change'))
+ // // now make it go away
+ // const bar = document.getElementById(':1.container')
+ // bar.style.display = 'none'
+ // bar.style.visibility = 'hidden'
+ // }, 1000)
+
+ // }
+
+ // // add the google translate script
+ // const translateScript = document.createElement('script')
+ // translateScript.src = '//translate.google.com/translate_a/element.js?cb=initGT'
+ // document.body.append(translateScript)
+ // },
+ // remove() {}
+ // },
+ {
+ name: "discount",
+ description: "get 3 random JUNK tech for the price of 1!",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.giveRandomJUNK()
+ tech.giveRandomJUNK()
+ tech.giveRandomJUNK()
+ },
+ remove() { }
+ },
+ // {
+ // name: "hi",
+ // description: `spawn to seed 616 `,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isNonRefundable: true,
+ // isJunk: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+ // document.getElementById("seed").placeholder = Math.initialSeed = String(616)
+ // Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it
+ // },
+ // remove() {}
+ // },
+ {
+ name: "Higgs phase transition",
+ description: "instantly spawn 5 tech , but add a chance to remove everything with a 5 minute half-life ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ powerUps.spawn(m.pos.x, m.pos.y, "tech");
+ powerUps.spawn(m.pos.x + 30, m.pos.y, "tech");
+ powerUps.spawn(m.pos.x + 60, m.pos.y, "tech");
+ powerUps.spawn(m.pos.x, m.pos.y - 30, "tech");
+ powerUps.spawn(m.pos.x + 30, m.pos.y - 60, "tech");
+
+ function loop() {
+ // (1-X)^cycles = chance to be removed //Math.random() < 0.000019 10 min
+ if (!simulation.paused && m.alive) {
+ if (Math.random() < 0.000038) {
+ // m.death();
+ simulation.clearMap();
+ simulation.draw.setPaths();
+ return
+ }
+ }
+ requestAnimationFrame(loop);
+ }
+ requestAnimationFrame(loop);
+ },
+ remove() { }
+ },
+ {
+ name: "harvest",
+ description: "convert all the mobs on this level into ammo ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].isDropPowerUp) {
+ powerUps.directSpawn(mob[i].position.x, mob[i].position.y, "ammo");
+ mob[i].death();
+ }
+ }
+ // for (let i = powerUp.length - 1; i > -1; i--) {
+ // if (powerUp[i].name !== "ammo") {
+ // Matter.Composite.remove(engine.world, powerUp[i]);
+ // powerUp.splice(i, 1);
+ // }
+ // }
+ },
+ remove() { }
+ },
+ {
+ name: "brainstorm",
+ description: "the tech choice menu randomizes every 0.5 seconds for 10 seconds",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isJunk: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ tech.isBrainstorm = true
+ tech.isBrainstormActive = false
+ tech.brainStormDelay = 500
+ },
+ remove() {
+ tech.isBrainstorm = false
+ tech.isBrainstormActive = false
+ }
+ },
+ {
+ name: "catabolysis",
+ description: `set your maximum health to 1 double your current ammo 10 times`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return !tech.isFallingDamage && !tech.isOverHeal && !tech.isEnergyHealth
+ },
+ requires: "not quenching, tungsten carbide, mass-energy",
+ effect() {
+ m.baseHealth = 0.01
+ m.setMaxHealth();
+ for (let i = 0; i < b.guns.length; i++) b.guns[i].ammo = b.guns[i].ammo * Math.pow(2, 10)
+ simulation.updateGunHUD();
+ },
+ remove() { }
+ },
+ {
+ name: "palantír",
+ description: `see far away lands`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ // isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ m.look = () => {
+ //always on mouse look
+ m.angle = Math.atan2(
+ simulation.mouseInGame.y - m.pos.y,
+ simulation.mouseInGame.x - m.pos.x
+ );
+ //smoothed mouse look translations
+ const scale = 2;
+ m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+ m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing;
+ m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing;
+ }
+ },
+ remove() {
+ if (this.count) m.look = m.lookDefault
+ }
+ },
+ {
+ name: "motion sickness",
+ description: `disable camera smoothing`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ // isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ m.look = () => {
+ //always on mouse look
+ m.angle = Math.atan2(
+ simulation.mouseInGame.y - m.pos.y,
+ simulation.mouseInGame.x - m.pos.x
+ );
+ //smoothed mouse look translations
+ const scale = 1.2;
+ m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+ m.transX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+ // m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing;
+ // m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing;
+ }
+ },
+ remove() {
+ if (this.count) m.look = m.lookDefault
+ }
+ },
+ {
+ name: "facsimile",
+ description: `inserts a copy of your current level into the level list`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ const index = Math.min(level.levels.length - 1, level.onLevel)
+ level.levels.splice(index, 0, level.levels[index]);
+ },
+ remove() { }
+ },
+ {
+ name: "negative friction",
+ description: "when you touch walls you speed up instead of slowing down. It's kinda fun.",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ player.friction = -0.4
+ },
+ remove() {
+ if (this.count) player.friction = 0.002
+ }
+ },
+ {
+ name: "bounce",
+ description: "you bounce off things. It's annoying, but not that bad.",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ player.restitution = 0.9
+ },
+ remove() {
+ if (this.count) player.restitution = 0
+ }
+ },
+ {
+ name: "mouth",
+ description: "mobs have a non functional mouth",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ mobs.draw = () => {
+ ctx.lineWidth = 2;
+ let i = mob.length;
+ while (i--) {
+ ctx.beginPath();
+ const vertices = mob[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
+ ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y);
+ ctx.fillStyle = mob[i].fill;
+ ctx.strokeStyle = mob[i].stroke;
+ ctx.fill();
+ ctx.stroke();
+ }
+ }
+ },
+ remove() {
+ mobs.draw = mobs.drawDefault
+ }
+ },
+ {
+ name: "all-stars",
+ description: "make all mobs look like stars",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ mobs.draw = () => {
+ ctx.lineWidth = 2;
+ let i = mob.length;
+ while (i--) {
+ ctx.beginPath();
+ const vertices = mob[i].vertices;
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (let j = 1, len = vertices.length; j < len; ++j) ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[j].x, vertices[j].y);
+ ctx.quadraticCurveTo(mob[i].position.x, mob[i].position.y, vertices[0].x, vertices[0].y);
+ ctx.fillStyle = mob[i].fill;
+ ctx.strokeStyle = mob[i].stroke;
+ ctx.fill();
+ ctx.stroke();
+ }
+ }
+ },
+ remove() {
+ mobs.draw = mobs.drawDefault
+ }
+ },
+ // draw() {
+ // ctx.lineWidth = 2;
+ // let i = mob.length;
+ // while (i--) {
+ // ctx.beginPath();
+ // const vertices = mob[i].vertices;
+ // ctx.moveTo(vertices[0].x, vertices[0].y);
+ // for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
+ // ctx.lineTo(vertices[0].x, vertices[0].y);
+ // ctx.fillStyle = mob[i].fill;
+ // ctx.strokeStyle = mob[i].stroke;
+ // ctx.fill();
+ // ctx.stroke();
+ // }
+ // },
+ {
+ name: "true colors",
+ description: `set all power ups to their real world colors`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ // const colors = shuffle(["#f7b", "#0eb", "#467", "#0cf", "hsl(246,100%,77%)", "#26a"])
+ const colors = shuffle([powerUps.research.color, powerUps.heal.color, powerUps.ammo.color, powerUps.ammo.color, powerUps.field.color, powerUps.gun.color])
+ powerUps.research.color = colors[0]
+ powerUps.heal.color = colors[1]
+ powerUps.ammo.color = colors[2]
+ powerUps.field.color = colors[3]
+ powerUps.tech.color = colors[4]
+ powerUps.gun.color = colors[5]
+ for (let i = 0; i < powerUp.length; i++) {
+ switch (powerUp[i].name) {
+ case "research":
+ powerUp[i].color = colors[0]
+ break;
+ case "heal":
+ powerUp[i].color = colors[1]
+ break;
+ case "ammo":
+ powerUp[i].color = colors[2]
+ break;
+ case "field":
+ powerUp[i].color = colors[3]
+ break;
+ case "tech":
+ powerUp[i].color = colors[4]
+ break;
+ case "gun":
+ powerUp[i].color = colors[5]
+ break;
+ }
+ }
+ },
+ remove() {
+ // const colors = ["#f7b", "#0eb", "#467", "#0cf", "hsl(246,100%,77%)", "#26a"] //no shuffle
+ // powerUps.research.color = colors[0]
+ // powerUps.heal.color = colors[1]
+ // powerUps.ammo.color = colors[2]
+ // powerUps.field.color = colors[3]
+ // powerUps.tech.color = colors[4]
+ // powerUps.gun.color = colors[5]
+ // for (let i = 0; i < powerUp.length; i++) {
+ // switch (powerUp[i].name) {
+ // case "research":
+ // powerUp[i].color = colors[0]
+ // break;
+ // case "heal":
+ // powerUp[i].color = colors[1]
+ // break;
+ // case "ammo":
+ // powerUp[i].color = colors[2]
+ // break;
+ // case "field":
+ // powerUp[i].color = colors[3]
+ // break;
+ // case "tech":
+ // powerUp[i].color = colors[4]
+ // break;
+ // case "gun":
+ // powerUp[i].color = colors[5]
+ // break;
+ // }
+ // }
+ }
+ },
+ {
+ name: "emergency broadcasting",
+ description: "emit 2 sine waveforms at 853 Hz and 960 Hzlower your volume ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect: () => {
+ //setup audio context
+ function tone(frequency) {
+ const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
+ const oscillator1 = audioCtx.createOscillator();
+ const gainNode1 = audioCtx.createGain();
+ gainNode1.gain.value = 0.5; //controls volume
+ oscillator1.connect(gainNode1);
+ gainNode1.connect(audioCtx.destination);
+ oscillator1.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
+ oscillator1.frequency.value = frequency; // value in hertz
+ oscillator1.start();
+ return audioCtx
+ }
+ // let sound = tone(1050)
+
+ function EBS() {
+ const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
+
+ const oscillator1 = audioCtx.createOscillator();
+ const gainNode1 = audioCtx.createGain();
+ gainNode1.gain.value = 0.3; //controls volume
+ oscillator1.connect(gainNode1);
+ gainNode1.connect(audioCtx.destination);
+ oscillator1.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
+ oscillator1.frequency.value = 850; // value in hertz
+ oscillator1.start();
+
+ const oscillator2 = audioCtx.createOscillator();
+ const gainNode2 = audioCtx.createGain();
+ gainNode2.gain.value = 0.3; //controls volume
+ oscillator2.connect(gainNode2);
+ gainNode2.connect(audioCtx.destination);
+ oscillator2.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
+ oscillator2.frequency.value = 957; // value in hertz
+ oscillator2.start();
+ return audioCtx
+ }
+ let sound = EBS()
+
+ delay = 1000
+ setTimeout(() => {
+ sound.suspend()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ setTimeout(() => {
+ sound.resume()
+ setTimeout(() => {
+ sound.suspend()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ setTimeout(() => {
+ sound.resume()
+ setTimeout(() => {
+ sound.suspend()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ setTimeout(() => {
+ sound.resume()
+ setTimeout(() => {
+ sound.suspend()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ setTimeout(() => {
+ sound.resume()
+ setTimeout(() => {
+ sound.suspend()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ setTimeout(() => {
+ sound.resume()
+ setTimeout(() => {
+ sound.suspend()
+ sound.close()
+ powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ }, delay);
+ }, delay);
+ }, delay);
+ }, delay);
+ }, delay);
+ }, delay);
+ }, delay);
+ }, delay);
+ }, delay);
+ }, delay);
+ }, delay);
+ },
+ remove() { }
+ },
+ {
+ name: "automatic",
+ description: "you can't fire when moving always fire when at rest ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !tech.isFireMoveLock
+ },
+ requires: "not Higgs mechanism",
+ effect() {
+ tech.isAlwaysFire = true;
+ b.setFireMethod();
+ },
+ remove() {
+ if (tech.isAlwaysFire) {
+ tech.isAlwaysFire = false
+ b.setFireMethod();
+ }
+ }
+ },
+ {
+ name: "hidden variable",
+ descriptionFunction() {
+ return `spawn ${powerUps.orb.heal(20)} but hide your health bar`
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ document.getElementById("health").style.display = "none"
+ document.getElementById("health-bg").style.display = "none"
+ document.getElementById("defense-bar").style.display = "none"
+ for (let i = 0; i < 20; i++) powerUps.spawn(m.pos.x + 160 * (Math.random() - 0.5), m.pos.y + 160 * (Math.random() - 0.5), "heal");
+ },
+ remove() { }
+ },
+ {
+ name: "not a bug",
+ description: "initiate a totally safe game crash for 10 seconds",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ const savedfunction = simulation.drawCircle
+ simulation.drawCircle = () => {
+ const a = mob[Infinity].position //crashed the game in a visually interesting way, because of the ctx.translate command is never reverted in the main game loop
+ }
+ setTimeout(() => {
+ simulation.drawCircle = savedfunction
+ canvas.width = canvas.width //clears the canvas // works on chrome at least
+ powerUps.spawn(m.pos.x, m.pos.y, "tech");
+ }, 10000);
+
+ // for (;;) {} //freezes the tab
+ },
+ remove() { }
+ },
+ {
+ name: "spinor",
+ description: "the direction you aim is determined by your position",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.look = function () {
+ //always on mouse look
+ m.angle = (((m.pos.x + m.pos.y) / 100 + Math.PI) % Math.PI * 2) - Math.PI
+ //smoothed mouse look translations
+ const scale = 0.8;
+ m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+
+ m.transX += (m.transSmoothX - m.transX) * 0.07;
+ m.transY += (m.transSmoothY - m.transY) * 0.07;
+ }
+ },
+ remove() {
+ if (this.count) m.look = m.lookDefault
+ }
+ },
+ {
+ name: "p-zombie",
+ description: "set your health to 1 all mobs, not bosses, die and resurrect as zombies",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ m.health = 0.01 //set health to 1
+ m.displayHealth();
+ for (let i = mob.length - 1; i > -1; i--) { //replace mobs with zombies
+ if (mob[i].isDropPowerUp && !mob[i].isBoss && mob[i].alive) {
+ mob[i].isSoonZombie = true
+ mob[i].death()
+ }
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "decomposers",
+ description: "after they die mobs leave behind spawns ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return tech.deathSpawns === 0
+ },
+ requires: "",
+ effect() {
+ tech.deathSpawns = 0.2
+ },
+ remove() {
+ tech.deathSpawns = 0
+ }
+ },
+ {
+ name: "panopticon",
+ description: "mobs can always see you",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ for (let i = 0; i < mob.length; i++) {
+ if (!mob[i].shield && mob[i].isDropPowerUp) {
+ mob[i].locatePlayer()
+ mob[i].seePlayer.yes = true;
+ }
+ }
+ }, 1000); //every 1 seconds
+ },
+ remove() { }
+ },
+ // {
+ // name: "inverted mouse",
+ // description: "your mouse is scrambled it's fine, just rotate it 90 degrees",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isExperimentHide: true,
+ // isNonRefundable: true,
+ // isJunk: true,
+ // allowed() {
+ // return !m.isShipMode
+ // },
+ // requires: "not ship",
+ // effect() {
+ // document.body.addEventListener("mousemove", (e) => {
+ // const ratio = window.innerWidth / window.innerHeight
+ // simulation.mouse.x = e.clientY * ratio
+ // simulation.mouse.y = e.clientX / ratio;
+ // });
+ // },
+ // remove() {
+ // // m.look = m.lookDefault
+ // }
+ // },
+ {
+ name: "Fourier analysis",
+ description: "your aiming is now controlled by this equation:2sin(0.0133t) + sin(0.013t) + 0.5sin(0.031t)+ 0.33sin(0.03t) ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "not ship",
+ effect() {
+ m.look = () => {
+ m.angle = 2 * Math.sin(m.cycle * 0.0133) + Math.sin(m.cycle * 0.013) + 0.5 * Math.sin(m.cycle * 0.031) + 0.33 * Math.sin(m.cycle * 0.03)
+ const scale = 0.8;
+ simulation.mouse.y
+ m.transSmoothX = canvas.width2 - m.pos.x - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y - (simulation.mouse.y - canvas.height2) * scale;
+ m.transX += (m.transSmoothX - m.transX) * 0.07;
+ m.transY += (m.transSmoothY - m.transY) * 0.07;
+ }
+ },
+ remove() {
+ if (this.count) m.look = m.lookDefault
+ }
+ },
+ {
+ name: "disintegrated armament",
+ description: "spawn a gun remove your active gun ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return b.inventory.length > 0
+ },
+ requires: "at least 1 gun",
+ effect() {
+ if (b.inventory.length > 0) b.removeGun(b.guns[b.activeGun].name)
+ simulation.makeGunHUD()
+ powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun");
+ },
+ remove() { }
+ },
+ {
+ name: "probability",
+ description: "increase the frequency of one random tech by 100 ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ let options = []; //find what tech I could get
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (
+ tech.tech[i].count < tech.tech[i].maxCount &&
+ tech.tech[i].allowed() &&
+ !tech.tech[i].isJunk &&
+ !tech.tech.isLore
+ ) {
+ options.push(i);
+ }
+ }
+ if (options.length) {
+ const index = options[Math.floor(Math.random() * options.length)]
+ tech.tech[index].frequency = 100
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "encryption",
+ description: "secure tech information",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ String.prototype.shuffle = function () {
+ var a = this.split(""),
+ n = a.length;
+
+ for (var i = n - 1; i > 0; i--) {
+ var j = Math.floor(Math.random() * (i + 1));
+ var tmp = a[i];
+ a[i] = a[j];
+ a[j] = tmp;
+ }
+ return a.join("");
+ }
+
+ for (let i = 0, len = tech.tech.length; i < len; i++) tech.tech[i].name = tech.tech[i].name.shuffle()
+ },
+ remove() { }
+ },
+ {
+ name: "quantum leap",
+ description: "become an alternate version of yourself every 20 seconds",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ m.switchWorlds()
+ simulation.trails()
+ }, 20000); //every 30 seconds
+ },
+ remove() { }
+ },
+ {
+ name: "score",
+ description: "Add a score to n-gon!",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ let score = Math.ceil(1000 * Math.random() * Math.random() * Math.random() * Math.random() * Math.random())
+ simulation.makeTextLog(`simulation.score = ${score.toFixed(0)}`);
+ }, 10000); //every 10 seconds
+ },
+ remove() { }
+ },
+ {
+ name: "pop-ups",
+ description: "sign up to learn endless easy ways to win n-gon that Landgreen doesn't want you to know!!!1!!",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ alert(`The best combo is ${tech.tech[Math.floor(Math.random() * tech.tech.length)].name} with ${tech.tech[Math.floor(Math.random() * tech.tech.length)].name}!`);
+ }, 30000); //every 30 seconds
+ },
+ remove() { }
+ },
+ {
+ name: "music",
+ description: "add music to n-gon",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ window.open('https://www.youtube.com/watch?v=lEbHeSdmS-k&list=PL9Z5wjoBiPKEDhwCW2RN-VZoCpmhIojdn', '_blank')
+ },
+ remove() { }
+ },
+ {
+ name: "performance",
+ description: "display performance stats to n-gon",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ (function () {
+ var script = document.createElement('script');
+ script.onload = function () {
+ var stats = new Stats();
+ document.body.appendChild(stats.dom);
+ requestAnimationFrame(function loop() {
+ stats.update();
+ requestAnimationFrame(loop)
+ });
+ };
+ script.src = 'https://unpkg.com/stats.js@0.17.0/build/stats.min.js';
+ document.head.appendChild(script);
+ })()
+ //move health to the right
+ document.getElementById("health").style.left = "86px"
+ document.getElementById("health-bg").style.left = "86px"
+ document.getElementById("defense-bar").style.left = "86px"
+ document.getElementById("damage-bar").style.left = "86px"
+ },
+ remove() { }
+ },
+ {
+ name: "repartitioning",
+ description: "set the frequency of finding normal tech to 0 spawn 5 tech ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0, len = tech.tech.length; i < len; i++) {
+ if (tech.tech[i].isJunk) {
+ tech.tech[i].frequency = 2
+ } else {
+ tech.tech[i].frequency = 0
+ }
+ }
+ for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x, m.pos.y, "tech");
+ },
+ remove() { }
+ },
+ {
+ name: "defragment",
+ description: "set the frequency of finding JUNK tech to zero",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = tech.tech.length - 1; i > 0; i--) {
+ if (tech.tech[i].isJunk) tech.tech[i].frequency = 0
+ }
+ },
+ remove() { }
+ },
+ // {
+ // name: "lubrication",
+ // description: "reduce block density and friction for this level",
+ // maxCount: 9,
+ // count: 0,
+ // frequency: 0,
+ // isNonRefundable: true,
+ // isExperimentHide: true,
+ // isJunk: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+ // for (let i = 0; i < body.length; i++) {
+ // Matter.Body.setDensity(body[i], 0.0001) // 0.001 is normal
+ // body[i].friction = 0.01
+ // }
+ // },
+ // remove() {}
+ // },
+ {
+ name: "pitch",
+ description: "oscillate the pitch of your world",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ if (!simulation.paused) ctx.rotate(0.001 * Math.sin(simulation.cycle * 0.01))
+ }, 16);
+ },
+ remove() { }
+ },
+ {
+ name: "flatland",
+ description: "map blocks line of sight",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() { return true },
+ requires: "",
+ effect() {
+ simulation.ephemera.push({
+ name: "LoS", count: 0, do() {
+ const pos = m.pos
+ const radius = 3000
+ if (!simulation.isTimeSkipping) {
+ const vertices = simulation.sight.circleLoS(pos, radius);
+ if (vertices.length) {
+ ctx.beginPath();
+ ctx.moveTo(vertices[0].x, vertices[0].y);
+ for (var i = 1; i < vertices.length; i++) {
+ var currentDistance = Math.sqrt((vertices[i - 1].x - pos.x) ** 2 + (vertices[i - 1].y - pos.y) ** 2);
+ var newDistance = Math.sqrt((vertices[i].x - pos.x) ** 2 + (vertices[i].y - pos.y) ** 2);
+ if (Math.abs(currentDistance - radius) < 1 && Math.abs(newDistance - radius) < 1) {
+ const currentAngle = Math.atan2(vertices[i - 1].y - pos.y, vertices[i - 1].x - pos.x);
+ const newAngle = Math.atan2(vertices[i].y - pos.y, vertices[i].x - pos.x);
+ ctx.arc(pos.x, pos.y, radius, currentAngle, newAngle);
+ } else {
+ ctx.lineTo(vertices[i].x, vertices[i].y)
+ }
+ }
+ newDistance = Math.sqrt((vertices[0].x - pos.x) ** 2 + (vertices[0].y - pos.y) ** 2);
+ currentDistance = Math.sqrt((vertices[vertices.length - 1].x - pos.x) ** 2 + (vertices[vertices.length - 1].y - pos.y) ** 2);
+ if (Math.abs(currentDistance - radius) < 1 && Math.abs(newDistance - radius) < 1) {
+ const currentAngle = Math.atan2(vertices[vertices.length - 1].y - pos.y, vertices[vertices.length - 1].x - pos.x);
+ const newAngle = Math.atan2(vertices[0].y - pos.y, vertices[0].x - pos.x);
+ ctx.arc(pos.x, pos.y, radius, currentAngle, newAngle);
+ } else {
+ ctx.lineTo(vertices[0].x, vertices[0].y)
+ }
+
+ //stroke the map, so it looks different form the line of sight
+ ctx.strokeStyle = "#234";
+ ctx.lineWidth = 9;
+ ctx.stroke(simulation.draw.mapPath); //this has a pretty large impact on performance, maybe 5% worse performance
+
+ ctx.globalCompositeOperation = "destination-in";
+ ctx.fillStyle = "#000";
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over";
+ // also see the map
+ // ctx.fill(simulation.draw.mapPath);
+ // ctx.fillStyle = "#000";
+ ctx.clip();
+ }
+ }
+ },
+ })
+ },
+ remove() { }
+ },
+ {
+ name: "umbra",
+ description: "produce a blue glow around everything and probably some simulation lag",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ ctx.shadowColor = '#06f';
+ ctx.shadowBlur = 25;
+ },
+ remove() { }
+ },
+ {
+ name: "lighter",
+ description: `ctx.globalCompositeOperation = "lighter"`,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ ctx.globalCompositeOperation = "lighter";
+ },
+ remove() { }
+ },
+ {
+ name: "rewind",
+ description: "every 10 seconds rewind 2 seconds",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ m.rewind(120)
+ m.energy += 0.4
+ }, 10000);
+ // for (let i = 0; i < 24; i++) {
+ // setTimeout(() => { m.rewind(120) }, i * 5000);
+ // }
+ },
+ remove() { }
+ },
+ {
+ name: "undo",
+ description: "every 4 seconds rewind 1/2 a second",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ m.rewind(30)
+ m.energy += 0.2
+ }, 4000);
+ },
+ remove() { }
+ },
+ {
+ name: "energy to mass conversion",
+ description: "convert your energy into blocks ",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0, len = 40; i < len; i++) {
+ setTimeout(() => {
+ m.energy -= 1 / len
+ where = Vector.add(m.pos, { x: 400 * (Math.random() - 0.5), y: 400 * (Math.random() - 0.5) })
+ spawn.bodyRect(where.x, where.y, Math.floor(15 + 100 * Math.random()), Math.floor(15 + 100 * Math.random()));
+ }, i * 100);
+ }
+
+ },
+ remove() { }
+ },
+ {
+ name: "level.nextLevel()",
+ description: "advance to the next level",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ level.nextLevel();
+ },
+ remove() { }
+ },
+ {
+ name: "reincarnation",
+ description: "kill all mobs and spawn new ones (also spawn a few extra mobs for fun)",
+ maxCount: 3,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ spawn.setSpawnList();
+ spawn.setSpawnList();
+ for (let i = 0, len = mob.length; i < len; i++) {
+ if (mob[i].alive && !mob[i].shield && !mob[i].isBadTarget) {
+ const pick = spawn.pickList[Math.floor(Math.random() * spawn.pickList.length)];
+ spawn[pick](mob[i].position.x, mob[i].position.y);
+ if (Math.random() < 0.5) spawn[pick](mob[i].position.x, mob[i].position.y);
+ mob[i].death();
+ }
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "expert system",
+ description: "spawn a tech power up+64% JUNK to tech pool",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ powerUps.spawn(m.pos.x, m.pos.y, "tech");
+ tech.addJunkTechToPool(0.64)
+ },
+ remove() { }
+ },
+ {
+ name: "energy investment",
+ description: "every 10 seconds drain your energy return it doubled 5 seconds later",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ if (!simulation.paused) {
+ const energy = m.energy
+ m.energy = 0
+ setTimeout(() => { //return energy
+ m.energy += 2 * energy
+ }, 5000);
+ }
+ }, 10000);
+ },
+ remove() { }
+ },
+ {
+ name: "missile launching system",
+ description: "fire missiles for the next 120 seconds",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0; i < 120; i++) {
+ setTimeout(() => {
+ const where = {
+ x: m.pos.x,
+ y: m.pos.y - 40
+ }
+ b.missile(where, -Math.PI / 2 + 0.2 * (Math.random() - 0.5) * Math.sqrt(tech.missileCount), -2)
+ }, i * 1000);
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "grenade production",
+ description: "drop a grenade every 2 seconds",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ if (!simulation.paused && document.visibilityState !== "hidden") {
+ b.grenade(Vector.add(m.pos, {
+ x: 10 * (Math.random() - 0.5),
+ y: 10 * (Math.random() - 0.5)
+ }), -Math.PI / 2) //fire different angles for each grenade
+ const who = bullet[bullet.length - 1]
+ Matter.Body.setVelocity(who, {
+ x: who.velocity.x * 0.1,
+ y: who.velocity.y * 0.1
+ });
+ }
+ }, 2000);
+ },
+ remove() { }
+ },
+ {
+ name: "stubs",
+ description: "no knees or toes are drawn on the player you can wall climb though",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.skin.stubs()
+ Matter.Body.scale(player.parts[3], 2, 2);
+ },
+ remove() {
+ // if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "Sleipnir",
+ description: "grow more legs",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.skin.Sleipnir()
+ },
+ remove() {
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "diegesis",
+ description: "indicate fire cooldown through a rotation of your head",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.skin.diegesis()
+ },
+ remove() {
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "🐱",
+ description: "🐈",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.skin.cat();
+ },
+ remove() {
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "n-gone",
+ description: "become invisible to yourselfmobs can still see you ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ m.draw = () => { }
+ },
+ remove() {
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "pareidolia",
+ description: "don't",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.skin.pareidolia()
+ },
+ remove() {
+ if (this.count) m.resetSkin();
+ }
+ },
+ {
+ name: "posture",
+ description: "stand a bit taller",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ m.yOffWhen.stand = 70
+ },
+ remove() {
+ m.yOffWhen.stand = 49
+ }
+ },
+ {
+ name: "rhythm",
+ description: "you oscillate up and down",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return !m.isShipMode
+ },
+ requires: "",
+ effect() {
+ setInterval(() => {
+ m.yOffWhen.stand = 53 + 28 * Math.sin(simulation.cycle * 0.2)
+ if (m.onGround && !m.crouch) m.yOffGoal = m.yOffWhen.stand
+ }, 100);
+ },
+ remove() { }
+ },
+ {
+ name: "prism",
+ description: "you cycle through different colors ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ m.color = {
+ hue: 0,
+ sat: 100,
+ light: 50
+ }
+ setInterval(function () {
+ m.color.hue++
+ m.setFillColors()
+ }, 10);
+ },
+ remove() { }
+ },
+ // {
+ // name: "microtransactions",
+ // description: `when you choose a tech you can use ${powerUps.orb.research(1)} to buy a free in game skin `,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isJunk: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+ // tech.isMicroTransactions = true
+ // },
+ // remove() {
+ // tech.isMicroTransactions = false
+ // }
+ // },
+ {
+ name: "ship",
+ description: "fly around with no legs reduce combat difficulty by 1 level ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return !m.isShipMode && !m.isAltSkin && m.fieldUpgrades[m.fieldMode].name !== "negative mass"
+ },
+ requires: "",
+ effect() {
+ m.isAltSkin = true
+ m.shipMode()
+ level.difficultyDecrease(simulation.difficultyMode)
+ //unlock relativistic rotation
+ for (let i = 0; i < tech.tech.length; i++) {
+ if (tech.tech[i].name === "relativistic rotation") tech.tech[i].frequency = 10
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "circular symmetry",
+ description: "turning the ship rotates the universe instead+200% damage ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return m.isShipMode
+ },
+ requires: "",
+ effect() {
+ tech.damage *= 3
+
+ m.look = () => {
+ // const scale = 0;
+ m.transSmoothX = canvas.width2 - m.pos.x // - (simulation.mouse.x - canvas.width2) * scale;
+ m.transSmoothY = canvas.height2 - m.pos.y // - (simulation.mouse.y - canvas.height2) * scale;
+ m.transX += (m.transSmoothX - m.transX) * m.lookSmoothing;
+ m.transY += (m.transSmoothY - m.transY) * m.lookSmoothing;
+ ctx.restore();
+ ctx.save();
+ ctx.translate(canvas.width2, canvas.height2); //center
+ ctx.rotate(-m.angle)
+ ctx.translate(-canvas.width2, -canvas.height2); //center
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "assimilation",
+ description: "all your bots are converted to the same random model",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isBotTech: true,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return b.totalBots() > 2
+ },
+ requires: "at least 3 bots",
+ effect() {
+ const total = b.totalBots();
+ tech.dynamoBotCount = 0;
+ tech.nailBotCount = 0;
+ tech.laserBotCount = 0;
+ tech.orbitBotCount = 0;
+ tech.foamBotCount = 0;
+ tech.soundBotCount = 0;
+ tech.boomBotCount = 0;
+ tech.plasmaBotCount = 0;
+ tech.missileBotCount = 0;
+ for (let i = 0; i < bullet.length; i++) {
+ if (bullet[i].botType) bullet[i].endCycle = 0
+ }
+
+ const bots = [
+ () => {
+ b.nailBot();
+ tech.nailBotCount++;
+ },
+ () => {
+ b.foamBot();
+ tech.foamBotCount++;
+ },
+ () => {
+ b.soundBot();
+ tech.soundBotCount++;
+ },
+ () => {
+ b.boomBot();
+ tech.boomBotCount++;
+ },
+ () => {
+ b.laserBot();
+ tech.laserBotCount++;
+ },
+ () => {
+ b.orbitBot();
+ tech.orbitBotCount++
+ },
+ () => {
+ b.dynamoBot();
+ tech.dynamoBotCount++
+ }
+ ]
+ const index = Math.floor(Math.random() * bots.length)
+ for (let i = 0; i < total; i++) bots[index]()
+ },
+ remove() { }
+ },
+ {
+ name: "growth hacking",
+ description: "increase combat difficulty by 1 level ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ level.difficultyIncrease(simulation.difficultyMode)
+ },
+ remove() { }
+ },
+ {
+ name: "stun",
+ description: "stun all mobs for up to 8 seconds",
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0; i < mob.length; i++) mobs.statusStun(mob[i], 480)
+ },
+ remove() { }
+ },
+ {
+ name: "translucent",
+ description: "spawn 3 gun power ups your bullets and bots are transparent",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ for (let i = 0; i < 3; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun");
+
+ // //removes guns and ammo
+ // b.inventory = [];
+ // b.activeGun = null;
+ // b.inventoryGun = 0;
+ // for (let i = 0, len = b.guns.length; i < len; ++i) {
+ // b.guns[i].have = false;
+ // if (b.guns[i].ammo !== Infinity) b.guns[i].ammo = 0;
+ // }
+ // simulation.makeGunHUD(); //update gun HUD
+ b.bulletDraw = () => { }; //make bullets invisible
+ },
+ remove() { }
+ },
+ {
+ name: "re-research",
+ description: `eject all your ${powerUps.orb.research(1)}`,
+ maxCount: 9,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return powerUps.research.count > 3
+ },
+ requires: "at least 4 research",
+ effect() {
+ powerUps.spawnDelay("research", powerUps.research.count);
+ powerUps.research.count = 0
+ },
+ remove() { }
+ },
+ {
+ name: "black hole",
+ description: `use your energy and ${powerUps.orb.research(4)} to spawn inside the event horizon of a huge black hole `,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return powerUps.research.count > 3
+ },
+ requires: "at least 4 research",
+ effect() {
+ m.energy = 0
+ spawn.suckerBoss(m.pos.x, m.pos.y - 700)
+ powerUps.research.changeRerolls(-4)
+ simulation.makeTextLog(`m .research -- ${powerUps.research.count}`)
+ },
+ remove() { }
+ },
+ {
+ name: "black hole cluster",
+ description: `spawn 30 nearby black holes `,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ const unit = {
+ x: 1,
+ y: 0
+ }
+ for (let i = 0; i < 30; i++) {
+ const where = Vector.add(m.pos, Vector.mult(Vector.rotate(unit, Math.random() * 2 * Math.PI), 2000 + 1200 * Math.random()))
+ spawn.sucker(where.x, where.y, 140)
+ const who = mob[mob.length - 1]
+ who.locatePlayer()
+ // who.damageReduction = 0.2
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "rule 30",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !build.isExperimentSelection
+ },
+ requires: "NOT EXPERIMENT MODE",
+ effect() { },
+ remove() { },
+ state: [
+ [false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false, false, true, false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, Math.random() > 0.8, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false, false]
+ ],
+ rule(state, a, b, c) {
+ //30
+ if (state[a] && state[b] && state[c]) return false; // TTT => F
+ if (state[a] && state[b] && !state[c]) return false; // TTF => F
+ if (state[a] && !state[b] && state[c]) return false; //TFT => F
+ if (state[a] && !state[b] && !state[c]) return true; //TFF => T
+ if (!state[a] && state[b] && state[c]) return true; //FTT => T
+ if (!state[a] && state[b] && !state[c]) return true; //FTF => T
+ if (!state[a] && !state[b] && state[c]) return true; //FFT => T
+ if (!state[a] && !state[b] && !state[c]) return false; //FFF => F
+ },
+ id: 0,
+ researchSpawned: 0,
+ descriptionFunction() {
+ const loop = () => {
+ if ((simulation.paused || simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0)
+ let b = []; //produce next row
+ b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 1, 0, 1)); //left edge wrap around
+ for (let i = 1; i < this.state[this.state.length - 1].length - 1; i++) { //apply rule to the rest of the array
+ b.push(this.rule(this.state[this.state.length - 1], i - 1, i, i + 1));
+ }
+ b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 2, this.state[this.state.length - 1].length - 1, 0)); //right edge wrap around
+ this.state.push(b)
+ if (document.getElementById(`cellular-rule-id${this.id}`)) document.getElementById(`cellular-rule-id${this.id}`).innerHTML = this.outputText() //convert to squares and send HTML
+ if (this.count && this.researchSpawned < 12 && !(this.state.length % 10)) {
+ this.researchSpawned++
+ powerUps.spawn(m.pos.x - 50 + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
+ }
+ setTimeout(() => {
+ loop()
+ }, 300 + 5 * this.state.length);
+ }
+ }
+ setTimeout(() => {
+ loop()
+ }, 300);
+ this.id++
+ return `${this.outputText()} `
+ },
+ outputText() {
+ let text = ""
+ for (let j = 0; j < this.state.length; j++) {
+ // text += ""
+ text += "
"
+ for (let i = 0; i < this.state[j].length; i++) {
+ if (this.state[j][i]) {
+ text += "■" //"☻" //"⬛" //"█" //"■"
+ } else {
+ text += " " //"□" //"☺" //"⬜" //" " //"□"
+ }
+ }
+ text += "
"
+ }
+ text += " "
+ return text
+ },
+ },
+ {
+ name: "rule 90",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ allowed() {
+ return !build.isExperimentSelection
+ },
+ requires: "NOT EXPERIMENT MODE",
+ effect() { },
+ remove() { },
+ state: [
+ [false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false, false, true, true, false, false, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, Math.random() > 0.8, false, Math.random() > 0.8, false, false, false, Math.random() > 0.8, false, false, false, false, false, false, false, false]
+ ],
+ rule(state, a, b, c) { //90
+ if (state[a] && state[b] && state[c]) return false; // TTT => F
+ if (state[a] && state[b] && !state[c]) return true; // TTF => T
+ if (state[a] && !state[b] && state[c]) return false; //TFT => F
+ if (state[a] && !state[b] && !state[c]) return true; //TFF => T
+ if (!state[a] && state[b] && state[c]) return true; //FTT => T
+ if (!state[a] && state[b] && !state[c]) return false; //FTF => F
+ if (!state[a] && !state[b] && state[c]) return true; //FFT => T
+ if (!state[a] && !state[b] && !state[c]) return false; //FFF => F
+ },
+ id: 90,
+ researchSpawned: 0,
+ descriptionFunction() {
+ const loop = () => {
+ if ((simulation.paused || simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0)
+ let b = []; //produce next row
+ b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 1, 0, 1)); //left edge wrap around
+ for (let i = 1; i < this.state[this.state.length - 1].length - 1; i++) { //apply rule to the rest of the array
+ b.push(this.rule(this.state[this.state.length - 1], i - 1, i, i + 1));
+ }
+ b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 2, this.state[this.state.length - 1].length - 1, 0)); //right edge wrap around
+ this.state.push(b)
+ if (document.getElementById(`cellular-rule-id${this.id}`)) document.getElementById(`cellular-rule-id${this.id}`).innerHTML = this.outputText() //convert to squares and send HTML
+ if (this.count && this.researchSpawned < 12 && !(this.state.length % 10)) {
+ this.researchSpawned++
+ powerUps.spawn(m.pos.x - 50 + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
+ }
+ setTimeout(() => {
+ loop()
+ }, 300 + 5 * this.state.length);
+ }
+ }
+ setTimeout(() => {
+ loop()
+ }, 300);
+ this.id++
+ return `${this.outputText()} `
+ },
+ outputText() {
+ let text = ""
+ for (let j = 0; j < this.state.length; j++) {
+ // text += ""
+ text += "
"
+ for (let i = 0; i < this.state[j].length; i++) {
+ if (this.state[j][i]) {
+ text += "■" //"☻" //"⬛" //"█" //"■"
+ } else {
+ text += " " //"□" //"☺" //"⬜" //" " //"□"
+ }
+ }
+ text += "
"
+ }
+ text += " "
+ return text
+ },
+ },
+ {
+ name: "cosmogonic myth",
+ description: `open a portal to a primordial version of reality in 5 minutes close the portal, spawn 1 of each power up `,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ const urls = ["https://scratch.mit.edu/projects/14005697/fullscreen/", "https://scratch.mit.edu/projects/22573757/fullscreen/", "https://scratch.mit.edu/projects/41429974/fullscreen/", "https://scratch.mit.edu/projects/43690666/fullscreen/", "https://codepen.io/lilgreenland/full/ozXNWZ", "https://codepen.io/lilgreenland/full/wzARJY", "classic/7-1-2017/", "classic/4-15-2018/", "classic/7-11-2019/", "classic/9-8-2019/", "classic/7-15-2020/", "classic/6-1-2021/"]
+ const choose = urls[Math.floor(Math.random() * urls.length)]
+ console.log(`opening new tab" ${choose}`)
+ let tab = window.open(choose, "_blank");
+ setTimeout(() => {
+ tab.close();
+ powerUps.spawn(m.pos.x, m.pos.y, "gun");
+ setTimeout(() => {
+ powerUps.spawn(m.pos.x, m.pos.y - 50, "ammo")
+ }, 250);
+ setTimeout(() => {
+ powerUps.spawn(m.pos.x + 50, m.pos.y, "field");
+ }, 500);
+ setTimeout(() => {
+ powerUps.spawn(m.pos.x + 50, m.pos.y - 50, "heal");
+ }, 750);
+ setTimeout(() => {
+ powerUps.spawn(m.pos.x - 50, m.pos.y, "tech");
+ }, 1000);
+ setTimeout(() => {
+ powerUps.spawn(m.pos.x - 50, m.pos.y - 50, "research");
+ }, 1250);
+ }, 1000 * 5 * 60);
+ },
+ remove() { }
+ },
+ {
+ name: "planetesimals",
+ description: `play planetesimals (an asteroids-like game) clear levels in planetesimals to spawn tech if you die in planetesimals you die in n-gon `,
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isNonRefundable: true,
+ isJunk: true,
+ allowed() {
+ return true
+ },
+ requires: "",
+ effect() {
+ window.open('../../planetesimals/index.html', '_blank')
+ // powerUps.spawn(m.pos.x, m.pos.y, "tech");
+
+ // for communicating to other tabs, like planetesimals
+ // Connection to a broadcast channel
+ const bc = new BroadcastChannel('planetesimals');
+ bc.activated = false
+
+ bc.onmessage = function (ev) {
+ if (ev.data === 'tech') powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
+ if (ev.data === 'death') {
+ m.death()
+ bc.close(); //end session
+ }
+ if (ev.data === 'ready' && !bc.activated) {
+ bc.activated = true //prevents n-gon from activating multiple copies of planetesimals
+ bc.postMessage("activate");
+ }
+ }
+ },
+ remove() { }
+ },
+ {
+ name: "tinker",
+ description: "permanently unlock JUNK tech in experiment modethis effect is stored for future visits ",
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ frequencyDefault: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed() {
+ return !localSettings.isJunkExperiment
+ },
+ requires: "",
+ effect() {
+ localSettings.isJunkExperiment = true
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ },
+ remove() { }
+ },
+ {
+ name: "NFT",
+ descriptionFunction() {
+ return `buy your current game seed: ${Math.initialSeed} no one is allowed to use your seeds if they use them they are gonna get in trouble your seeds: ${localSettings.personalSeeds.join(", ")} `
+ },
+ maxCount: 1,
+ count: 0,
+ frequency: 0,
+ isJunk: true,
+ isNonRefundable: true,
+ allowed: () => true,
+ requires: "",
+ effect() {
+ localSettings.personalSeeds.push(Math.initialSeed)
+ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
+ },
+ remove() { }
+ },
+ // {
+ // name: "rule 90",
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 0,
+ // isJunk: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {},
+ // remove() {},
+ // state: [
+ // [false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false]
+ // ],
+ // rule(state, a, b, c) {
+ // if (state[a] && state[b] && state[c]) return false; // TTT => F
+ // if (state[a] && state[b] && !state[c]) return true; // TTF => T
+ // if (state[a] && !state[b] && state[c]) return false; //TFT => F
+ // if (state[a] && !state[b] && !state[c]) return true; //TFF => T
+ // if (!state[a] && state[b] && state[c]) return true; //FTT => T
+ // if (!state[a] && state[b] && !state[c]) return false; //FTF => F
+ // if (!state[a] && !state[b] && state[c]) return true; //FFT => T
+ // if (!state[a] && !state[b] && !state[c]) return false; //FFF => F
+ // },
+ // id: 0,
+ // descriptionFunction() {
+ // const loop = () => {
+ // if ((simulation.paused || simulation.isChoosing) && m.alive && !build.isExperimentSelection) { //&& (!simulation.isChoosing || this.count === 0)
+ // let b = []; //produce next row
+ // b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 1, 0, 1)); //left edge wrap around
+ // for (let i = 1; i < this.state[this.state.length - 1].length - 1; i++) { //apply rule to the rest of the array
+ // b.push(this.rule(this.state[this.state.length - 1], i - 1, i, i + 1));
+ // }
+ // b.push(this.rule(this.state[this.state.length - 1], this.state[this.state.length - 1].length - 2, this.state[this.state.length - 1].length - 1, 0)); //right edge wrap around
+ // this.state.push(b)
+ // if (document.getElementById(`cellular-rule-id${this.id}`)) document.getElementById(`cellular-rule-id${this.id}`).innerHTML = this.outputText() //convert to squares and send HTML
+ // if (this.count && this.state.length < 120 && !(this.state.length % 10)) powerUps.spawn(m.pos.x - 50 + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
+ // setTimeout(() => { loop() }, 400);
+ // }
+ // }
+ // setTimeout(() => { loop() }, 400);
+ // // if (this.id === 0) {
+ // // for (let i = 0; i < 29; i++) this.state[0][i] = Math.random() < 0.5 //randomize seed
+ // // }
+ // this.id++
+ // return `${this.outputText()} `
+ // },
+ // outputText() {
+ // let text = ""
+ // for (let j = 0; j < this.state.length; j++) {
+ // text += ""
+ // for (let i = 0; i < this.state[j].length; i++) {
+ // if (this.state[j][i]) {
+ // text += "⬛" //"█" //"■"
+ // } else {
+ // text += "⬜" //" " //"□"
+ // }
+ // }
+ // text += "
"
+ // }
+ // return text
+ // },
+ // },
+
+ //**************************************************
+ //************************************************** undefined / lore
+ //************************************************** tech
+ //**************************************************
+ {
+ name: `undefined`,
+ description: `this `,
+ maxCount: 1,
+ count: 0,
+ frequency: 2,
+ frequencyDefault: 2,
+ isLore: true,
+ // isExperimentHide: true,
+ allowed() { return !build.isExperimentSelection },
+ requires: "NOT EXPERIMENT MODE",
+ effect() {
+ if (localSettings.loreCount > lore.conversation.length - 1) { //reward for people done with lore chapters (or on the final chapter)
+ for (let i = mob.length - 1; i > -1; i--) { //replace mobs with starters
+ if (!mob[i].isBoss && mob[i].isDropPowerUp && mob[i].alive) {
+ spawn.starter(mob[i].position.x, mob[i].position.y)
+ mob[i].leaveBody = false
+ mob[i].isDropPowerUp = false
+ mob[i].death()
+
+ //spawn a random power up
+ // if (Math.random() < 1 / 5) {
+ // powerUps.spawn(mob[i].position.x, mob[i].position.y, "research")
+ // } else
+ if (Math.random() < 1 / 4) {
+ powerUps.spawn(mob[i].position.x, mob[i].position.y, "ammo")
+ } else if (Math.random() < 1 / 3) {
+ powerUps.spawn(mob[i].position.x, mob[i].position.y, "heal")
+ } else if (Math.random() < 1 / 2) {
+ powerUps.spawn(mob[i].position.x, mob[i].position.y, "boost")
+ } else {
+ powerUps.spawn(mob[i].position.x, mob[i].position.y, "coupling")
+ }
+ }
+ }
+ }
+
+ setTimeout(() => { //a short delay, I can't remember why
+ lore.techCount++
+ if (lore.techCount === lore.techGoal) {
+ // tech.removeLoreTechFromPool();
+ this.frequency = 0;
+ this.description = `null is open at level.final() `
+ } else {
+ this.frequency += lore.techGoal * 2
+ // for (let i = 0; i < tech.tech.length; i++) { //set name for all unchosen copies of this tech
+ // if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech[i].description = `${lore.techCount+1}/${lore.techGoal}add copies of this to the potential tech pool `
+ // }
+ // for (let i = 0, len = 10; i < len; i++) tech.addLoreTechToPool()
+ this.description = `uncaught error: ${Math.max(0, lore.techGoal - lore.techCount)} more required for access to null `
+ }
+ }, 1);
+ },
+ remove() {
+ lore.techCount = 0;
+ this.maxCount = lore.techGoal;
+ this.description = `this `
+ }
+ }
+ ],
+ // addLoreTechToPool() { //adds lore tech to tech pool
+ // if (!simulation.isCheating) {
+ // tech.tech.push({
+ // name: `undefined`,
+ // description: `${lore.techCount+1}/${lore.techGoal}add copies of this to the potential tech pool `,
+ // maxCount: 1,
+ // count: 0,
+ // frequency: 2,
+ // isLore: true,
+ // isNonRefundable: true,
+ // isExperimentHide: true,
+ // allowed() {
+ // return true
+ // },
+ // requires: "",
+ // effect() {
+ // setTimeout(() => { //a short delay, I can't remember why
+ // lore.techCount++
+ // if (lore.techCount > lore.techGoal - 1) {
+ // // tech.removeLoreTechFromPool();
+ // for (let i = tech.tech.length - 1; i > 0; i--) {
+ // if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech.splice(i, 1)
+ // }
+ // } else {
+ // for (let i = 0; i < tech.tech.length; i++) { //set name for all unchosen copies of this tech
+ // if (tech.tech[i].isLore && tech.tech[i].count === 0) tech.tech[i].description = `${lore.techCount+1}/${lore.techGoal}add copies of this to the potential tech pool `
+ // }
+ // for (let i = 0, len = 10; i < len; i++) tech.addLoreTechToPool()
+ // }
+ // }, 1);
+ // },
+ // remove() {}
+ // })
+ // }
+ // },
+ // junk: [
+
+ // ],
+ //variables use for gun tech upgrades
+ fireRate: null,
+ bulletSize: null,
+ energySiphon: null,
+ healthDrain: null,
+ crouchAmmoCount: null,
+ bulletsLastLonger: null,
+ isImmortal: null,
+ sporesOnDeath: null,
+ isImmuneExplosion: null,
+ isExplodeMob: null,
+ isDroneOnDamage: null,
+ isAcidDmg: null,
+ isAnnihilation: null,
+ largerHeals: null,
+ squirrelFx: null,
+ isCrit: null,
+ isLowHealthDmg: null,
+ isLowHealthDefense: null,
+ isLowHealthFireRate: null,
+ isFarAwayDmg: null,
+ isFirstDer: null,
+ isMassEnergy: null,
+ extraChoices: null,
+ laserBotCount: null,
+ dynamoBotCount: null,
+ nailBotCount: null,
+ foamBotCount: null,
+ soundBotCount: null,
+ boomBotCount: null,
+ plasmaBotCount: null,
+ missileBotCount: null,
+ orbitBotCount: null,
+ blockDmg: null,
+ isBlockRadiation: null,
+ isPiezo: null,
+ isFastDrones: null,
+ oneSuperBall: null,
+ laserReflections: null,
+ laserDamage: null,
+ isAmmoFromHealth: null,
+ mobSpawnWithHealth: null,
+ isEnergyRecovery: null,
+ isHealthRecovery: null,
+ isEnergyLoss: null,
+ isDeathAvoid: null,
+ isDeathAvoidedThisLevel: null,
+ isPlasmaRange: null,
+ isFreezeMobs: null,
+ isIceCrystals: null,
+ blockDamage: null,
+ isBlockStun: null,
+ isStunField: null,
+ isHarmDamage: null,
+ energyRegen: null,
+ isVacuumBomb: null,
+ renormalization: null,
+ fragments: null,
+ energyDamage: null,
+ botSpawner: null,
+ isBotSpawnerReset: null,
+ isSporeFollow: null,
+ isNailRadiation: null,
+ isEnergyHealth: null,
+ isStun: null,
+ restDamage: null,
+ isRPG: null,
+ missileCount: null,
+ isDeterminism: null,
+ isSuperDeterminism: null,
+ isHarmReduce: null,
+ nailsDeathMob: null,
+ isSlowFPS: null,
+ isNeutronStun: null,
+ isAnsatz: null,
+ isDamageFromBulletCount: null,
+ laserDrain: null,
+ isNailShot: null,
+ slowFire: null,
+ fastTime: null,
+ squirrelJump: null,
+ isFastRadiation: null,
+ isAmmoForGun: null,
+ isRapidPulse: null,
+ isSporeFreeze: null,
+ isShotgunRecoil: null,
+ isHealLowHealth: null,
+ isAoESlow: null,
+ isHarmArmor: null,
+ isTurret: null,
+ isRerollDamage: null,
+ isHarmFreeze: null,
+ isBotArmor: null,
+ isRerollHaste: null,
+ researchHaste: null,
+ isMineDrop: null,
+ isRerollBots: null,
+ isNailBotUpgrade: null,
+ isFoamBotUpgrade: null,
+ isSoundBotUpgrade: null,
+ isLaserBotUpgrade: null,
+ isBoomBotUpgrade: null,
+ isOrbitBotUpgrade: null,
+ isDroneGrab: null,
+ isOneGun: null,
+ isDamageForGuns: null,
+ isGunCycle: null,
+ isFastFoam: null,
+ isSporeGrowth: null,
+ isStimulatedEmission: null,
+ nailGun: null,
+ nailInstantFireRate: null,
+ isCapacitor: null,
+ isEnergyNoAmmo: null,
+ // isFreezeHarmImmune: null,
+ isSmallExplosion: null,
+ isExplosionHarm: null,
+ extraMaxHealth: null,
+ // bonusHealth: null,
+ isIntangible: null,
+ isCloakStun: null,
+ bonusEnergy: null,
+ // healGiveMaxEnergy: null,
+ healMaxEnergyBonus: 0, //not null
+ aimDamage: null,
+ isNoFireDefense: null,
+ isNoFireDamage: null,
+ duplicateChance: null,
+ beamSplitter: null,
+ iceEnergy: null,
+ isPerfectBrake: null,
+ explosiveRadius: null,
+ // isWormholeEnergy: null,
+ isWormholeDamage: null,
+ isNailCrit: null,
+ isFlechetteExplode: null,
+ isWormholeWorms: null,
+ isWormHoleBullets: null,
+ isWideLaser: null,
+ wideLaser: null,
+ isPulseLaser: null,
+ isRadioactive: null,
+ radioactiveDamage: null,
+ isRailEnergy: null,
+ isMineSentry: null,
+ isIncendiary: null,
+ overfillDrain: null,
+ isNeutronSlow: null,
+ // isRailAreaDamage: null,
+ historyLaser: null,
+ isSpeedHarm: null,
+ isSpeedDamage: null,
+ isTimeSkip: null,
+ isCancelDuplication: null,
+ duplication: null,
+ isCancelRerolls: null,
+ isCancelTech: null,
+ isBotDamage: null,
+ isBanish: null,
+ isMaxEnergyTech: null,
+ isLowEnergyDamage: null,
+ isRewindBot: null,
+ isRewindGrenade: null,
+ isExtruder: null,
+ isEndLevelPowerUp: null,
+ isMissileBig: null,
+ isMissileBiggest: null,
+ isLaserMine: null,
+ isFoamMine: null,
+ isAmmoFoamSize: null,
+ isIceIX: null,
+ isDupDamage: null,
+ isFireRateForGuns: null,
+ cyclicImmunity: null,
+ isTechDamage: null,
+ isRestHarm: null,
+ isFireMoveLock: null,
+ isRivets: null,
+ isNeedles: null,
+ isExplodeRadio: null,
+ isPauseSwitchField: null,
+ isPauseEjectTech: null,
+ isShieldPierce: null,
+ isDuplicateMobs: null,
+ is100Duplicate: null,
+ isDynamoBotUpgrade: null,
+ isBlockPowerUps: null,
+ isDamageAfterKillNoRegen: null,
+ isHarmReduceNoKill: null,
+ isSwitchReality: null,
+ isResearchReality: null,
+ isAnthropicDamage: null,
+ isFlipFlop: null,
+ isFlipFlopHarm: null,
+ isFlipFlopOn: null,
+ // isFlipFlopLevelReset: null,
+ isFlipFlopDamage: null,
+ isFlipFlopEnergy: null,
+ isFlipFlopChoices: null,
+ isRelay: null,
+ relayIce: null,
+ isMetaAnalysis: null,
+ isFoamAttract: null,
+ droneCycleReduction: null,
+ droneEnergyReduction: null,
+ isHalfHeals: null,
+ isAlwaysFire: null,
+ isDroneRespawn: null,
+ deathSpawns: null,
+ isMobBlockFling: null,
+ // blockingIce: null,
+ isPhaseVelocity: null,
+ waveBeamSpeed: null,
+ wavePacketAmplitude: null,
+ isCollisionRealitySwitch: null,
+ iceIXOnDeath: null,
+ wimpCount: null,
+ isAddBlockMass: null,
+ isMACHO: null,
+ isHarmMACHO: null,
+ isSneakAttack: null,
+ isFallingDamage: null,
+ harmonics: null,
+ isStandingWaveExpand: null,
+ isTokamak: null,
+ deflectEnergy: null,
+ superBallDelay: null,
+ isBlockExplode: null,
+ isOverHeal: null,
+ isDroneRadioactive: null,
+ droneRadioDamage: null,
+ isDroneTeleport: null,
+ isDroneFastLook: null,
+ isBulletTeleport: null,
+ isResearchBoss: null,
+ isJunkResearch: null,
+ junkResearchNumber: null,
+ laserColor: null,
+ laserColorAlpha: null,
+ isLongitudinal: null,
+ is360Longitudinal: null,
+ isShotgunReversed: null,
+ fieldDuplicate: null,
+ isCloakingDamage: null,
+ harmonicEnergy: null,
+ isFieldHarmReduction: null,
+ isFastTime: null,
+ isAnthropicTech: null,
+ isSporeWorm: null,
+ isSporeFlea: null,
+ isFoamShot: null,
+ isIceShot: null,
+ isBlockRestitution: null,
+ isZeno: null,
+ isFieldFree: null,
+ isExtraGunField: null,
+ isBigField: null,
+ isSmartRadius: null,
+ isFilament: null,
+ isLargeHarpoon: null,
+ extraHarpoons: null,
+ ammoCap: null,
+ isHarpoonPowerUp: null,
+ harpoonDensity: null,
+ isAddRemoveMaxHealth: null,
+ cloakDuplication: null,
+ extruderRange: null,
+ isForeverDrones: null,
+ nailRecoil: null,
+ baseJumpForce: null,
+ baseFx: null,
+ isNeutronium: null,
+ isFreeWormHole: null,
+ isRewindField: null,
+ isCrouchRegen: null,
+ isAxion: null,
+ isDarkStar: null,
+ isWormholeMapIgnore: null,
+ isLessDamageReduction: null,
+ needleTunnel: null,
+ isBrainstorm: null,
+ isBrainstormActive: null,
+ brainStormDelay: null,
+ wormSize: null,
+ extraSuperBalls: null,
+ isTimeCrystals: null,
+ isGroundState: null,
+ isRailGun: null,
+ isGrapple: null,
+ isImmuneGrapple: null,
+ isDronesTravel: null,
+ isTechDebt: null,
+ isPlasmaBall: null,
+ plasmaDischarge: null,
+ isFlipFlopHealth: null,
+ isRelayEnergy: null,
+ coyoteTime: null,
+ missileFireCD: null,
+ isBotField: null,
+ isFoamBall: null,
+ isNoDraftPause: null,
+ isFoamPressure: null,
+ foamDamage: null,
+ isClusterExplode: null,
+ isCircleExplode: null,
+ isPetalsExplode: null,
+ deathSkipTime: null,
+ isIceMaxHealthLoss: null,
+ isIceKill: null,
+ isCritKill: null,
+ isQuantumEraser: null,
+ isPhononBlock: null,
+ isPhononWave: null,
+ isLaserLens: null,
+ laserCrit: null,
+ isSporeColony: null,
+ isExtraBotOption: null,
+ isLastHitDamage: null,
+ isCloakHealLastHit: null,
+ isRicochet: null,
+ isCancelCouple: null,
+ isCouplingPowerUps: null,
+ isBoostPowerUps: null,
+ isBoostReplaceAmmo: null,
+ isInfiniteWaveAmmo: null,
+ isJunkDNA: null,
+ buffedGun: 0,
+ isGunChoice: null,
+ railChargeRate: null,
+ isSuperHarm: null,
+ isZombieMobs: null,
+ isSuperMine: null,
+ sentryAmmo: null,
+ collidePowerUps: null,
+ isDilate: null,
+ isDiaphragm: null,
+ hardLanding: null,
+ isNoGroundDamage: null,
+ isSuperBounce: null,
+ isDivisor: null,
+ isFoamCavitation: null,
+ isHealAttract: null,
+ isLaserField: null,
+ isHealBrake: null,
+ isMassProduction: null,
+ isPrinter: null,
+}
\ No newline at end of file
diff --git a/ngon/js/visibility.js b/ngon/js/visibility.js
new file mode 100644
index 00000000..d1686b76
--- /dev/null
+++ b/ngon/js/visibility.js
@@ -0,0 +1,44 @@
+// https://ncase.me/sight-and-light/
+// redblobgames.com/articles/visibility
+// https://github.com/Silverwolf90/2d-visibility/tree/master/src
+// could apply to explosions, neutron bomb, player LOS
+
+
+const v = {
+ points: [],
+ populate() {
+ v.points = [{
+ x: -150,
+ y: -950
+ }, {
+ x: 710,
+ y: -950
+ }, {
+ x: 710,
+ y: -940
+ }, {
+ x: 710,
+ y: -710
+ }, {
+ x: 710,
+ y: -700
+ }, {
+ x: -150,
+ y: -700
+ }]
+ },
+ draw() {
+ ctx.beginPath();
+ ctx.moveTo(v.points[0].x, v.points[0].y)
+ for (let i = 0, len = v.points.length; i < len; i++) {
+ ctx.lineTo(v.points[i].x, v.points[i].y)
+ }
+ // ctx.fillStyle = "#333"
+ ctx.globalCompositeOperation = "destination-in";
+ ctx.fill();
+ ctx.globalCompositeOperation = "source-over";
+ ctx.clip();
+ }
+}
+v.populate();
+// console.log(v.points)
\ No newline at end of file
diff --git a/ngon/lib/matter.min.js b/ngon/lib/matter.min.js
new file mode 100644
index 00000000..d93e50fe
--- /dev/null
+++ b/ngon/lib/matter.min.js
@@ -0,0 +1,714 @@
+/*!
+ * matter-js 0.18.0-alpha+0eeceb5 by @liabru
+ * Experimental pre-release build.
+ * http://brm.io/matter-js/
+ * License MIT
+ */
+! function(e, t) { "object" == typeof exports && "object" == typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define("Matter", [], t) : "object" == typeof exports ? exports.Matter = t() : e.Matter = t() }(this, (function() { return function(e) { var t = {};
+
+ function n(i) { if (t[i]) return t[i].exports; var o = t[i] = { i: i, l: !1, exports: {} }; return e[i].call(o.exports, o, o.exports, n), o.l = !0, o.exports } return n.m = e, n.c = t, n.d = function(e, t, i) { n.o(e, t) || Object.defineProperty(e, t, { enumerable: !0, get: i }) }, n.r = function(e) { "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(e, "__esModule", { value: !0 }) }, n.t = function(e, t) { if (1 & t && (e = n(e)), 8 & t) return e; if (4 & t && "object" == typeof e && e && e.__esModule) return e; var i = Object.create(null); if (n.r(i), Object.defineProperty(i, "default", { enumerable: !0, value: e }), 2 & t && "string" != typeof e)
+ for (var o in e) n.d(i, o, function(t) { return e[t] }.bind(null, o)); return i }, n.n = function(e) { var t = e && e.__esModule ? function() { return e.default } : function() { return e }; return n.d(t, "a", t), t }, n.o = function(e, t) { return Object.prototype.hasOwnProperty.call(e, t) }, n.p = "", n(n.s = 21) }([function(e, t) { var n = {};
+ e.exports = n,
+ function() { n._nextId = 0, n._seed = 0, n._nowStartTime = +new Date, n._warnedOnce = {}, n._decomp = null, n.extend = function(e, t) { var i, o; "boolean" == typeof t ? (i = 2, o = t) : (i = 1, o = !0); for (var r = i; r < arguments.length; r++) { var a = arguments[r]; if (a)
+ for (var s in a) o && a[s] && a[s].constructor === Object ? e[s] && e[s].constructor !== Object ? e[s] = a[s] : (e[s] = e[s] || {}, n.extend(e[s], o, a[s])) : e[s] = a[s] } return e }, n.clone = function(e, t) { return n.extend({}, t, e) }, n.keys = function(e) { if (Object.keys) return Object.keys(e); var t = []; for (var n in e) t.push(n); return t }, n.values = function(e) { var t = []; if (Object.keys) { for (var n = Object.keys(e), i = 0; i < n.length; i++) t.push(e[n[i]]); return t } for (var o in e) t.push(e[o]); return t }, n.get = function(e, t, n, i) { t = t.split(".").slice(n, i); for (var o = 0; o < t.length; o += 1) e = e[t[o]]; return e }, n.set = function(e, t, i, o, r) { var a = t.split(".").slice(o, r); return n.get(e, t, 0, -1)[a[a.length - 1]] = i, i }, n.shuffle = function(e) { for (var t = e.length - 1; t > 0; t--) { var i = Math.floor(n.random() * (t + 1)),
+ o = e[t];
+ e[t] = e[i], e[i] = o } return e }, n.choose = function(e) { return e[Math.floor(n.random() * e.length)] }, n.isElement = function(e) { return "undefined" != typeof HTMLElement ? e instanceof HTMLElement : !!(e && e.nodeType && e.nodeName) }, n.isArray = function(e) { return "[object Array]" === Object.prototype.toString.call(e) }, n.isFunction = function(e) { return "function" == typeof e }, n.isPlainObject = function(e) { return "object" == typeof e && e.constructor === Object }, n.isString = function(e) { return "[object String]" === toString.call(e) }, n.clamp = function(e, t, n) { return e < t ? t : e > n ? n : e }, n.sign = function(e) { return e < 0 ? -1 : 1 }, n.now = function() { if ("undefined" != typeof window && window.performance) { if (window.performance.now) return window.performance.now(); if (window.performance.webkitNow) return window.performance.webkitNow() } return Date.now ? Date.now() : new Date - n._nowStartTime }, n.random = function(t, n) { return n = void 0 !== n ? n : 1, (t = void 0 !== t ? t : 0) + e() * (n - t) }; var e = function() { return n._seed = (9301 * n._seed + 49297) % 233280, n._seed / 233280 };
+ n.colorToNumber = function(e) { return 3 == (e = e.replace("#", "")).length && (e = e.charAt(0) + e.charAt(0) + e.charAt(1) + e.charAt(1) + e.charAt(2) + e.charAt(2)), parseInt(e, 16) }, n.logLevel = 1, n.log = function() { console && n.logLevel > 0 && n.logLevel <= 3 && console.log.apply(console, ["matter-js:"].concat(Array.prototype.slice.call(arguments))) }, n.info = function() { console && n.logLevel > 0 && n.logLevel <= 2 && console.info.apply(console, ["matter-js:"].concat(Array.prototype.slice.call(arguments))) }, n.warn = function() { console && n.logLevel > 0 && n.logLevel <= 3 && console.warn.apply(console, ["matter-js:"].concat(Array.prototype.slice.call(arguments))) }, n.warnOnce = function() { var e = Array.prototype.slice.call(arguments).join(" ");
+ n._warnedOnce[e] || (n.warn(e), n._warnedOnce[e] = !0) }, n.deprecated = function(e, t, i) { e[t] = n.chain((function() { n.warnOnce("🔅 deprecated 🔅", i) }), e[t]) }, n.nextId = function() { return n._nextId++ }, n.indexOf = function(e, t) { if (e.indexOf) return e.indexOf(t); for (var n = 0; n < e.length; n++)
+ if (e[n] === t) return n; return -1 }, n.map = function(e, t) { if (e.map) return e.map(t); for (var n = [], i = 0; i < e.length; i += 1) n.push(t(e[i])); return n }, n.topologicalSort = function(e) { var t = [],
+ i = [],
+ o = []; for (var r in e) i[r] || o[r] || n._topologicalSort(r, i, o, e, t); return t }, n._topologicalSort = function(e, t, i, o, r) { var a = o[e] || [];
+ i[e] = !0; for (var s = 0; s < a.length; s += 1) { var l = a[s];
+ i[l] || (t[l] || n._topologicalSort(l, t, i, o, r)) } i[e] = !1, t[e] = !0, r.push(e) }, n.chain = function() { for (var e = [], t = 0; t < arguments.length; t += 1) { var n = arguments[t];
+ n._chained ? e.push.apply(e, n._chained) : e.push(n) } var i = function() { for (var t, n = new Array(arguments.length), i = 0, o = arguments.length; i < o; i++) n[i] = arguments[i]; for (i = 0; i < e.length; i += 1) { var r = e[i].apply(t, n);
+ void 0 !== r && (t = r) } return t }; return i._chained = e, i }, n.chainPathBefore = function(e, t, i) { return n.set(e, t, n.chain(i, n.get(e, t))) }, n.chainPathAfter = function(e, t, i) { return n.set(e, t, n.chain(n.get(e, t), i)) }, n.setDecomp = function(e) { n._decomp = e }, n.getDecomp = function() { var e = n._decomp; try { e || "undefined" == typeof window || (e = window.decomp), e || "undefined" == typeof global || (e = global.decomp) } catch (t) { e = null } return e } }() }, function(e, t) { var n = {};
+ e.exports = n, n.create = function(e) { var t = { min: { x: 0, y: 0 }, max: { x: 0, y: 0 } }; return e && n.update(t, e), t }, n.update = function(e, t, n) { e.min.x = 1 / 0, e.max.x = -1 / 0, e.min.y = 1 / 0, e.max.y = -1 / 0; for (var i = 0; i < t.length; i++) { var o = t[i];
+ o.x > e.max.x && (e.max.x = o.x), o.x < e.min.x && (e.min.x = o.x), o.y > e.max.y && (e.max.y = o.y), o.y < e.min.y && (e.min.y = o.y) } n && (n.x > 0 ? e.max.x += n.x : e.min.x += n.x, n.y > 0 ? e.max.y += n.y : e.min.y += n.y) }, n.contains = function(e, t) { return t.x >= e.min.x && t.x <= e.max.x && t.y >= e.min.y && t.y <= e.max.y }, n.overlaps = function(e, t) { return e.min.x <= t.max.x && e.max.x >= t.min.x && e.max.y >= t.min.y && e.min.y <= t.max.y }, n.translate = function(e, t) { e.min.x += t.x, e.max.x += t.x, e.min.y += t.y, e.max.y += t.y }, n.shift = function(e, t) { var n = e.max.x - e.min.x,
+ i = e.max.y - e.min.y;
+ e.min.x = t.x, e.max.x = t.x + n, e.min.y = t.y, e.max.y = t.y + i } }, function(e, t) { var n = {};
+ e.exports = n, n.create = function(e, t) { return { x: e || 0, y: t || 0 } }, n.clone = function(e) { return { x: e.x, y: e.y } }, n.magnitude = function(e) { return Math.sqrt(e.x * e.x + e.y * e.y) }, n.magnitudeSquared = function(e) { return e.x * e.x + e.y * e.y }, n.rotate = function(e, t, n) { var i = Math.cos(t),
+ o = Math.sin(t);
+ n || (n = {}); var r = e.x * i - e.y * o; return n.y = e.x * o + e.y * i, n.x = r, n }, n.rotateAbout = function(e, t, n, i) { var o = Math.cos(t),
+ r = Math.sin(t);
+ i || (i = {}); var a = n.x + ((e.x - n.x) * o - (e.y - n.y) * r); return i.y = n.y + ((e.x - n.x) * r + (e.y - n.y) * o), i.x = a, i }, n.normalise = function(e) { var t = n.magnitude(e); return 0 === t ? { x: 0, y: 0 } : { x: e.x / t, y: e.y / t } }, n.dot = function(e, t) { return e.x * t.x + e.y * t.y }, n.cross = function(e, t) { return e.x * t.y - e.y * t.x }, n.cross3 = function(e, t, n) { return (t.x - e.x) * (n.y - e.y) - (t.y - e.y) * (n.x - e.x) }, n.add = function(e, t, n) { return n || (n = {}), n.x = e.x + t.x, n.y = e.y + t.y, n }, n.sub = function(e, t, n) { return n || (n = {}), n.x = e.x - t.x, n.y = e.y - t.y, n }, n.mult = function(e, t) { return { x: e.x * t, y: e.y * t } }, n.div = function(e, t) { return { x: e.x / t, y: e.y / t } }, n.perp = function(e, t) { return { x: (t = !0 === t ? -1 : 1) * -e.y, y: t * e.x } }, n.neg = function(e) { return { x: -e.x, y: -e.y } }, n.angle = function(e, t) { return Math.atan2(t.y - e.y, t.x - e.x) }, n._temp = [n.create(), n.create(), n.create(), n.create(), n.create(), n.create()] }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(2),
+ r = n(0);
+ i.create = function(e, t) { for (var n = [], i = 0; i < e.length; i++) { var o = e[i],
+ r = { x: o.x, y: o.y, index: i, body: t, isInternal: !1 };
+ n.push(r) } return n }, i.fromPath = function(e, t) { var n = []; return e.replace(/L?\s*([-\d.e]+)[\s,]*([-\d.e]+)*/gi, (function(e, t, i) { n.push({ x: parseFloat(t), y: parseFloat(i) }) })), i.create(n, t) }, i.centre = function(e) { for (var t, n, r, a = i.area(e, !0), s = { x: 0, y: 0 }, l = 0; l < e.length; l++) r = (l + 1) % e.length, t = o.cross(e[l], e[r]), n = o.mult(o.add(e[l], e[r]), t), s = o.add(s, n); return o.div(s, 6 * a) }, i.mean = function(e) { for (var t = { x: 0, y: 0 }, n = 0; n < e.length; n++) t.x += e[n].x, t.y += e[n].y; return o.div(t, e.length) }, i.area = function(e, t) { for (var n = 0, i = e.length - 1, o = 0; o < e.length; o++) n += (e[i].x - e[o].x) * (e[i].y + e[o].y), i = o; return t ? n / 2 : Math.abs(n) / 2 }, i.inertia = function(e, t) { for (var n, i, r = 0, a = 0, s = e, l = 0; l < s.length; l++) i = (l + 1) % s.length, r += (n = Math.abs(o.cross(s[i], s[l]))) * (o.dot(s[i], s[i]) + o.dot(s[i], s[l]) + o.dot(s[l], s[l])), a += n; return t / 6 * (r / a) }, i.translate = function(e, t, n) { n = void 0 !== n ? n : 1; var i, o = e.length,
+ r = t.x * n,
+ a = t.y * n; for (i = 0; i < o; i++) e[i].x += r, e[i].y += a; return e }, i.rotate = function(e, t, n) { if (0 !== t) { var i, o, r, a, s = Math.cos(t),
+ l = Math.sin(t),
+ c = n.x,
+ u = n.y,
+ d = e.length; for (a = 0; a < d; a++) o = (i = e[a]).x - c, r = i.y - u, i.x = c + (o * s - r * l), i.y = u + (o * l + r * s); return e } }, i.contains = function(e, t) { for (var n, i = t.x, o = t.y, r = e.length, a = e[r - 1], s = 0; s < r; s++) { if (n = e[s], (i - a.x) * (n.y - a.y) + (o - a.y) * (a.x - n.x) > 0) return !1;
+ a = n } return !0 }, i.scale = function(e, t, n, r) { if (1 === t && 1 === n) return e; var a, s;
+ r = r || i.centre(e); for (var l = 0; l < e.length; l++) a = e[l], s = o.sub(a, r), e[l].x = r.x + s.x * t, e[l].y = r.y + s.y * n; return e }, i.chamfer = function(e, t, n, i, a) { t = "number" == typeof t ? [t] : t || [8], n = void 0 !== n ? n : -1, i = i || 2, a = a || 14; for (var s = [], l = 0; l < e.length; l++) { var c = e[l - 1 >= 0 ? l - 1 : e.length - 1],
+ u = e[l],
+ d = e[(l + 1) % e.length],
+ p = t[l < t.length ? l : t.length - 1]; if (0 !== p) { var f = o.normalise({ x: u.y - c.y, y: c.x - u.x }),
+ v = o.normalise({ x: d.y - u.y, y: u.x - d.x }),
+ y = Math.sqrt(2 * Math.pow(p, 2)),
+ m = o.mult(r.clone(f), p),
+ g = o.normalise(o.mult(o.add(f, v), .5)),
+ x = o.sub(u, o.mult(g, y)),
+ h = n; - 1 === n && (h = 1.75 * Math.pow(p, .32)), (h = r.clamp(h, i, a)) % 2 == 1 && (h += 1); for (var b = Math.acos(o.dot(f, v)) / h, S = 0; S < h; S++) s.push(o.add(o.rotate(m, b * S), x)) } else s.push(u) } return s }, i.clockwiseSort = function(e) { var t = i.mean(e); return e.sort((function(e, n) { return o.angle(t, e) - o.angle(t, n) })), e }, i.isConvex = function(e) { var t, n, i, o, r = 0,
+ a = e.length; if (a < 3) return null; for (t = 0; t < a; t++)
+ if (i = (t + 2) % a, o = (e[n = (t + 1) % a].x - e[t].x) * (e[i].y - e[n].y), (o -= (e[n].y - e[t].y) * (e[i].x - e[n].x)) < 0 ? r |= 1 : o > 0 && (r |= 2), 3 === r) return !1; return 0 !== r || null }, i.hull = function(e) { var t, n, i = [],
+ r = []; for ((e = e.slice(0)).sort((function(e, t) { var n = e.x - t.x; return 0 !== n ? n : e.y - t.y })), n = 0; n < e.length; n += 1) { for (t = e[n]; r.length >= 2 && o.cross3(r[r.length - 2], r[r.length - 1], t) <= 0;) r.pop();
+ r.push(t) } for (n = e.length - 1; n >= 0; n -= 1) { for (t = e[n]; i.length >= 2 && o.cross3(i[i.length - 2], i[i.length - 1], t) <= 0;) i.pop();
+ i.push(t) } return i.pop(), r.pop(), i.concat(r) } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(0);
+ i.on = function(e, t, n) { for (var i, o = t.split(" "), r = 0; r < o.length; r++) i = o[r], e.events = e.events || {}, e.events[i] = e.events[i] || [], e.events[i].push(n); return n }, i.off = function(e, t, n) { if (t) { "function" == typeof t && (n = t, t = o.keys(e.events).join(" ")); for (var i = t.split(" "), r = 0; r < i.length; r++) { var a = e.events[i[r]],
+ s = []; if (n && a)
+ for (var l = 0; l < a.length; l++) a[l] !== n && s.push(a[l]);
+ e.events[i[r]] = s } } else e.events = {} }, i.trigger = function(e, t, n) { var i, r, a, s, l = e.events; if (l && o.keys(l).length > 0) { n || (n = {}), i = t.split(" "); for (var c = 0; c < i.length; c++)
+ if (a = l[r = i[c]]) {
+ (s = o.clone(n, !1)).name = r, s.source = e; for (var u = 0; u < a.length; u++) a[u].apply(e, [s]) } } } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(4),
+ r = n(0),
+ a = n(1),
+ s = n(6);
+ i.create = function(e) { return r.extend({ id: r.nextId(), type: "composite", parent: null, isModified: !1, bodies: [], constraints: [], composites: [], label: "Composite", plugin: {}, cache: { allBodies: null, allConstraints: null, allComposites: null } }, e) }, i.setModified = function(e, t, n, o) { if (e.isModified = t, t && e.cache && (e.cache.allBodies = null, e.cache.allConstraints = null, e.cache.allComposites = null), n && e.parent && i.setModified(e.parent, t, n, o), o)
+ for (var r = 0; r < e.composites.length; r++) { var a = e.composites[r];
+ i.setModified(a, t, n, o) } }, i.add = function(e, t) { var n = [].concat(t);
+ o.trigger(e, "beforeAdd", { object: t }); for (var a = 0; a < n.length; a++) { var s = n[a]; switch (s.type) {
+ case "body":
+ if (s.parent !== s) { r.warn("Composite.add: skipped adding a compound body part (you must add its parent instead)"); break } i.addBody(e, s); break;
+ case "constraint":
+ i.addConstraint(e, s); break;
+ case "composite":
+ i.addComposite(e, s); break;
+ case "mouseConstraint":
+ i.addConstraint(e, s.constraint) } } return o.trigger(e, "afterAdd", { object: t }), e }, i.remove = function(e, t, n) { var r = [].concat(t);
+ o.trigger(e, "beforeRemove", { object: t }); for (var a = 0; a < r.length; a++) { var s = r[a]; switch (s.type) {
+ case "body":
+ i.removeBody(e, s, n); break;
+ case "constraint":
+ i.removeConstraint(e, s, n); break;
+ case "composite":
+ i.removeComposite(e, s, n); break;
+ case "mouseConstraint":
+ i.removeConstraint(e, s.constraint) } } return o.trigger(e, "afterRemove", { object: t }), e }, i.addComposite = function(e, t) { return e.composites.push(t), t.parent = e, i.setModified(e, !0, !0, !1), e }, i.removeComposite = function(e, t, n) { var o = r.indexOf(e.composites, t); if (-1 !== o && i.removeCompositeAt(e, o), n)
+ for (var a = 0; a < e.composites.length; a++) i.removeComposite(e.composites[a], t, !0); return e }, i.removeCompositeAt = function(e, t) { return e.composites.splice(t, 1), i.setModified(e, !0, !0, !1), e }, i.addBody = function(e, t) { return e.bodies.push(t), i.setModified(e, !0, !0, !1), e }, i.removeBody = function(e, t, n) { var o = r.indexOf(e.bodies, t); if (-1 !== o && (i.removeBodyAt(e, o), t.isSleeping = !1, t.sleepCounter = 0), n)
+ for (var a = 0; a < e.composites.length; a++) i.removeBody(e.composites[a], t, !0); return e }, i.removeBodyAt = function(e, t) { return e.bodies.splice(t, 1), i.setModified(e, !0, !0, !1), e }, i.addConstraint = function(e, t) { return e.constraints.push(t), i.setModified(e, !0, !0, !1), e }, i.removeConstraint = function(e, t, n) { var o = r.indexOf(e.constraints, t); if (-1 !== o && i.removeConstraintAt(e, o), n)
+ for (var a = 0; a < e.composites.length; a++) i.removeConstraint(e.composites[a], t, !0); return e }, i.removeConstraintAt = function(e, t) { return e.constraints.splice(t, 1), i.setModified(e, !0, !0, !1), e }, i.clear = function(e, t, n) { if (n)
+ for (var o = 0; o < e.composites.length; o++) i.clear(e.composites[o], t, !0); return t ? e.bodies = e.bodies.filter((function(e) { return e.isStatic })) : e.bodies.length = 0, e.constraints.length = 0, e.composites.length = 0, i.setModified(e, !0, !0, !1), e }, i.allBodies = function(e) { if (e.cache && e.cache.allBodies) return e.cache.allBodies; for (var t = [].concat(e.bodies), n = 0; n < e.composites.length; n++) t = t.concat(i.allBodies(e.composites[n])); return e.cache && (e.cache.allBodies = t), t }, i.allConstraints = function(e) { if (e.cache && e.cache.allConstraints) return e.cache.allConstraints; for (var t = [].concat(e.constraints), n = 0; n < e.composites.length; n++) t = t.concat(i.allConstraints(e.composites[n])); return e.cache && (e.cache.allConstraints = t), t }, i.allComposites = function(e) { if (e.cache && e.cache.allComposites) return e.cache.allComposites; for (var t = [].concat(e.composites), n = 0; n < e.composites.length; n++) t = t.concat(i.allComposites(e.composites[n])); return e.cache && (e.cache.allComposites = t), t }, i.get = function(e, t, n) { var o, r; switch (n) {
+ case "body":
+ o = i.allBodies(e); break;
+ case "constraint":
+ o = i.allConstraints(e); break;
+ case "composite":
+ o = i.allComposites(e).concat(e) } return o ? 0 === (r = o.filter((function(e) { return e.id.toString() === t.toString() }))).length ? null : r[0] : null }, i.move = function(e, t, n) { return i.remove(e, t), i.add(n, t), e }, i.rebase = function(e) { for (var t = i.allBodies(e).concat(i.allConstraints(e)).concat(i.allComposites(e)), n = 0; n < t.length; n++) t[n].id = r.nextId(); return e }, i.translate = function(e, t, n) { for (var o = n ? i.allBodies(e) : e.bodies, r = 0; r < o.length; r++) s.translate(o[r], t); return e }, i.rotate = function(e, t, n, o) { for (var r = Math.cos(t), a = Math.sin(t), l = o ? i.allBodies(e) : e.bodies, c = 0; c < l.length; c++) { var u = l[c],
+ d = u.position.x - n.x,
+ p = u.position.y - n.y;
+ s.setPosition(u, { x: n.x + (d * r - p * a), y: n.y + (d * a + p * r) }), s.rotate(u, t) } return e }, i.scale = function(e, t, n, o, r) { for (var a = r ? i.allBodies(e) : e.bodies, l = 0; l < a.length; l++) { var c = a[l],
+ u = c.position.x - o.x,
+ d = c.position.y - o.y;
+ s.setPosition(c, { x: o.x + u * t, y: o.y + d * n }), s.scale(c, t, n) } return e }, i.bounds = function(e) { for (var t = i.allBodies(e), n = [], o = 0; o < t.length; o += 1) { var r = t[o];
+ n.push(r.bounds.min, r.bounds.max) } return a.create(n) } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(3),
+ r = n(2),
+ a = n(7),
+ s = (n(16), n(0)),
+ l = n(1),
+ c = n(11);! function() { i._inertiaScale = 4, i._nextCollidingGroupId = 1, i._nextNonCollidingGroupId = -1, i._nextCategory = 1, i.create = function(t) { var n = { id: s.nextId(), type: "body", label: "Body", parts: [], plugin: {}, angle: 0, vertices: o.fromPath("L 0 0 L 40 0 L 40 40 L 0 40"), position: { x: 0, y: 0 }, force: { x: 0, y: 0 }, torque: 0, positionImpulse: { x: 0, y: 0 }, constraintImpulse: { x: 0, y: 0, angle: 0 }, totalContacts: 0, speed: 0, angularSpeed: 0, velocity: { x: 0, y: 0 }, angularVelocity: 0, isSensor: !1, isStatic: !1, isSleeping: !1, motion: 0, sleepThreshold: 60, density: .001, restitution: 0, friction: .1, frictionStatic: .5, frictionAir: .01, collisionFilter: { category: 1, mask: 4294967295, group: 0 }, slop: .05, timeScale: 1, render: { visible: !0, opacity: 1, strokeStyle: null, fillStyle: null, lineWidth: null, sprite: { xScale: 1, yScale: 1, xOffset: 0, yOffset: 0 } }, events: null, bounds: null, chamfer: null, circleRadius: 0, positionPrev: null, anglePrev: 0, parent: null, axes: null, area: 0, mass: 0, inertia: 0, _original: null },
+ i = s.extend(n, t); return e(i, t), i }, i.nextGroup = function(e) { return e ? i._nextNonCollidingGroupId-- : i._nextCollidingGroupId++ }, i.nextCategory = function() { return i._nextCategory = i._nextCategory << 1, i._nextCategory }; var e = function(e, t) { t = t || {}, i.set(e, { bounds: e.bounds || l.create(e.vertices), positionPrev: e.positionPrev || r.clone(e.position), anglePrev: e.anglePrev || e.angle, vertices: e.vertices, parts: e.parts || [e], isStatic: e.isStatic, isSleeping: e.isSleeping, parent: e.parent || e }), o.rotate(e.vertices, e.angle, e.position), c.rotate(e.axes, e.angle), l.update(e.bounds, e.vertices, e.velocity), i.set(e, { axes: t.axes || e.axes, area: t.area || e.area, mass: t.mass || e.mass, inertia: t.inertia || e.inertia }); var n = e.isStatic ? "#14151f" : s.choose(["#f19648", "#f5d259", "#f55a3c", "#063e7b", "#ececd1"]),
+ a = e.isStatic ? "#555" : "#ccc",
+ u = e.isStatic && null === e.render.fillStyle ? 1 : 0;
+ e.render.fillStyle = e.render.fillStyle || n, e.render.strokeStyle = e.render.strokeStyle || a, e.render.lineWidth = e.render.lineWidth || u, e.render.sprite.xOffset += -(e.bounds.min.x - e.position.x) / (e.bounds.max.x - e.bounds.min.x), e.render.sprite.yOffset += -(e.bounds.min.y - e.position.y) / (e.bounds.max.y - e.bounds.min.y) };
+ i.set = function(e, t, n) { var o; for (o in "string" == typeof t && (o = t, (t = {})[o] = n), t)
+ if (Object.prototype.hasOwnProperty.call(t, o)) switch (n = t[o], o) {
+ case "isStatic":
+ i.setStatic(e, n); break;
+ case "isSleeping":
+ a.set(e, n); break;
+ case "mass":
+ i.setMass(e, n); break;
+ case "density":
+ i.setDensity(e, n); break;
+ case "inertia":
+ i.setInertia(e, n); break;
+ case "vertices":
+ i.setVertices(e, n); break;
+ case "position":
+ i.setPosition(e, n); break;
+ case "angle":
+ i.setAngle(e, n); break;
+ case "velocity":
+ i.setVelocity(e, n); break;
+ case "angularVelocity":
+ i.setAngularVelocity(e, n); break;
+ case "parts":
+ i.setParts(e, n); break;
+ case "centre":
+ i.setCentre(e, n); break;
+ default:
+ e[o] = n } }, i.setStatic = function(e, t) { for (var n = 0; n < e.parts.length; n++) { var i = e.parts[n];
+ i.isStatic = t, t ? (i._original = { restitution: i.restitution, friction: i.friction, mass: i.mass, inertia: i.inertia, density: i.density, inverseMass: i.inverseMass, inverseInertia: i.inverseInertia }, i.restitution = 0, i.friction = 1, i.mass = i.inertia = i.density = 1 / 0, i.inverseMass = i.inverseInertia = 0, i.positionPrev.x = i.position.x, i.positionPrev.y = i.position.y, i.anglePrev = i.angle, i.angularVelocity = 0, i.speed = 0, i.angularSpeed = 0, i.motion = 0) : i._original && (i.restitution = i._original.restitution, i.friction = i._original.friction, i.mass = i._original.mass, i.inertia = i._original.inertia, i.density = i._original.density, i.inverseMass = i._original.inverseMass, i.inverseInertia = i._original.inverseInertia, i._original = null) } }, i.setMass = function(e, t) { var n = e.inertia / (e.mass / 6);
+ e.inertia = n * (t / 6), e.inverseInertia = 1 / e.inertia, e.mass = t, e.inverseMass = 1 / e.mass, e.density = e.mass / e.area }, i.setDensity = function(e, t) { i.setMass(e, t * e.area), e.density = t }, i.setInertia = function(e, t) { e.inertia = t, e.inverseInertia = 1 / e.inertia }, i.setVertices = function(e, t) { t[0].body === e ? e.vertices = t : e.vertices = o.create(t, e), e.axes = c.fromVertices(e.vertices), e.area = o.area(e.vertices), i.setMass(e, e.density * e.area); var n = o.centre(e.vertices);
+ o.translate(e.vertices, n, -1), i.setInertia(e, i._inertiaScale * o.inertia(e.vertices, e.mass)), o.translate(e.vertices, e.position), l.update(e.bounds, e.vertices, e.velocity) }, i.setParts = function(e, t, n) { var r; for (t = t.slice(0), e.parts.length = 0, e.parts.push(e), e.parent = e, r = 0; r < t.length; r++) { var a = t[r];
+ a !== e && (a.parent = e, e.parts.push(a)) } if (1 !== e.parts.length) { if (n = void 0 === n || n) { var s = []; for (r = 0; r < t.length; r++) s = s.concat(t[r].vertices);
+ o.clockwiseSort(s); var l = o.hull(s),
+ c = o.centre(l);
+ i.setVertices(e, l), o.translate(e.vertices, c) } var u = i._totalProperties(e);
+ e.area = u.area, e.parent = e, e.position.x = u.centre.x, e.position.y = u.centre.y, e.positionPrev.x = u.centre.x, e.positionPrev.y = u.centre.y, i.setMass(e, u.mass), i.setInertia(e, u.inertia), i.setPosition(e, u.centre) } }, i.setCentre = function(e, t, n) { n ? (e.positionPrev.x += t.x, e.positionPrev.y += t.y, e.position.x += t.x, e.position.y += t.y) : (e.positionPrev.x = t.x - (e.position.x - e.positionPrev.x), e.positionPrev.y = t.y - (e.position.y - e.positionPrev.y), e.position.x = t.x, e.position.y = t.y) }, i.setPosition = function(e, t) { var n = r.sub(t, e.position);
+ e.positionPrev.x += n.x, e.positionPrev.y += n.y; for (var i = 0; i < e.parts.length; i++) { var a = e.parts[i];
+ a.position.x += n.x, a.position.y += n.y, o.translate(a.vertices, n), l.update(a.bounds, a.vertices, e.velocity) } }, i.setAngle = function(e, t) { var n = t - e.angle;
+ e.anglePrev += n; for (var i = 0; i < e.parts.length; i++) { var a = e.parts[i];
+ a.angle += n, o.rotate(a.vertices, n, e.position), c.rotate(a.axes, n), l.update(a.bounds, a.vertices, e.velocity), i > 0 && r.rotateAbout(a.position, n, e.position, a.position) } }, i.setVelocity = function(e, t) { e.positionPrev.x = e.position.x - t.x, e.positionPrev.y = e.position.y - t.y, e.velocity.x = t.x, e.velocity.y = t.y, e.speed = r.magnitude(e.velocity) }, i.setAngularVelocity = function(e, t) { e.anglePrev = e.angle - t, e.angularVelocity = t, e.angularSpeed = Math.abs(e.angularVelocity) }, i.translate = function(e, t) { i.setPosition(e, r.add(e.position, t)) }, i.rotate = function(e, t, n) { if (n) { var o = Math.cos(t),
+ r = Math.sin(t),
+ a = e.position.x - n.x,
+ s = e.position.y - n.y;
+ i.setPosition(e, { x: n.x + (a * o - s * r), y: n.y + (a * r + s * o) }), i.setAngle(e, e.angle + t) } else i.setAngle(e, e.angle + t) }, i.scale = function(e, t, n, r) { var a = 0,
+ s = 0;
+ r = r || e.position; for (var u = 0; u < e.parts.length; u++) { var d = e.parts[u];
+ o.scale(d.vertices, t, n, r), d.axes = c.fromVertices(d.vertices), d.area = o.area(d.vertices), i.setMass(d, e.density * d.area), o.translate(d.vertices, { x: -d.position.x, y: -d.position.y }), i.setInertia(d, i._inertiaScale * o.inertia(d.vertices, d.mass)), o.translate(d.vertices, { x: d.position.x, y: d.position.y }), u > 0 && (a += d.area, s += d.inertia), d.position.x = r.x + (d.position.x - r.x) * t, d.position.y = r.y + (d.position.y - r.y) * n, l.update(d.bounds, d.vertices, e.velocity) } e.parts.length > 1 && (e.area = a, e.isStatic || (i.setMass(e, e.density * a), i.setInertia(e, s))), e.circleRadius && (t === n ? e.circleRadius *= t : e.circleRadius = null) }, i.update = function(e, t, n, i) { var a = Math.pow(t * n * e.timeScale, 2),
+ s = 1 - e.frictionAir * n * e.timeScale,
+ u = e.position.x - e.positionPrev.x,
+ d = e.position.y - e.positionPrev.y;
+ e.velocity.x = u * s * i + e.force.x / e.mass * a, e.velocity.y = d * s * i + e.force.y / e.mass * a, e.positionPrev.x = e.position.x, e.positionPrev.y = e.position.y, e.position.x += e.velocity.x, e.position.y += e.velocity.y, e.angularVelocity = (e.angle - e.anglePrev) * s * i + e.torque / e.inertia * a, e.anglePrev = e.angle, e.angle += e.angularVelocity, e.speed = r.magnitude(e.velocity), e.angularSpeed = Math.abs(e.angularVelocity); for (var p = 0; p < e.parts.length; p++) { var f = e.parts[p];
+ o.translate(f.vertices, e.velocity), p > 0 && (f.position.x += e.velocity.x, f.position.y += e.velocity.y), 0 !== e.angularVelocity && (o.rotate(f.vertices, e.angularVelocity, e.position), c.rotate(f.axes, e.angularVelocity), p > 0 && r.rotateAbout(f.position, e.angularVelocity, e.position, f.position)), l.update(f.bounds, f.vertices, e.velocity) } }, i.applyForce = function(e, t, n) { e.force.x += n.x, e.force.y += n.y; var i = t.x - e.position.x,
+ o = t.y - e.position.y;
+ e.torque += i * n.y - o * n.x }, i._totalProperties = function(e) { for (var t = { mass: 0, area: 0, inertia: 0, centre: { x: 0, y: 0 } }, n = 1 === e.parts.length ? 0 : 1; n < e.parts.length; n++) { var i = e.parts[n],
+ o = i.mass !== 1 / 0 ? i.mass : 1;
+ t.mass += o, t.area += i.area, t.inertia += i.inertia, t.centre = r.add(t.centre, r.mult(i.position, o)) } return t.centre = r.div(t.centre, t.mass), t } }() }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(4);
+ i._motionWakeThreshold = .18, i._motionSleepThreshold = .08, i._minBias = .9, i.update = function(e, t) { for (var n = t * t * t, o = 0; o < e.length; o++) { var r = e[o],
+ a = r.speed * r.speed + r.angularSpeed * r.angularSpeed; if (0 === r.force.x && 0 === r.force.y) { var s = Math.min(r.motion, a),
+ l = Math.max(r.motion, a);
+ r.motion = i._minBias * s + (1 - i._minBias) * l, r.sleepThreshold > 0 && r.motion < i._motionSleepThreshold * n ? (r.sleepCounter += 1, r.sleepCounter >= r.sleepThreshold && i.set(r, !0)) : r.sleepCounter > 0 && (r.sleepCounter -= 1) } else i.set(r, !1) } }, i.afterCollisions = function(e, t) { for (var n = t * t * t, o = 0; o < e.length; o++) { var r = e[o]; if (r.isActive) { var a = r.collision,
+ s = a.bodyA.parent,
+ l = a.bodyB.parent; if (!(s.isSleeping && l.isSleeping || s.isStatic || l.isStatic) && (s.isSleeping || l.isSleeping)) { var c = s.isSleeping && !s.isStatic ? s : l,
+ u = c === s ? l : s;!c.isStatic && u.motion > i._motionWakeThreshold * n && i.set(c, !1) } } } }, i.set = function(e, t) { var n = e.isSleeping;
+ t ? (e.isSleeping = !0, e.sleepCounter = e.sleepThreshold, e.positionImpulse.x = 0, e.positionImpulse.y = 0, e.positionPrev.x = e.position.x, e.positionPrev.y = e.position.y, e.anglePrev = e.angle, e.speed = 0, e.angularSpeed = 0, e.motion = 0, n || o.trigger(e, "sleepStart")) : (e.isSleeping = !1, e.sleepCounter = 0, n && o.trigger(e, "sleepEnd")) } }, function(e, t, n) { var i = {};
+ e.exports = i; var o, r, a, s = n(3),
+ l = n(9);
+ o = [], r = { overlap: 0, axis: null }, a = { overlap: 0, axis: null }, i.create = function(e, t) { return { pair: null, collided: !1, bodyA: e, bodyB: t, parentA: e.parent, parentB: t.parent, depth: 0, normal: { x: 0, y: 0 }, tangent: { x: 0, y: 0 }, penetration: { x: 0, y: 0 }, supports: [] } }, i.collides = function(e, t, n) { if (i._overlapAxes(r, e.vertices, t.vertices, e.axes), r.overlap <= 0) return null; if (i._overlapAxes(a, t.vertices, e.vertices, t.axes), a.overlap <= 0) return null; var o, c, u = n && n.table[l.id(e, t)];
+ u ? o = u.collision : ((o = i.create(e, t)).collided = !0, o.bodyA = e.id < t.id ? e : t, o.bodyB = e.id < t.id ? t : e, o.parentA = o.bodyA.parent, o.parentB = o.bodyB.parent), e = o.bodyA, t = o.bodyB, c = r.overlap < a.overlap ? r : a; var d = o.normal,
+ p = o.supports,
+ f = c.axis,
+ v = f.x,
+ y = f.y;
+ v * (t.position.x - e.position.x) + y * (t.position.y - e.position.y) < 0 ? (d.x = v, d.y = y) : (d.x = -v, d.y = -y), o.tangent.x = -d.y, o.tangent.y = d.x, o.depth = c.overlap, o.penetration.x = d.x * o.depth, o.penetration.y = d.y * o.depth; var m = i._findSupports(e, t, d, 1),
+ g = 0; if (s.contains(e.vertices, m[0]) && (p[g++] = m[0]), s.contains(e.vertices, m[1]) && (p[g++] = m[1]), g < 2) { var x = i._findSupports(t, e, d, -1);
+ s.contains(t.vertices, x[0]) && (p[g++] = x[0]), g < 2 && s.contains(t.vertices, x[1]) && (p[g++] = x[1]) } return 0 === g && (p[g++] = m[0]), p.length = g, o }, i._overlapAxes = function(e, t, n, i) { var o, r, a, s, l, c, u = t.length,
+ d = n.length,
+ p = t[0].x,
+ f = t[0].y,
+ v = n[0].x,
+ y = n[0].y,
+ m = i.length,
+ g = Number.MAX_VALUE,
+ x = 0; for (l = 0; l < m; l++) { var h = i[l],
+ b = h.x,
+ S = h.y,
+ w = p * b + f * S,
+ A = v * b + y * S,
+ P = w,
+ C = A; for (c = 1; c < u; c += 1)(s = t[c].x * b + t[c].y * S) > P ? P = s : s < w && (w = s); for (c = 1; c < d; c += 1)(s = n[c].x * b + n[c].y * S) > C ? C = s : s < A && (A = s); if ((o = (r = P - A) < (a = C - w) ? r : a) < g && (g = o, x = l, o <= 0)) break } e.axis = i[x], e.overlap = g }, i._projectToAxis = function(e, t, n) { for (var i = t[0].x * n.x + t[0].y * n.y, o = i, r = 1; r < t.length; r += 1) { var a = t[r].x * n.x + t[r].y * n.y;
+ a > o ? o = a : a < i && (i = a) } e.min = i, e.max = o }, i._findSupports = function(e, t, n, i) { var r, a, s, l, c, u = t.vertices,
+ d = u.length,
+ p = e.position.x,
+ f = e.position.y,
+ v = n.x * i,
+ y = n.y * i,
+ m = Number.MAX_VALUE; for (c = 0; c < d; c += 1)(l = v * (p - (a = u[c]).x) + y * (f - a.y)) < m && (m = l, r = a); return m = v * (p - (s = u[(d + r.index - 1) % d]).x) + y * (f - s.y), v * (p - (a = u[(r.index + 1) % d]).x) + y * (f - a.y) < m ? (o[0] = r, o[1] = a, o) : (o[0] = r, o[1] = s, o) } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(17);
+ i.create = function(e, t) { var n = e.bodyA,
+ o = e.bodyB,
+ r = { id: i.id(n, o), bodyA: n, bodyB: o, collision: e, contacts: [], activeContacts: [], separation: 0, isActive: !0, confirmedActive: !0, isSensor: n.isSensor || o.isSensor, timeCreated: t, timeUpdated: t, inverseMass: 0, friction: 0, frictionStatic: 0, restitution: 0, slop: 0 }; return i.update(r, e, t), r }, i.update = function(e, t, n) { var i = e.contacts,
+ r = t.supports,
+ a = e.activeContacts,
+ s = t.parentA,
+ l = t.parentB,
+ c = s.vertices.length;
+ e.isActive = !0, e.timeUpdated = n, e.collision = t, e.separation = t.depth, e.inverseMass = s.inverseMass + l.inverseMass, e.friction = s.friction < l.friction ? s.friction : l.friction, e.frictionStatic = s.frictionStatic > l.frictionStatic ? s.frictionStatic : l.frictionStatic, e.restitution = s.restitution > l.restitution ? s.restitution : l.restitution, e.slop = s.slop > l.slop ? s.slop : l.slop, t.pair = e, a.length = 0; for (var u = 0; u < r.length; u++) { var d = r[u],
+ p = d.body === s ? d.index : c + d.index,
+ f = i[p];
+ f ? a.push(f) : a.push(i[p] = o.create(d)) } }, i.setActive = function(e, t, n) { t ? (e.isActive = !0, e.timeUpdated = n) : (e.isActive = !1, e.activeContacts.length = 0) }, i.id = function(e, t) { return e.id < t.id ? "A" + e.id + "B" + t.id : "A" + t.id + "B" + e.id } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(3),
+ r = n(2),
+ a = n(7),
+ s = n(1),
+ l = n(11),
+ c = n(0);
+ i._warming = .4, i._torqueDampen = 1, i._minLength = 1e-6, i.create = function(e) { var t = e;
+ t.bodyA && !t.pointA && (t.pointA = { x: 0, y: 0 }), t.bodyB && !t.pointB && (t.pointB = { x: 0, y: 0 }); var n = t.bodyA ? r.add(t.bodyA.position, t.pointA) : t.pointA,
+ i = t.bodyB ? r.add(t.bodyB.position, t.pointB) : t.pointB,
+ o = r.magnitude(r.sub(n, i));
+ t.length = void 0 !== t.length ? t.length : o, t.id = t.id || c.nextId(), t.label = t.label || "Constraint", t.type = "constraint", t.stiffness = t.stiffness || (t.length > 0 ? 1 : .7), t.damping = t.damping || 0, t.angularStiffness = t.angularStiffness || 0, t.angleA = t.bodyA ? t.bodyA.angle : t.angleA, t.angleB = t.bodyB ? t.bodyB.angle : t.angleB, t.plugin = {}; var a = { visible: !0, lineWidth: 2, strokeStyle: "#ffffff", type: "line", anchors: !0 }; return 0 === t.length && t.stiffness > .1 ? (a.type = "pin", a.anchors = !1) : t.stiffness < .9 && (a.type = "spring"), t.render = c.extend(a, t.render), t }, i.preSolveAll = function(e) { for (var t = 0; t < e.length; t += 1) { var n = e[t],
+ i = n.constraintImpulse;
+ n.isStatic || 0 === i.x && 0 === i.y && 0 === i.angle || (n.position.x += i.x, n.position.y += i.y, n.angle += i.angle) } }, i.solveAll = function(e, t) { for (var n = 0; n < e.length; n += 1) { var o = e[n],
+ r = !o.bodyA || o.bodyA && o.bodyA.isStatic,
+ a = !o.bodyB || o.bodyB && o.bodyB.isStatic;
+ (r || a) && i.solve(e[n], t) } for (n = 0; n < e.length; n += 1) r = !(o = e[n]).bodyA || o.bodyA && o.bodyA.isStatic, a = !o.bodyB || o.bodyB && o.bodyB.isStatic, r || a || i.solve(e[n], t) }, i.solve = function(e, t) { var n = e.bodyA,
+ o = e.bodyB,
+ a = e.pointA,
+ s = e.pointB; if (n || o) { n && !n.isStatic && (r.rotate(a, n.angle - e.angleA, a), e.angleA = n.angle), o && !o.isStatic && (r.rotate(s, o.angle - e.angleB, s), e.angleB = o.angle); var l = a,
+ c = s; if (n && (l = r.add(n.position, a)), o && (c = r.add(o.position, s)), l && c) { var u = r.sub(l, c),
+ d = r.magnitude(u);
+ d < i._minLength && (d = i._minLength); var p, f, v, y, m, g = (d - e.length) / d,
+ x = e.stiffness < 1 ? e.stiffness * t : e.stiffness,
+ h = r.mult(u, g * x),
+ b = (n ? n.inverseMass : 0) + (o ? o.inverseMass : 0),
+ S = b + ((n ? n.inverseInertia : 0) + (o ? o.inverseInertia : 0)); if (e.damping) { var w = r.create();
+ v = r.div(u, d), m = r.sub(o && r.sub(o.position, o.positionPrev) || w, n && r.sub(n.position, n.positionPrev) || w), y = r.dot(v, m) } n && !n.isStatic && (f = n.inverseMass / b, n.constraintImpulse.x -= h.x * f, n.constraintImpulse.y -= h.y * f, n.position.x -= h.x * f, n.position.y -= h.y * f, e.damping && (n.positionPrev.x -= e.damping * v.x * y * f, n.positionPrev.y -= e.damping * v.y * y * f), p = r.cross(a, h) / S * i._torqueDampen * n.inverseInertia * (1 - e.angularStiffness), n.constraintImpulse.angle -= p, n.angle -= p), o && !o.isStatic && (f = o.inverseMass / b, o.constraintImpulse.x += h.x * f, o.constraintImpulse.y += h.y * f, o.position.x += h.x * f, o.position.y += h.y * f, e.damping && (o.positionPrev.x += e.damping * v.x * y * f, o.positionPrev.y += e.damping * v.y * y * f), p = r.cross(s, h) / S * i._torqueDampen * o.inverseInertia * (1 - e.angularStiffness), o.constraintImpulse.angle += p, o.angle += p) } } }, i.postSolveAll = function(e) { for (var t = 0; t < e.length; t++) { var n = e[t],
+ c = n.constraintImpulse; if (!(n.isStatic || 0 === c.x && 0 === c.y && 0 === c.angle)) { a.set(n, !1); for (var u = 0; u < n.parts.length; u++) { var d = n.parts[u];
+ o.translate(d.vertices, c), u > 0 && (d.position.x += c.x, d.position.y += c.y), 0 !== c.angle && (o.rotate(d.vertices, c.angle, n.position), l.rotate(d.axes, c.angle), u > 0 && r.rotateAbout(d.position, c.angle, n.position, d.position)), s.update(d.bounds, d.vertices, n.velocity) } c.angle *= i._warming, c.x *= i._warming, c.y *= i._warming } } }, i.pointAWorld = function(e) { return { x: (e.bodyA ? e.bodyA.position.x : 0) + (e.pointA ? e.pointA.x : 0), y: (e.bodyA ? e.bodyA.position.y : 0) + (e.pointA ? e.pointA.y : 0) } }, i.pointBWorld = function(e) { return { x: (e.bodyB ? e.bodyB.position.x : 0) + (e.pointB ? e.pointB.x : 0), y: (e.bodyB ? e.bodyB.position.y : 0) + (e.pointB ? e.pointB.y : 0) } } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(2),
+ r = n(0);
+ i.fromVertices = function(e) { for (var t = {}, n = 0; n < e.length; n++) { var i = (n + 1) % e.length,
+ a = o.normalise({ x: e[i].y - e[n].y, y: e[n].x - e[i].x }),
+ s = 0 === a.y ? 1 / 0 : a.x / a.y;
+ t[s = s.toFixed(3).toString()] = a } return r.values(t) }, i.rotate = function(e, t) { if (0 !== t)
+ for (var n = Math.cos(t), i = Math.sin(t), o = 0; o < e.length; o++) { var r, a = e[o];
+ r = a.x * n - a.y * i, a.y = a.x * i + a.y * n, a.x = r } } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(3),
+ r = n(0),
+ a = n(6),
+ s = n(1),
+ l = n(2);
+ i.rectangle = function(e, t, n, i, s) { s = s || {}; var l = { label: "Rectangle Body", position: { x: e, y: t }, vertices: o.fromPath("L 0 0 L " + n + " 0 L " + n + " " + i + " L 0 " + i) }; if (s.chamfer) { var c = s.chamfer;
+ l.vertices = o.chamfer(l.vertices, c.radius, c.quality, c.qualityMin, c.qualityMax), delete s.chamfer } return a.create(r.extend({}, l, s)) }, i.trapezoid = function(e, t, n, i, s, l) { l = l || {}; var c, u = n * (s *= .5),
+ d = u + (1 - 2 * s) * n,
+ p = d + u;
+ c = s < .5 ? "L 0 0 L " + u + " " + -i + " L " + d + " " + -i + " L " + p + " 0" : "L 0 0 L " + d + " " + -i + " L " + p + " 0"; var f = { label: "Trapezoid Body", position: { x: e, y: t }, vertices: o.fromPath(c) }; if (l.chamfer) { var v = l.chamfer;
+ f.vertices = o.chamfer(f.vertices, v.radius, v.quality, v.qualityMin, v.qualityMax), delete l.chamfer } return a.create(r.extend({}, f, l)) }, i.circle = function(e, t, n, o, a) { o = o || {}; var s = { label: "Circle Body", circleRadius: n };
+ a = a || 25; var l = Math.ceil(Math.max(10, Math.min(a, n))); return l % 2 == 1 && (l += 1), i.polygon(e, t, l, n, r.extend({}, s, o)) }, i.polygon = function(e, t, n, s, l) { if (l = l || {}, n < 3) return i.circle(e, t, s, l); for (var c = 2 * Math.PI / n, u = "", d = .5 * c, p = 0; p < n; p += 1) { var f = d + p * c,
+ v = Math.cos(f) * s,
+ y = Math.sin(f) * s;
+ u += "L " + v.toFixed(3) + " " + y.toFixed(3) + " " } var m = { label: "Polygon Body", position: { x: e, y: t }, vertices: o.fromPath(u) }; if (l.chamfer) { var g = l.chamfer;
+ m.vertices = o.chamfer(m.vertices, g.radius, g.quality, g.qualityMin, g.qualityMax), delete l.chamfer } return a.create(r.extend({}, m, l)) }, i.fromVertices = function(e, t, n, i, c, u, d, p) { var f, v, y, m, g, x, h, b, S, w, A = r.getDecomp(); for (f = Boolean(A && A.quickDecomp), i = i || {}, y = [], c = void 0 !== c && c, u = void 0 !== u ? u : .01, d = void 0 !== d ? d : 10, p = void 0 !== p ? p : .01, r.isArray(n[0]) || (n = [n]), S = 0; S < n.length; S += 1)
+ if (g = n[S], !(m = o.isConvex(g)) && !f && r.warnOnce("Bodies.fromVertices: Install the 'poly-decomp' library and use Common.setDecomp or provide 'decomp' as a global to decompose concave vertices."), m || !f) g = m ? o.clockwiseSort(g) : o.hull(g), y.push({ position: { x: e, y: t }, vertices: g });
+ else { var P = g.map((function(e) { return [e.x, e.y] }));
+ A.makeCCW(P), !1 !== u && A.removeCollinearPoints(P, u), !1 !== p && A.removeDuplicatePoints && A.removeDuplicatePoints(P, p); var C = A.quickDecomp(P); for (x = 0; x < C.length; x++) { var B = C[x].map((function(e) { return { x: e[0], y: e[1] } }));
+ d > 0 && o.area(B) < d || y.push({ position: o.centre(B), vertices: B }) } } for (x = 0; x < y.length; x++) y[x] = a.create(r.extend(y[x], i)); if (c)
+ for (x = 0; x < y.length; x++) { var M = y[x]; for (h = x + 1; h < y.length; h++) { var k = y[h]; if (s.overlaps(M.bounds, k.bounds)) { var _ = M.vertices,
+ I = k.vertices; for (b = 0; b < M.vertices.length; b++)
+ for (w = 0; w < k.vertices.length; w++) { var T = l.magnitudeSquared(l.sub(_[(b + 1) % _.length], I[w])),
+ R = l.magnitudeSquared(l.sub(_[b], I[(w + 1) % I.length]));
+ T < 5 && R < 5 && (_[b].isInternal = !0, I[w].isInternal = !0) } } } }
+ return y.length > 1 ? (v = a.create(r.extend({ parts: y.slice(0) }, i)), a.setPosition(v, { x: e, y: t }), v) : y[0] } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(0);
+ i.create = function(e) { var t = {}; return e || o.log("Mouse.create: element was undefined, defaulting to document.body", "warn"), t.element = e || document.body, t.absolute = { x: 0, y: 0 }, t.position = { x: 0, y: 0 }, t.mousedownPosition = { x: 0, y: 0 }, t.mouseupPosition = { x: 0, y: 0 }, t.offset = { x: 0, y: 0 }, t.scale = { x: 1, y: 1 }, t.wheelDelta = 0, t.button = -1, t.pixelRatio = parseInt(t.element.getAttribute("data-pixel-ratio"), 10) || 1, t.sourceEvents = { mousemove: null, mousedown: null, mouseup: null, mousewheel: null }, t.mousemove = function(e) { var n = i._getRelativeMousePosition(e, t.element, t.pixelRatio);
+ e.changedTouches && (t.button = 0, e.preventDefault()), t.absolute.x = n.x, t.absolute.y = n.y, t.position.x = t.absolute.x * t.scale.x + t.offset.x, t.position.y = t.absolute.y * t.scale.y + t.offset.y, t.sourceEvents.mousemove = e }, t.mousedown = function(e) { var n = i._getRelativeMousePosition(e, t.element, t.pixelRatio);
+ e.changedTouches ? (t.button = 0, e.preventDefault()) : t.button = e.button, t.absolute.x = n.x, t.absolute.y = n.y, t.position.x = t.absolute.x * t.scale.x + t.offset.x, t.position.y = t.absolute.y * t.scale.y + t.offset.y, t.mousedownPosition.x = t.position.x, t.mousedownPosition.y = t.position.y, t.sourceEvents.mousedown = e }, t.mouseup = function(e) { var n = i._getRelativeMousePosition(e, t.element, t.pixelRatio);
+ e.changedTouches && e.preventDefault(), t.button = -1, t.absolute.x = n.x, t.absolute.y = n.y, t.position.x = t.absolute.x * t.scale.x + t.offset.x, t.position.y = t.absolute.y * t.scale.y + t.offset.y, t.mouseupPosition.x = t.position.x, t.mouseupPosition.y = t.position.y, t.sourceEvents.mouseup = e }, t.mousewheel = function(e) { t.wheelDelta = Math.max(-1, Math.min(1, e.wheelDelta || -e.detail)), e.preventDefault() }, i.setElement(t, t.element), t }, i.setElement = function(e, t) { e.element = t, t.addEventListener("mousemove", e.mousemove), t.addEventListener("mousedown", e.mousedown), t.addEventListener("mouseup", e.mouseup), t.addEventListener("mousewheel", e.mousewheel), t.addEventListener("DOMMouseScroll", e.mousewheel), t.addEventListener("touchmove", e.mousemove), t.addEventListener("touchstart", e.mousedown), t.addEventListener("touchend", e.mouseup) }, i.clearSourceEvents = function(e) { e.sourceEvents.mousemove = null, e.sourceEvents.mousedown = null, e.sourceEvents.mouseup = null, e.sourceEvents.mousewheel = null, e.wheelDelta = 0 }, i.setOffset = function(e, t) { e.offset.x = t.x, e.offset.y = t.y, e.position.x = e.absolute.x * e.scale.x + e.offset.x, e.position.y = e.absolute.y * e.scale.y + e.offset.y }, i.setScale = function(e, t) { e.scale.x = t.x, e.scale.y = t.y, e.position.x = e.absolute.x * e.scale.x + e.offset.x, e.position.y = e.absolute.y * e.scale.y + e.offset.y }, i._getRelativeMousePosition = function(e, t, n) { var i, o, r = t.getBoundingClientRect(),
+ a = document.documentElement || document.body.parentNode || document.body,
+ s = void 0 !== window.pageXOffset ? window.pageXOffset : a.scrollLeft,
+ l = void 0 !== window.pageYOffset ? window.pageYOffset : a.scrollTop,
+ c = e.changedTouches; return c ? (i = c[0].pageX - r.left - s, o = c[0].pageY - r.top - l) : (i = e.pageX - r.left - s, o = e.pageY - r.top - l), { x: i / (t.clientWidth / (t.width || t.clientWidth) * n), y: o / (t.clientHeight / (t.height || t.clientHeight) * n) } } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(0),
+ r = n(8);
+ i.create = function(e) { return o.extend({ bodies: [], pairs: null }, e) }, i.setBodies = function(e, t) { e.bodies = t.slice(0) }, i.clear = function(e) { e.bodies = [] }, i.collisions = function(e) { var t, n, o = [],
+ a = e.pairs,
+ s = e.bodies,
+ l = s.length,
+ c = i.canCollide,
+ u = r.collides; for (s.sort(i._compareBoundsX), t = 0; t < l; t++) { var d = s[t],
+ p = d.bounds,
+ f = d.bounds.max.x,
+ v = d.bounds.max.y,
+ y = d.bounds.min.y,
+ m = d.isStatic || d.isSleeping,
+ g = d.parts.length,
+ x = 1 === g; for (n = t + 1; n < l; n++) { var h = s[n]; if ((M = h.bounds).min.x > f) break; if (!(v < M.min.y || y > M.max.y) && (!m || !h.isStatic && !h.isSleeping) && c(d.collisionFilter, h.collisionFilter)) { var b = h.parts.length; if (x && 1 === b)(C = u(d, h, a)) && o.push(C);
+ else
+ for (var S = b > 1 ? 1 : 0, w = g > 1 ? 1 : 0; w < g; w++)
+ for (var A = d.parts[w], P = (p = A.bounds, S); P < b; P++) { var C, B = h.parts[P],
+ M = B.bounds;
+ p.min.x > M.max.x || p.max.x < M.min.x || p.max.y < M.min.y || p.min.y > M.max.y || (C = u(A, B, a)) && o.push(C) } } } } return o }, i.canCollide = function(e, t) { return e.group === t.group && 0 !== e.group ? e.group > 0 : 0 != (e.mask & t.category) && 0 != (t.mask & e.category) }, i._compareBoundsX = function(e, t) { return e.bounds.min.x - t.bounds.min.x } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(0);
+ i._registry = {}, i.register = function(e) { if (i.isPlugin(e) || o.warn("Plugin.register:", i.toString(e), "does not implement all required fields."), e.name in i._registry) { var t = i._registry[e.name],
+ n = i.versionParse(e.version).number,
+ r = i.versionParse(t.version).number;
+ n > r ? (o.warn("Plugin.register:", i.toString(t), "was upgraded to", i.toString(e)), i._registry[e.name] = e) : n < r ? o.warn("Plugin.register:", i.toString(t), "can not be downgraded to", i.toString(e)) : e !== t && o.warn("Plugin.register:", i.toString(e), "is already registered to different plugin object") } else i._registry[e.name] = e; return e }, i.resolve = function(e) { return i._registry[i.dependencyParse(e).name] }, i.toString = function(e) { return "string" == typeof e ? e : (e.name || "anonymous") + "@" + (e.version || e.range || "0.0.0") }, i.isPlugin = function(e) { return e && e.name && e.version && e.install }, i.isUsed = function(e, t) { return e.used.indexOf(t) > -1 }, i.isFor = function(e, t) { var n = e.for && i.dependencyParse(e.for); return !e.for || t.name === n.name && i.versionSatisfies(t.version, n.range) }, i.use = function(e, t) { if (e.uses = (e.uses || []).concat(t || []), 0 !== e.uses.length) { for (var n = i.dependencies(e), r = o.topologicalSort(n), a = [], s = 0; s < r.length; s += 1)
+ if (r[s] !== e.name) { var l = i.resolve(r[s]);
+ l ? i.isUsed(e, l.name) || (i.isFor(l, e) || (o.warn("Plugin.use:", i.toString(l), "is for", l.for, "but installed on", i.toString(e) + "."), l._warned = !0), l.install ? l.install(e) : (o.warn("Plugin.use:", i.toString(l), "does not specify an install function."), l._warned = !0), l._warned ? (a.push("🔶 " + i.toString(l)), delete l._warned) : a.push("✅ " + i.toString(l)), e.used.push(l.name)) : a.push("❌ " + r[s]) } a.length > 0 && o.info(a.join(" ")) } else o.warn("Plugin.use:", i.toString(e), "does not specify any dependencies to install.") }, i.dependencies = function(e, t) { var n = i.dependencyParse(e),
+ r = n.name; if (!(r in (t = t || {}))) { e = i.resolve(e) || e, t[r] = o.map(e.uses || [], (function(t) { i.isPlugin(t) && i.register(t); var r = i.dependencyParse(t),
+ a = i.resolve(t); return a && !i.versionSatisfies(a.version, r.range) ? (o.warn("Plugin.dependencies:", i.toString(a), "does not satisfy", i.toString(r), "used by", i.toString(n) + "."), a._warned = !0, e._warned = !0) : a || (o.warn("Plugin.dependencies:", i.toString(t), "used by", i.toString(n), "could not be resolved."), e._warned = !0), r.name })); for (var a = 0; a < t[r].length; a += 1) i.dependencies(t[r][a], t); return t } }, i.dependencyParse = function(e) { return o.isString(e) ? (/^[\w-]+(@(\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-+]+)?))?$/.test(e) || o.warn("Plugin.dependencyParse:", e, "is not a valid dependency string."), { name: e.split("@")[0], range: e.split("@")[1] || "*" }) : { name: e.name, range: e.range || e.version } }, i.versionParse = function(e) { var t = /^(\*)|(\^|~|>=|>)?\s*((\d+)\.(\d+)\.(\d+))(-[0-9A-Za-z-+]+)?$/;
+ t.test(e) || o.warn("Plugin.versionParse:", e, "is not a valid version or range."); var n = t.exec(e),
+ i = Number(n[4]),
+ r = Number(n[5]),
+ a = Number(n[6]); return { isRange: Boolean(n[1] || n[2]), version: n[3], range: e, operator: n[1] || n[2] || "", major: i, minor: r, patch: a, parts: [i, r, a], prerelease: n[7], number: 1e8 * i + 1e4 * r + a } }, i.versionSatisfies = function(e, t) { t = t || "*"; var n = i.versionParse(t),
+ o = i.versionParse(e); if (n.isRange) { if ("*" === n.operator || "*" === e) return !0; if (">" === n.operator) return o.number > n.number; if (">=" === n.operator) return o.number >= n.number; if ("~" === n.operator) return o.major === n.major && o.minor === n.minor && o.patch >= n.patch; if ("^" === n.operator) return n.major > 0 ? o.major === n.major && o.number >= n.number : n.minor > 0 ? o.minor === n.minor && o.patch >= n.patch : o.patch === n.patch } return e === t || "*" === e } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(0),
+ r = n(5),
+ a = n(1),
+ s = n(4),
+ l = n(2),
+ c = n(13);! function() { var e, t; "undefined" != typeof window && (e = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || function(e) { window.setTimeout((function() { e(o.now()) }), 1e3 / 60) }, t = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame), i._goodFps = 30, i._goodDelta = 1e3 / 60, i.create = function(e) { var t = { engine: null, element: null, canvas: null, mouse: null, frameRequestId: null, timing: { historySize: 60, delta: 0, deltaHistory: [], lastTime: 0, lastTimestamp: 0, lastElapsed: 0, timestampElapsed: 0, timestampElapsedHistory: [], engineDeltaHistory: [], engineElapsedHistory: [], elapsedHistory: [] }, options: { width: 800, height: 600, pixelRatio: 1, background: "#14151f", wireframeBackground: "#14151f", hasBounds: !!e.bounds, enabled: !0, wireframes: !0, showSleeping: !0, showDebug: !1, showStats: !1, showPerformance: !1, showBounds: !1, showVelocity: !1, showCollisions: !1, showSeparations: !1, showAxes: !1, showPositions: !1, showAngleIndicator: !1, showIds: !1, showVertexNumbers: !1, showConvexHulls: !1, showInternalEdges: !1, showMousePosition: !1 } },
+ n = o.extend(t, e); return n.canvas && (n.canvas.width = n.options.width || n.canvas.width, n.canvas.height = n.options.height || n.canvas.height), n.mouse = e.mouse, n.engine = e.engine, n.canvas = n.canvas || d(n.options.width, n.options.height), n.context = n.canvas.getContext("2d"), n.textures = {}, n.bounds = n.bounds || { min: { x: 0, y: 0 }, max: { x: n.canvas.width, y: n.canvas.height } }, n.controller = i, n.options.showBroadphase = !1, 1 !== n.options.pixelRatio && i.setPixelRatio(n, n.options.pixelRatio), o.isElement(n.element) && n.element.appendChild(n.canvas), n }, i.run = function(t) {! function o(r) { t.frameRequestId = e(o), n(t, r), i.world(t, r), (t.options.showStats || t.options.showDebug) && i.stats(t, t.context, r), (t.options.showPerformance || t.options.showDebug) && i.performance(t, t.context, r) }() }, i.stop = function(e) { t(e.frameRequestId) }, i.setPixelRatio = function(e, t) { var n = e.options,
+ i = e.canvas; "auto" === t && (t = p(i)), n.pixelRatio = t, i.setAttribute("data-pixel-ratio", t), i.width = n.width * t, i.height = n.height * t, i.style.width = n.width + "px", i.style.height = n.height + "px" }, i.lookAt = function(e, t, n, i) { i = void 0 === i || i, t = o.isArray(t) ? t : [t], n = n || { x: 0, y: 0 }; for (var r = { min: { x: 1 / 0, y: 1 / 0 }, max: { x: -1 / 0, y: -1 / 0 } }, a = 0; a < t.length; a += 1) { var s = t[a],
+ l = s.bounds ? s.bounds.min : s.min || s.position || s,
+ u = s.bounds ? s.bounds.max : s.max || s.position || s;
+ l && u && (l.x < r.min.x && (r.min.x = l.x), u.x > r.max.x && (r.max.x = u.x), l.y < r.min.y && (r.min.y = l.y), u.y > r.max.y && (r.max.y = u.y)) } var d = r.max.x - r.min.x + 2 * n.x,
+ p = r.max.y - r.min.y + 2 * n.y,
+ f = e.canvas.height,
+ v = e.canvas.width / f,
+ y = d / p,
+ m = 1,
+ g = 1;
+ y > v ? g = y / v : m = v / y, e.options.hasBounds = !0, e.bounds.min.x = r.min.x, e.bounds.max.x = r.min.x + d * m, e.bounds.min.y = r.min.y, e.bounds.max.y = r.min.y + p * g, i && (e.bounds.min.x += .5 * d - d * m * .5, e.bounds.max.x += .5 * d - d * m * .5, e.bounds.min.y += .5 * p - p * g * .5, e.bounds.max.y += .5 * p - p * g * .5), e.bounds.min.x -= n.x, e.bounds.max.x -= n.x, e.bounds.min.y -= n.y, e.bounds.max.y -= n.y, e.mouse && (c.setScale(e.mouse, { x: (e.bounds.max.x - e.bounds.min.x) / e.canvas.width, y: (e.bounds.max.y - e.bounds.min.y) / e.canvas.height }), c.setOffset(e.mouse, e.bounds.min)) }, i.startViewTransform = function(e) { var t = e.bounds.max.x - e.bounds.min.x,
+ n = e.bounds.max.y - e.bounds.min.y,
+ i = t / e.options.width,
+ o = n / e.options.height;
+ e.context.setTransform(e.options.pixelRatio / i, 0, 0, e.options.pixelRatio / o, 0, 0), e.context.translate(-e.bounds.min.x, -e.bounds.min.y) }, i.endViewTransform = function(e) { e.context.setTransform(e.options.pixelRatio, 0, 0, e.options.pixelRatio, 0, 0) }, i.world = function(e, t) { var n, u = o.now(),
+ d = e.engine,
+ p = d.world,
+ f = e.canvas,
+ y = e.context,
+ m = e.options,
+ g = e.timing,
+ x = r.allBodies(p),
+ h = r.allConstraints(p),
+ b = m.wireframes ? m.wireframeBackground : m.background,
+ S = [],
+ w = [],
+ A = { timestamp: d.timing.timestamp }; if (s.trigger(e, "beforeRender", A), e.currentBackground !== b && v(e, b), y.globalCompositeOperation = "source-in", y.fillStyle = "transparent", y.fillRect(0, 0, f.width, f.height), y.globalCompositeOperation = "source-over", m.hasBounds) { for (n = 0; n < x.length; n++) { var P = x[n];
+ a.overlaps(P.bounds, e.bounds) && S.push(P) } for (n = 0; n < h.length; n++) { var C = h[n],
+ B = C.bodyA,
+ M = C.bodyB,
+ k = C.pointA,
+ _ = C.pointB;
+ B && (k = l.add(B.position, C.pointA)), M && (_ = l.add(M.position, C.pointB)), k && _ && ((a.contains(e.bounds, k) || a.contains(e.bounds, _)) && w.push(C)) } i.startViewTransform(e), e.mouse && (c.setScale(e.mouse, { x: (e.bounds.max.x - e.bounds.min.x) / e.options.width, y: (e.bounds.max.y - e.bounds.min.y) / e.options.height }), c.setOffset(e.mouse, e.bounds.min)) } else w = h, S = x, 1 !== e.options.pixelRatio && e.context.setTransform(e.options.pixelRatio, 0, 0, e.options.pixelRatio, 0, 0);!m.wireframes || d.enableSleeping && m.showSleeping ? i.bodies(e, S, y) : (m.showConvexHulls && i.bodyConvexHulls(e, S, y), i.bodyWireframes(e, S, y)), m.showBounds && i.bodyBounds(e, S, y), (m.showAxes || m.showAngleIndicator) && i.bodyAxes(e, S, y), m.showPositions && i.bodyPositions(e, S, y), m.showVelocity && i.bodyVelocity(e, S, y), m.showIds && i.bodyIds(e, S, y), m.showSeparations && i.separations(e, d.pairs.list, y), m.showCollisions && i.collisions(e, d.pairs.list, y), m.showVertexNumbers && i.vertexNumbers(e, S, y), m.showMousePosition && i.mousePosition(e, e.mouse, y), i.constraints(w, y), m.hasBounds && i.endViewTransform(e), s.trigger(e, "afterRender", A), g.lastElapsed = o.now() - u }, i.stats = function(e, t, n) { for (var i = e.engine, o = i.world, a = r.allBodies(o), s = 0, l = 0, c = 0; c < a.length; c += 1) s += a[c].parts.length; var u = { Part: s, Body: a.length, Cons: r.allConstraints(o).length, Comp: r.allComposites(o).length, Pair: i.pairs.list.length }; for (var d in t.fillStyle = "#0e0f19", t.fillRect(l, 0, 302.5, 44), t.font = "12px Arial", t.textBaseline = "top", t.textAlign = "right", u) { var p = u[d];
+ t.fillStyle = "#aaa", t.fillText(d, l + 55, 8), t.fillStyle = "#eee", t.fillText(p, l + 55, 26), l += 55 } }, i.performance = function(e, t) { var n = e.engine,
+ o = e.timing,
+ r = o.deltaHistory,
+ a = o.elapsedHistory,
+ s = o.timestampElapsedHistory,
+ l = o.engineDeltaHistory,
+ c = o.engineElapsedHistory,
+ d = n.timing.lastDelta,
+ p = u(r),
+ f = u(a),
+ v = u(l),
+ y = u(c),
+ m = u(s) / p || 0,
+ g = 1e3 / p || 0;
+ t.fillStyle = "#0e0f19", t.fillRect(0, 50, 370, 34), i.status(t, 10, 69, 60, 4, r.length, Math.round(g) + " fps", g / i._goodFps, (function(e) { return r[e] / p - 1 })), i.status(t, 82, 69, 60, 4, l.length, d.toFixed(2) + " dt", i._goodDelta / d, (function(e) { return l[e] / v - 1 })), i.status(t, 154, 69, 60, 4, c.length, y.toFixed(2) + " ut", 1 - y / i._goodFps, (function(e) { return c[e] / y - 1 })), i.status(t, 226, 69, 60, 4, a.length, f.toFixed(2) + " rt", 1 - f / i._goodFps, (function(e) { return a[e] / f - 1 })), i.status(t, 298, 69, 60, 4, s.length, m.toFixed(2) + " x", m * m * m, (function(e) { return (s[e] / r[e] / m || 0) - 1 })) }, i.status = function(e, t, n, i, r, a, s, l, c) { e.strokeStyle = "#888", e.fillStyle = "#444", e.lineWidth = 1, e.fillRect(t, n + 7, i, 1), e.beginPath(), e.moveTo(t, n + 7 - r * o.clamp(.4 * c(0), -2, 2)); for (var u = 0; u < i; u += 1) e.lineTo(t + u, n + 7 - (u < a ? r * o.clamp(.4 * c(u), -2, 2) : 0));
+ e.stroke(), e.fillStyle = "hsl(" + o.clamp(25 + 95 * l, 0, 120) + ",100%,60%)", e.fillRect(t, n - 7, 4, 4), e.font = "12px Arial", e.textBaseline = "middle", e.textAlign = "right", e.fillStyle = "#eee", e.fillText(s, t + i, n - 5) }, i.constraints = function(e, t) { for (var n = t, i = 0; i < e.length; i++) { var r = e[i]; if (r.render.visible && r.pointA && r.pointB) { var a, s, c = r.bodyA,
+ u = r.bodyB; if (a = c ? l.add(c.position, r.pointA) : r.pointA, "pin" === r.render.type) n.beginPath(), n.arc(a.x, a.y, 3, 0, 2 * Math.PI), n.closePath();
+ else { if (s = u ? l.add(u.position, r.pointB) : r.pointB, n.beginPath(), n.moveTo(a.x, a.y), "spring" === r.render.type)
+ for (var d, p = l.sub(s, a), f = l.perp(l.normalise(p)), v = Math.ceil(o.clamp(r.length / 5, 12, 20)), y = 1; y < v; y += 1) d = y % 2 == 0 ? 1 : -1, n.lineTo(a.x + p.x * (y / v) + f.x * d * 4, a.y + p.y * (y / v) + f.y * d * 4);
+ n.lineTo(s.x, s.y) } r.render.lineWidth && (n.lineWidth = r.render.lineWidth, n.strokeStyle = r.render.strokeStyle, n.stroke()), r.render.anchors && (n.fillStyle = r.render.strokeStyle, n.beginPath(), n.arc(a.x, a.y, 3, 0, 2 * Math.PI), n.arc(s.x, s.y, 3, 0, 2 * Math.PI), n.closePath(), n.fill()) } } }, i.bodies = function(e, t, n) { var i, o, r, a, s = n,
+ l = (e.engine, e.options),
+ c = l.showInternalEdges || !l.wireframes; for (r = 0; r < t.length; r++)
+ if ((i = t[r]).render.visible)
+ for (a = i.parts.length > 1 ? 1 : 0; a < i.parts.length; a++)
+ if ((o = i.parts[a]).render.visible) { if (l.showSleeping && i.isSleeping ? s.globalAlpha = .5 * o.render.opacity : 1 !== o.render.opacity && (s.globalAlpha = o.render.opacity), o.render.sprite && o.render.sprite.texture && !l.wireframes) { var u = o.render.sprite,
+ d = f(e, u.texture);
+ s.translate(o.position.x, o.position.y), s.rotate(o.angle), s.drawImage(d, d.width * -u.xOffset * u.xScale, d.height * -u.yOffset * u.yScale, d.width * u.xScale, d.height * u.yScale), s.rotate(-o.angle), s.translate(-o.position.x, -o.position.y) } else { if (o.circleRadius) s.beginPath(), s.arc(o.position.x, o.position.y, o.circleRadius, 0, 2 * Math.PI);
+ else { s.beginPath(), s.moveTo(o.vertices[0].x, o.vertices[0].y); for (var p = 1; p < o.vertices.length; p++) !o.vertices[p - 1].isInternal || c ? s.lineTo(o.vertices[p].x, o.vertices[p].y) : s.moveTo(o.vertices[p].x, o.vertices[p].y), o.vertices[p].isInternal && !c && s.moveTo(o.vertices[(p + 1) % o.vertices.length].x, o.vertices[(p + 1) % o.vertices.length].y);
+ s.lineTo(o.vertices[0].x, o.vertices[0].y), s.closePath() } l.wireframes ? (s.lineWidth = 1, s.strokeStyle = "#bbb", s.stroke()) : (s.fillStyle = o.render.fillStyle, o.render.lineWidth && (s.lineWidth = o.render.lineWidth, s.strokeStyle = o.render.strokeStyle, s.stroke()), s.fill()) } s.globalAlpha = 1 } }, i.bodyWireframes = function(e, t, n) { var i, o, r, a, s, l = n,
+ c = e.options.showInternalEdges; for (l.beginPath(), r = 0; r < t.length; r++)
+ if ((i = t[r]).render.visible)
+ for (s = i.parts.length > 1 ? 1 : 0; s < i.parts.length; s++) { for (o = i.parts[s], l.moveTo(o.vertices[0].x, o.vertices[0].y), a = 1; a < o.vertices.length; a++) !o.vertices[a - 1].isInternal || c ? l.lineTo(o.vertices[a].x, o.vertices[a].y) : l.moveTo(o.vertices[a].x, o.vertices[a].y), o.vertices[a].isInternal && !c && l.moveTo(o.vertices[(a + 1) % o.vertices.length].x, o.vertices[(a + 1) % o.vertices.length].y);
+ l.lineTo(o.vertices[0].x, o.vertices[0].y) } l.lineWidth = 1, l.strokeStyle = "#bbb", l.stroke() }, i.bodyConvexHulls = function(e, t, n) { var i, o, r, a = n; for (a.beginPath(), o = 0; o < t.length; o++)
+ if ((i = t[o]).render.visible && 1 !== i.parts.length) { for (a.moveTo(i.vertices[0].x, i.vertices[0].y), r = 1; r < i.vertices.length; r++) a.lineTo(i.vertices[r].x, i.vertices[r].y);
+ a.lineTo(i.vertices[0].x, i.vertices[0].y) } a.lineWidth = 1, a.strokeStyle = "rgba(255,255,255,0.2)", a.stroke() }, i.vertexNumbers = function(e, t, n) { var i, o, r, a = n; for (i = 0; i < t.length; i++) { var s = t[i].parts; for (r = s.length > 1 ? 1 : 0; r < s.length; r++) { var l = s[r]; for (o = 0; o < l.vertices.length; o++) a.fillStyle = "rgba(255,255,255,0.2)", a.fillText(i + "_" + o, l.position.x + .8 * (l.vertices[o].x - l.position.x), l.position.y + .8 * (l.vertices[o].y - l.position.y)) } } }, i.mousePosition = function(e, t, n) { var i = n;
+ i.fillStyle = "rgba(255,255,255,0.8)", i.fillText(t.position.x + " " + t.position.y, t.position.x + 5, t.position.y - 5) }, i.bodyBounds = function(e, t, n) { var i = n,
+ o = (e.engine, e.options);
+ i.beginPath(); for (var r = 0; r < t.length; r++) { if (t[r].render.visible)
+ for (var a = t[r].parts, s = a.length > 1 ? 1 : 0; s < a.length; s++) { var l = a[s];
+ i.rect(l.bounds.min.x, l.bounds.min.y, l.bounds.max.x - l.bounds.min.x, l.bounds.max.y - l.bounds.min.y) } } o.wireframes ? i.strokeStyle = "rgba(255,255,255,0.08)" : i.strokeStyle = "rgba(0,0,0,0.1)", i.lineWidth = 1, i.stroke() }, i.bodyAxes = function(e, t, n) { var i, o, r, a, s = n,
+ l = (e.engine, e.options); for (s.beginPath(), o = 0; o < t.length; o++) { var c = t[o],
+ u = c.parts; if (c.render.visible)
+ if (l.showAxes)
+ for (r = u.length > 1 ? 1 : 0; r < u.length; r++)
+ for (i = u[r], a = 0; a < i.axes.length; a++) { var d = i.axes[a];
+ s.moveTo(i.position.x, i.position.y), s.lineTo(i.position.x + 20 * d.x, i.position.y + 20 * d.y) } else
+ for (r = u.length > 1 ? 1 : 0; r < u.length; r++)
+ for (i = u[r], a = 0; a < i.axes.length; a++) s.moveTo(i.position.x, i.position.y), s.lineTo((i.vertices[0].x + i.vertices[i.vertices.length - 1].x) / 2, (i.vertices[0].y + i.vertices[i.vertices.length - 1].y) / 2) } l.wireframes ? (s.strokeStyle = "indianred", s.lineWidth = 1) : (s.strokeStyle = "rgba(255, 255, 255, 0.4)", s.globalCompositeOperation = "overlay", s.lineWidth = 2), s.stroke(), s.globalCompositeOperation = "source-over" }, i.bodyPositions = function(e, t, n) { var i, o, r, a, s = n,
+ l = (e.engine, e.options); for (s.beginPath(), r = 0; r < t.length; r++)
+ if ((i = t[r]).render.visible)
+ for (a = 0; a < i.parts.length; a++) o = i.parts[a], s.arc(o.position.x, o.position.y, 3, 0, 2 * Math.PI, !1), s.closePath(); for (l.wireframes ? s.fillStyle = "indianred" : s.fillStyle = "rgba(0,0,0,0.5)", s.fill(), s.beginPath(), r = 0; r < t.length; r++)(i = t[r]).render.visible && (s.arc(i.positionPrev.x, i.positionPrev.y, 2, 0, 2 * Math.PI, !1), s.closePath());
+ s.fillStyle = "rgba(255,165,0,0.8)", s.fill() }, i.bodyVelocity = function(e, t, n) { var i = n;
+ i.beginPath(); for (var o = 0; o < t.length; o++) { var r = t[o];
+ r.render.visible && (i.moveTo(r.position.x, r.position.y), i.lineTo(r.position.x + 2 * (r.position.x - r.positionPrev.x), r.position.y + 2 * (r.position.y - r.positionPrev.y))) } i.lineWidth = 3, i.strokeStyle = "cornflowerblue", i.stroke() }, i.bodyIds = function(e, t, n) { var i, o, r = n; for (i = 0; i < t.length; i++)
+ if (t[i].render.visible) { var a = t[i].parts; for (o = a.length > 1 ? 1 : 0; o < a.length; o++) { var s = a[o];
+ r.font = "12px Arial", r.fillStyle = "rgba(255,255,255,0.5)", r.fillText(s.id, s.position.x + 10, s.position.y - 10) } } }, i.collisions = function(e, t, n) { var i, o, r, a, s = n,
+ l = e.options; for (s.beginPath(), r = 0; r < t.length; r++)
+ if ((i = t[r]).isActive)
+ for (o = i.collision, a = 0; a < i.activeContacts.length; a++) { var c = i.activeContacts[a].vertex;
+ s.rect(c.x - 1.5, c.y - 1.5, 3.5, 3.5) }
+ for (l.wireframes ? s.fillStyle = "rgba(255,255,255,0.7)" : s.fillStyle = "orange", s.fill(), s.beginPath(), r = 0; r < t.length; r++)
+ if ((i = t[r]).isActive && (o = i.collision, i.activeContacts.length > 0)) { var u = i.activeContacts[0].vertex.x,
+ d = i.activeContacts[0].vertex.y;
+ 2 === i.activeContacts.length && (u = (i.activeContacts[0].vertex.x + i.activeContacts[1].vertex.x) / 2, d = (i.activeContacts[0].vertex.y + i.activeContacts[1].vertex.y) / 2), o.bodyB === o.supports[0].body || !0 === o.bodyA.isStatic ? s.moveTo(u - 8 * o.normal.x, d - 8 * o.normal.y) : s.moveTo(u + 8 * o.normal.x, d + 8 * o.normal.y), s.lineTo(u, d) } l.wireframes ? s.strokeStyle = "rgba(255,165,0,0.7)" : s.strokeStyle = "orange", s.lineWidth = 1, s.stroke() }, i.separations = function(e, t, n) { var i, o, r, a, s, l = n,
+ c = e.options; for (l.beginPath(), s = 0; s < t.length; s++)
+ if ((i = t[s]).isActive) { r = (o = i.collision).bodyA; var u = 1;
+ (a = o.bodyB).isStatic || r.isStatic || (u = .5), a.isStatic && (u = 0), l.moveTo(a.position.x, a.position.y), l.lineTo(a.position.x - o.penetration.x * u, a.position.y - o.penetration.y * u), u = 1, a.isStatic || r.isStatic || (u = .5), r.isStatic && (u = 0), l.moveTo(r.position.x, r.position.y), l.lineTo(r.position.x + o.penetration.x * u, r.position.y + o.penetration.y * u) } c.wireframes ? l.strokeStyle = "rgba(255,165,0,0.5)" : l.strokeStyle = "orange", l.stroke() }, i.inspector = function(e, t) { e.engine; var n, i = e.selected,
+ o = e.render,
+ r = o.options; if (r.hasBounds) { var a = o.bounds.max.x - o.bounds.min.x,
+ s = o.bounds.max.y - o.bounds.min.y,
+ l = a / o.options.width,
+ c = s / o.options.height;
+ t.scale(1 / l, 1 / c), t.translate(-o.bounds.min.x, -o.bounds.min.y) } for (var u = 0; u < i.length; u++) { var d = i[u].data; switch (t.translate(.5, .5), t.lineWidth = 1, t.strokeStyle = "rgba(255,165,0,0.9)", t.setLineDash([1, 2]), d.type) {
+ case "body":
+ n = d.bounds, t.beginPath(), t.rect(Math.floor(n.min.x - 3), Math.floor(n.min.y - 3), Math.floor(n.max.x - n.min.x + 6), Math.floor(n.max.y - n.min.y + 6)), t.closePath(), t.stroke(); break;
+ case "constraint":
+ var p = d.pointA;
+ d.bodyA && (p = d.pointB), t.beginPath(), t.arc(p.x, p.y, 10, 0, 2 * Math.PI), t.closePath(), t.stroke() } t.setLineDash([]), t.translate(-.5, -.5) } null !== e.selectStart && (t.translate(.5, .5), t.lineWidth = 1, t.strokeStyle = "rgba(255,165,0,0.6)", t.fillStyle = "rgba(255,165,0,0.1)", n = e.selectBounds, t.beginPath(), t.rect(Math.floor(n.min.x), Math.floor(n.min.y), Math.floor(n.max.x - n.min.x), Math.floor(n.max.y - n.min.y)), t.closePath(), t.stroke(), t.fill(), t.translate(-.5, -.5)), r.hasBounds && t.setTransform(1, 0, 0, 1, 0, 0) }; var n = function(e, t) { var n = e.engine,
+ o = e.timing,
+ r = o.historySize,
+ a = n.timing.timestamp;
+ o.delta = t - o.lastTime || i._goodDelta, o.lastTime = t, o.timestampElapsed = a - o.lastTimestamp || 0, o.lastTimestamp = a, o.deltaHistory.unshift(o.delta), o.deltaHistory.length = Math.min(o.deltaHistory.length, r), o.engineDeltaHistory.unshift(n.timing.lastDelta), o.engineDeltaHistory.length = Math.min(o.engineDeltaHistory.length, r), o.timestampElapsedHistory.unshift(o.timestampElapsed), o.timestampElapsedHistory.length = Math.min(o.timestampElapsedHistory.length, r), o.engineElapsedHistory.unshift(n.timing.lastElapsed), o.engineElapsedHistory.length = Math.min(o.engineElapsedHistory.length, r), o.elapsedHistory.unshift(o.lastElapsed), o.elapsedHistory.length = Math.min(o.elapsedHistory.length, r) },
+ u = function(e) { for (var t = 0, n = 0; n < e.length; n += 1) t += e[n]; return t / e.length || 0 },
+ d = function(e, t) { var n = document.createElement("canvas"); return n.width = e, n.height = t, n.oncontextmenu = function() { return !1 }, n.onselectstart = function() { return !1 }, n },
+ p = function(e) { var t = e.getContext("2d"); return (window.devicePixelRatio || 1) / (t.webkitBackingStorePixelRatio || t.mozBackingStorePixelRatio || t.msBackingStorePixelRatio || t.oBackingStorePixelRatio || t.backingStorePixelRatio || 1) },
+ f = function(e, t) { var n = e.textures[t]; return n || ((n = e.textures[t] = new Image).src = t, n) },
+ v = function(e, t) { var n = t; /(jpg|gif|png)$/.test(t) && (n = "url(" + t + ")"), e.canvas.style.background = n, e.canvas.style.backgroundSize = "contain", e.currentBackground = t } }() }, function(e, t) { var n = {};
+ e.exports = n, n.create = function(e) { return { vertex: e, normalImpulse: 0, tangentImpulse: 0 } } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(7),
+ r = n(19),
+ a = n(14),
+ s = n(20),
+ l = n(4),
+ c = n(5),
+ u = n(10),
+ d = n(0),
+ p = n(6);
+ i.create = function(e) { e = e || {}; var t = d.extend({ positionIterations: 6, velocityIterations: 4, constraintIterations: 2, enableSleeping: !1, events: [], plugin: {}, gravity: { x: 0, y: 1, scale: .001 }, timing: { timestamp: 0, timeScale: 1, lastDelta: 0, lastElapsed: 0 } }, e); return t.world = e.world || c.create({ label: "World" }), t.pairs = e.pairs || s.create(), t.detector = e.detector || a.create(), t.grid = { buckets: [] }, t.world.gravity = t.gravity, t.broadphase = t.grid, t.metrics = {}, t }, i.update = function(e, t, n) { var p = d.now();
+ t = t || 1e3 / 60, n = n || 1; var f, v = e.world,
+ y = e.detector,
+ m = e.pairs,
+ g = e.timing,
+ x = g.timestamp;
+ g.timestamp += t * g.timeScale, g.lastDelta = t * g.timeScale; var h = { timestamp: g.timestamp };
+ l.trigger(e, "beforeUpdate", h); var b = c.allBodies(v),
+ S = c.allConstraints(v); for (v.isModified && a.setBodies(y, b), v.isModified && c.setModified(v, !1, !1, !0), e.enableSleeping && o.update(b, g.timeScale), i._bodiesApplyGravity(b, e.gravity), i._bodiesUpdate(b, t, g.timeScale, n, v.bounds), u.preSolveAll(b), f = 0; f < e.constraintIterations; f++) u.solveAll(S, g.timeScale);
+ u.postSolveAll(b), y.pairs = e.pairs; var w = a.collisions(y); for (s.update(m, w, x), e.enableSleeping && o.afterCollisions(m.list, g.timeScale), m.collisionStart.length > 0 && l.trigger(e, "collisionStart", { pairs: m.collisionStart }), r.preSolvePosition(m.list), f = 0; f < e.positionIterations; f++) r.solvePosition(m.list, g.timeScale); for (r.postSolvePosition(b), u.preSolveAll(b), f = 0; f < e.constraintIterations; f++) u.solveAll(S, g.timeScale); for (u.postSolveAll(b), r.preSolveVelocity(m.list), f = 0; f < e.velocityIterations; f++) r.solveVelocity(m.list, g.timeScale); return m.collisionActive.length > 0 && l.trigger(e, "collisionActive", { pairs: m.collisionActive }), m.collisionEnd.length > 0 && l.trigger(e, "collisionEnd", { pairs: m.collisionEnd }), i._bodiesClearForces(b), l.trigger(e, "afterUpdate", h), e.timing.lastElapsed = d.now() - p, e }, i.merge = function(e, t) { if (d.extend(e, t), t.world) { e.world = t.world, i.clear(e); for (var n = c.allBodies(e.world), r = 0; r < n.length; r++) { var a = n[r];
+ o.set(a, !1), a.id = d.nextId() } } }, i.clear = function(e) { s.clear(e.pairs), a.clear(e.detector) }, i._bodiesClearForces = function(e) { for (var t = 0; t < e.length; t++) { var n = e[t];
+ n.force.x = 0, n.force.y = 0, n.torque = 0 } }, i._bodiesApplyGravity = function(e, t) { var n = void 0 !== t.scale ? t.scale : .001; if ((0 !== t.x || 0 !== t.y) && 0 !== n)
+ for (var i = 0; i < e.length; i++) { var o = e[i];
+ o.isStatic || o.isSleeping || (o.force.y += o.mass * t.y * n, o.force.x += o.mass * t.x * n) } }, i._bodiesUpdate = function(e, t, n, i, o) { for (var r = 0; r < e.length; r++) { var a = e[r];
+ a.isStatic || a.isSleeping || p.update(a, t, n, i) } } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(3),
+ r = n(1);
+ i._restingThresh = 4, i._restingThreshTangent = 6, i._positionDampen = .9, i._positionWarming = .8, i._frictionNormalMultiplier = 5, i.preSolvePosition = function(e) { var t, n, i, o = e.length; for (t = 0; t < o; t++)(n = e[t]).isActive && (i = n.activeContacts.length, n.collision.parentA.totalContacts += i, n.collision.parentB.totalContacts += i) }, i.solvePosition = function(e, t) { var n, o, r, a, s, l, c, u, d = i._positionDampen,
+ p = e.length; for (n = 0; n < p; n++)(o = e[n]).isActive && !o.isSensor && (a = (r = o.collision).parentA, s = r.parentB, l = r.normal, o.separation = l.x * (s.positionImpulse.x + r.penetration.x - a.positionImpulse.x) + l.y * (s.positionImpulse.y + r.penetration.y - a.positionImpulse.y)); for (n = 0; n < p; n++)(o = e[n]).isActive && !o.isSensor && (a = (r = o.collision).parentA, s = r.parentB, l = r.normal, u = (o.separation - o.slop) * t, (a.isStatic || s.isStatic) && (u *= 2), a.isStatic || a.isSleeping || (c = d / a.totalContacts, a.positionImpulse.x += l.x * u * c, a.positionImpulse.y += l.y * u * c), s.isStatic || s.isSleeping || (c = d / s.totalContacts, s.positionImpulse.x -= l.x * u * c, s.positionImpulse.y -= l.y * u * c)) }, i.postSolvePosition = function(e) { for (var t = i._positionWarming, n = e.length, a = o.translate, s = r.update, l = 0; l < n; l++) { var c = e[l],
+ u = c.positionImpulse,
+ d = u.x,
+ p = u.y,
+ f = c.velocity; if (c.totalContacts = 0, 0 !== d || 0 !== p) { for (var v = 0; v < c.parts.length; v++) { var y = c.parts[v];
+ a(y.vertices, u), s(y.bounds, y.vertices, f), y.position.x += d, y.position.y += p } c.positionPrev.x += d, c.positionPrev.y += p, d * f.x + p * f.y < 0 ? (u.x = 0, u.y = 0) : (u.x *= t, u.y *= t) } } }, i.preSolveVelocity = function(e) { var t, n, i = e.length; for (t = 0; t < i; t++) { var o = e[t]; if (o.isActive && !o.isSensor) { var r = o.activeContacts,
+ a = r.length,
+ s = o.collision,
+ l = s.parentA,
+ c = s.parentB,
+ u = s.normal,
+ d = s.tangent; for (n = 0; n < a; n++) { var p = r[n],
+ f = p.vertex,
+ v = p.normalImpulse,
+ y = p.tangentImpulse; if (0 !== v || 0 !== y) { var m = u.x * v + d.x * y,
+ g = u.y * v + d.y * y;
+ l.isStatic || l.isSleeping || (l.positionPrev.x += m * l.inverseMass, l.positionPrev.y += g * l.inverseMass, l.anglePrev += l.inverseInertia * ((f.x - l.position.x) * g - (f.y - l.position.y) * m)), c.isStatic || c.isSleeping || (c.positionPrev.x -= m * c.inverseMass, c.positionPrev.y -= g * c.inverseMass, c.anglePrev -= c.inverseInertia * ((f.x - c.position.x) * g - (f.y - c.position.y) * m)) } } } } }, i.solveVelocity = function(e, t) { var n, o, r, a, s = t * t,
+ l = i._restingThresh * s,
+ c = i._frictionNormalMultiplier,
+ u = i._restingThreshTangent * s,
+ d = Number.MAX_VALUE,
+ p = e.length; for (r = 0; r < p; r++) { var f = e[r]; if (f.isActive && !f.isSensor) { var v = f.collision,
+ y = v.parentA,
+ m = v.parentB,
+ g = y.velocity,
+ x = m.velocity,
+ h = v.normal.x,
+ b = v.normal.y,
+ S = v.tangent.x,
+ w = v.tangent.y,
+ A = f.activeContacts,
+ P = A.length,
+ C = 1 / P,
+ B = y.inverseMass + m.inverseMass,
+ M = f.friction * f.frictionStatic * c * s; for (g.x = y.position.x - y.positionPrev.x, g.y = y.position.y - y.positionPrev.y, x.x = m.position.x - m.positionPrev.x, x.y = m.position.y - m.positionPrev.y, y.angularVelocity = y.angle - y.anglePrev, m.angularVelocity = m.angle - m.anglePrev, a = 0; a < P; a++) { var k = A[a],
+ _ = k.vertex,
+ I = _.x - y.position.x,
+ T = _.y - y.position.y,
+ R = _.x - m.position.x,
+ E = _.y - m.position.y,
+ V = g.x - T * y.angularVelocity,
+ L = g.y + I * y.angularVelocity,
+ O = V - (x.x - E * m.angularVelocity),
+ D = L - (x.y + R * m.angularVelocity),
+ F = h * O + b * D,
+ H = S * O + w * D,
+ j = f.separation + F,
+ q = Math.min(j, 1),
+ W = (q = j < 0 ? 0 : q) * M;
+ H > W || -H > W ? (o = H > 0 ? H : -H, (n = f.friction * (H > 0 ? 1 : -1) * s) < -o ? n = -o : n > o && (n = o)) : (n = H, o = d); var G = I * b - T * h,
+ N = R * b - E * h,
+ U = C / (B + y.inverseInertia * G * G + m.inverseInertia * N * N),
+ z = (1 + f.restitution) * F * U; if (n *= U, F * F > l && F < 0) k.normalImpulse = 0;
+ else { var X = k.normalImpulse;
+ k.normalImpulse += z, k.normalImpulse = Math.min(k.normalImpulse, 0), z = k.normalImpulse - X } if (H * H > u) k.tangentImpulse = 0;
+ else { var Q = k.tangentImpulse;
+ k.tangentImpulse += n, k.tangentImpulse < -o && (k.tangentImpulse = -o), k.tangentImpulse > o && (k.tangentImpulse = o), n = k.tangentImpulse - Q } var Y = h * z + S * n,
+ Z = b * z + w * n;
+ y.isStatic || y.isSleeping || (y.positionPrev.x += Y * y.inverseMass, y.positionPrev.y += Z * y.inverseMass, y.anglePrev += (I * Z - T * Y) * y.inverseInertia), m.isStatic || m.isSleeping || (m.positionPrev.x -= Y * m.inverseMass, m.positionPrev.y -= Z * m.inverseMass, m.anglePrev -= (R * Z - E * Y) * m.inverseInertia) } } } } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(9),
+ r = n(0);
+ i.create = function(e) { return r.extend({ table: {}, list: [], collisionStart: [], collisionActive: [], collisionEnd: [] }, e) }, i.update = function(e, t, n) { var i, r, a, s, l, c, u = e.list,
+ d = u.length,
+ p = e.table,
+ f = t.length,
+ v = e.collisionStart,
+ y = e.collisionEnd,
+ m = e.collisionActive; for (v.length = 0, y.length = 0, m.length = 0, c = 0; c < d; c++) u[c].confirmedActive = !1; for (c = 0; c < f; c++)(l = (i = t[c]).pair) ? (l.isActive ? m.push(l) : v.push(l), o.update(l, i, n), l.confirmedActive = !0) : (p[(l = o.create(i, n)).id] = l, v.push(l), u.push(l)); var g = []; for (d = u.length, c = 0; c < d; c++)(l = u[c]).confirmedActive || (r = l.collision.bodyA, a = l.collision.bodyB, (!r.isSleeping && !r.isStatic || !a.isSleeping && !a.isStatic || r.isStatic && a.isStatic) && (o.setActive(l, !1, n), y.push(l), g.push(c))); for (c = 0; c < g.length; c++) l = u[s = g[c] - c], u.splice(s, 1), delete p[l.id] }, i.clear = function(e) { return e.table = {}, e.list.length = 0, e.collisionStart.length = 0, e.collisionActive.length = 0, e.collisionEnd.length = 0, e } }, function(e, t, n) { var i = e.exports = n(22);
+ i.Axes = n(11), i.Bodies = n(12), i.Body = n(6), i.Bounds = n(1), i.Collision = n(8), i.Common = n(0), i.Composite = n(5), i.Composites = n(23), i.Constraint = n(10), i.Contact = n(17), i.Detector = n(14), i.Engine = n(18), i.Events = n(4), i.Grid = n(24), i.Mouse = n(13), i.MouseConstraint = n(25), i.Pair = n(9), i.Pairs = n(20), i.Plugin = n(15), i.Query = n(26), i.Render = n(16), i.Resolver = n(19), i.Runner = n(27), i.SAT = n(28), i.Sleeping = n(7), i.Svg = n(29), i.Vector = n(2), i.Vertices = n(3), i.World = n(30), i.Engine.run = i.Runner.run, i.Common.deprecated(i.Engine, "run", "Engine.run ➤ use Matter.Runner.run(engine) instead") }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(15),
+ r = n(0);
+ i.name = "matter-js", i.version = "0.18.0-alpha+0eeceb5", i.uses = [], i.used = [], i.use = function() { o.use(i, Array.prototype.slice.call(arguments)) }, i.before = function(e, t) { return e = e.replace(/^Matter./, ""), r.chainPathBefore(i, e, t) }, i.after = function(e, t) { return e = e.replace(/^Matter./, ""), r.chainPathAfter(i, e, t) } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(5),
+ r = n(10),
+ a = n(0),
+ s = n(6),
+ l = n(12),
+ c = a.deprecated;
+ i.stack = function(e, t, n, i, r, a, l) { for (var c, u = o.create({ label: "Stack" }), d = e, p = t, f = 0, v = 0; v < i; v++) { for (var y = 0, m = 0; m < n; m++) { var g = l(d, p, m, v, c, f); if (g) { var x = g.bounds.max.y - g.bounds.min.y,
+ h = g.bounds.max.x - g.bounds.min.x;
+ x > y && (y = x), s.translate(g, { x: .5 * h, y: .5 * x }), d = g.bounds.max.x + r, o.addBody(u, g), c = g, f += 1 } else d += r } p += y + a, d = e } return u }, i.chain = function(e, t, n, i, s, l) { for (var c = e.bodies, u = 1; u < c.length; u++) { var d = c[u - 1],
+ p = c[u],
+ f = d.bounds.max.y - d.bounds.min.y,
+ v = d.bounds.max.x - d.bounds.min.x,
+ y = p.bounds.max.y - p.bounds.min.y,
+ m = { bodyA: d, pointA: { x: v * t, y: f * n }, bodyB: p, pointB: { x: (p.bounds.max.x - p.bounds.min.x) * i, y: y * s } },
+ g = a.extend(m, l);
+ o.addConstraint(e, r.create(g)) } return e.label += " Chain", e }, i.mesh = function(e, t, n, i, s) { var l, c, u, d, p, f = e.bodies; for (l = 0; l < n; l++) { for (c = 1; c < t; c++) u = f[c - 1 + l * t], d = f[c + l * t], o.addConstraint(e, r.create(a.extend({ bodyA: u, bodyB: d }, s))); if (l > 0)
+ for (c = 0; c < t; c++) u = f[c + (l - 1) * t], d = f[c + l * t], o.addConstraint(e, r.create(a.extend({ bodyA: u, bodyB: d }, s))), i && c > 0 && (p = f[c - 1 + (l - 1) * t], o.addConstraint(e, r.create(a.extend({ bodyA: p, bodyB: d }, s)))), i && c < t - 1 && (p = f[c + 1 + (l - 1) * t], o.addConstraint(e, r.create(a.extend({ bodyA: p, bodyB: d }, s)))) } return e.label += " Mesh", e }, i.pyramid = function(e, t, n, o, r, a, l) { return i.stack(e, t, n, o, r, a, (function(t, i, a, c, u, d) { var p = Math.min(o, Math.ceil(n / 2)),
+ f = u ? u.bounds.max.x - u.bounds.min.x : 0; if (!(c > p || a < (c = p - c) || a > n - 1 - c)) return 1 === d && s.translate(u, { x: (a + (n % 2 == 1 ? 1 : -1)) * f, y: 0 }), l(e + (u ? a * f : 0) + a * r, i, a, c, u, d) })) }, i.newtonsCradle = function(e, t, n, i, a) { for (var s = o.create({ label: "Newtons Cradle" }), c = 0; c < n; c++) { var u = l.circle(e + c * (1.9 * i), t + a, i, { inertia: 1 / 0, restitution: 1, friction: 0, frictionAir: 1e-4, slop: 1 }),
+ d = r.create({ pointA: { x: e + c * (1.9 * i), y: t }, bodyB: u });
+ o.addBody(s, u), o.addConstraint(s, d) } return s }, c(i, "newtonsCradle", "Composites.newtonsCradle ➤ moved to newtonsCradle example"), i.car = function(e, t, n, i, a) { var c = s.nextGroup(!0),
+ u = .5 * -n + 20,
+ d = .5 * n - 20,
+ p = o.create({ label: "Car" }),
+ f = l.rectangle(e, t, n, i, { collisionFilter: { group: c }, chamfer: { radius: .5 * i }, density: 2e-4 }),
+ v = l.circle(e + u, t + 0, a, { collisionFilter: { group: c }, friction: .8 }),
+ y = l.circle(e + d, t + 0, a, { collisionFilter: { group: c }, friction: .8 }),
+ m = r.create({ bodyB: f, pointB: { x: u, y: 0 }, bodyA: v, stiffness: 1, length: 0 }),
+ g = r.create({ bodyB: f, pointB: { x: d, y: 0 }, bodyA: y, stiffness: 1, length: 0 }); return o.addBody(p, f), o.addBody(p, v), o.addBody(p, y), o.addConstraint(p, m), o.addConstraint(p, g), p }, c(i, "car", "Composites.car ➤ moved to car example"), i.softBody = function(e, t, n, o, r, s, c, u, d, p) { d = a.extend({ inertia: 1 / 0 }, d), p = a.extend({ stiffness: .2, render: { type: "line", anchors: !1 } }, p); var f = i.stack(e, t, n, o, r, s, (function(e, t) { return l.circle(e, t, u, d) })); return i.mesh(f, n, o, c, p), f.label = "Soft Body", f }, c(i, "softBody", "Composites.softBody ➤ moved to softBody and cloth examples") }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(9),
+ r = n(0),
+ a = r.deprecated;
+ i.create = function(e) { return r.extend({ buckets: {}, pairs: {}, pairsList: [], bucketWidth: 48, bucketHeight: 48 }, e) }, i.update = function(e, t, n, o) { var r, a, s, l, c, u = n.world,
+ d = e.buckets,
+ p = !1; for (r = 0; r < t.length; r++) { var f = t[r]; if ((!f.isSleeping || o) && (!u.bounds || !(f.bounds.max.x < u.bounds.min.x || f.bounds.min.x > u.bounds.max.x || f.bounds.max.y < u.bounds.min.y || f.bounds.min.y > u.bounds.max.y))) { var v = i._getRegion(e, f); if (!f.region || v.id !== f.region.id || o) { f.region && !o || (f.region = v); var y = i._regionUnion(v, f.region); for (a = y.startCol; a <= y.endCol; a++)
+ for (s = y.startRow; s <= y.endRow; s++) { l = d[c = i._getBucketId(a, s)]; var m = a >= v.startCol && a <= v.endCol && s >= v.startRow && s <= v.endRow,
+ g = a >= f.region.startCol && a <= f.region.endCol && s >= f.region.startRow && s <= f.region.endRow;!m && g && g && l && i._bucketRemoveBody(e, l, f), (f.region === v || m && !g || o) && (l || (l = i._createBucket(d, c)), i._bucketAddBody(e, l, f)) } f.region = v, p = !0 } } } p && (e.pairsList = i._createActivePairsList(e)) }, a(i, "update", "Grid.update ➤ replaced by Matter.Detector"), i.clear = function(e) { e.buckets = {}, e.pairs = {}, e.pairsList = [] }, a(i, "clear", "Grid.clear ➤ replaced by Matter.Detector"), i._regionUnion = function(e, t) { var n = Math.min(e.startCol, t.startCol),
+ o = Math.max(e.endCol, t.endCol),
+ r = Math.min(e.startRow, t.startRow),
+ a = Math.max(e.endRow, t.endRow); return i._createRegion(n, o, r, a) }, i._getRegion = function(e, t) { var n = t.bounds,
+ o = Math.floor(n.min.x / e.bucketWidth),
+ r = Math.floor(n.max.x / e.bucketWidth),
+ a = Math.floor(n.min.y / e.bucketHeight),
+ s = Math.floor(n.max.y / e.bucketHeight); return i._createRegion(o, r, a, s) }, i._createRegion = function(e, t, n, i) { return { id: e + "," + t + "," + n + "," + i, startCol: e, endCol: t, startRow: n, endRow: i } }, i._getBucketId = function(e, t) { return "C" + e + "R" + t }, i._createBucket = function(e, t) { return e[t] = [] }, i._bucketAddBody = function(e, t, n) { var i, r = e.pairs,
+ a = o.id,
+ s = t.length; for (i = 0; i < s; i++) { var l = t[i]; if (!(n.id === l.id || n.isStatic && l.isStatic)) { var c = a(n, l),
+ u = r[c];
+ u ? u[2] += 1 : r[c] = [n, l, 1] } } t.push(n) }, i._bucketRemoveBody = function(e, t, n) { var i, a = e.pairs,
+ s = o.id;
+ t.splice(r.indexOf(t, n), 1); var l = t.length; for (i = 0; i < l; i++) { var c = a[s(n, t[i])];
+ c && (c[2] -= 1) } }, i._createActivePairsList = function(e) { var t, n, i = e.pairs,
+ o = r.keys(i),
+ a = o.length,
+ s = []; for (n = 0; n < a; n++)(t = i[o[n]])[2] > 0 ? s.push(t) : delete i[o[n]]; return s } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(3),
+ r = n(7),
+ a = n(13),
+ s = n(4),
+ l = n(14),
+ c = n(10),
+ u = n(5),
+ d = n(0),
+ p = n(1);
+ i.create = function(e, t) { var n = (e ? e.mouse : null) || (t ? t.mouse : null);
+ n || (e && e.render && e.render.canvas ? n = a.create(e.render.canvas) : t && t.element ? n = a.create(t.element) : (n = a.create(), d.warn("MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected"))); var o = { type: "mouseConstraint", mouse: n, element: null, body: null, constraint: c.create({ label: "Mouse Constraint", pointA: n.position, pointB: { x: 0, y: 0 }, length: .01, stiffness: .1, angularStiffness: 1, render: { strokeStyle: "#90EE90", lineWidth: 3 } }), collisionFilter: { category: 1, mask: 4294967295, group: 0 } },
+ r = d.extend(o, t); return s.on(e, "beforeUpdate", (function() { var t = u.allBodies(e.world);
+ i.update(r, t), i._triggerEvents(r) })), r }, i.update = function(e, t) { var n = e.mouse,
+ i = e.constraint,
+ a = e.body; if (0 === n.button) { if (i.bodyB) r.set(i.bodyB, !1), i.pointA = n.position;
+ else
+ for (var c = 0; c < t.length; c++)
+ if (a = t[c], p.contains(a.bounds, n.position) && l.canCollide(a.collisionFilter, e.collisionFilter))
+ for (var u = a.parts.length > 1 ? 1 : 0; u < a.parts.length; u++) { var d = a.parts[u]; if (o.contains(d.vertices, n.position)) { i.pointA = n.position, i.bodyB = e.body = a, i.pointB = { x: n.position.x - a.position.x, y: n.position.y - a.position.y }, i.angleB = a.angle, r.set(a, !1), s.trigger(e, "startdrag", { mouse: n, body: a }); break } } } else i.bodyB = e.body = null, i.pointB = null, a && s.trigger(e, "enddrag", { mouse: n, body: a }) }, i._triggerEvents = function(e) { var t = e.mouse,
+ n = t.sourceEvents;
+ n.mousemove && s.trigger(e, "mousemove", { mouse: t }), n.mousedown && s.trigger(e, "mousedown", { mouse: t }), n.mouseup && s.trigger(e, "mouseup", { mouse: t }), a.clearSourceEvents(t) } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(2),
+ r = n(8),
+ a = n(1),
+ s = n(12),
+ l = n(3);
+ i.collides = function(e, t) { for (var n = [], i = t.length, o = e.bounds, s = r.collides, l = a.overlaps, c = 0; c < i; c++) { var u = t[c],
+ d = u.parts.length,
+ p = 1 === d ? 0 : 1; if (l(u.bounds, o))
+ for (var f = p; f < d; f++) { var v = u.parts[f]; if (l(v.bounds, o)) { var y = s(v, e); if (y) { n.push(y); break } } } } return n }, i.ray = function(e, t, n, r) { r = r || 1e-100; for (var a = o.angle(t, n), l = o.magnitude(o.sub(t, n)), c = .5 * (n.x + t.x), u = .5 * (n.y + t.y), d = s.rectangle(c, u, l, r, { angle: a }), p = i.collides(d, e), f = 0; f < p.length; f += 1) { var v = p[f];
+ v.body = v.bodyB = v.bodyA } return p }, i.region = function(e, t, n) { for (var i = [], o = 0; o < e.length; o++) { var r = e[o],
+ s = a.overlaps(r.bounds, t);
+ (s && !n || !s && n) && i.push(r) } return i }, i.point = function(e, t) { for (var n = [], i = 0; i < e.length; i++) { var o = e[i]; if (a.contains(o.bounds, t))
+ for (var r = 1 === o.parts.length ? 0 : 1; r < o.parts.length; r++) { var s = o.parts[r]; if (a.contains(s.bounds, t) && l.contains(s.vertices, t)) { n.push(o); break } } } return n } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(4),
+ r = n(18),
+ a = n(0);! function() { var e, t, n;
+ ("undefined" != typeof window && (e = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame, t = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame), e) || (e = function(e) { n = setTimeout((function() { e(a.now()) }), 1e3 / 60) }, t = function() { clearTimeout(n) });
+ i.create = function(e) { var t = a.extend({ fps: 60, correction: 1, deltaSampleSize: 60, counterTimestamp: 0, frameCounter: 0, deltaHistory: [], timePrev: null, timeScalePrev: 1, frameRequestId: null, isFixed: !1, enabled: !0 }, e); return t.delta = t.delta || 1e3 / t.fps, t.deltaMin = t.deltaMin || 1e3 / t.fps, t.deltaMax = t.deltaMax || 1e3 / (.5 * t.fps), t.fps = 1e3 / t.delta, t }, i.run = function(t, n) { return void 0 !== t.positionIterations && (n = t, t = i.create()),
+ function o(r) { t.frameRequestId = e(o), r && t.enabled && i.tick(t, n, r) }(), t }, i.tick = function(e, t, n) { var i, a = t.timing,
+ s = 1,
+ l = { timestamp: a.timestamp };
+ o.trigger(e, "beforeTick", l), e.isFixed ? i = e.delta : (i = n - e.timePrev || e.delta, e.timePrev = n, e.deltaHistory.push(i), e.deltaHistory = e.deltaHistory.slice(-e.deltaSampleSize), s = (i = (i = (i = Math.min.apply(null, e.deltaHistory)) < e.deltaMin ? e.deltaMin : i) > e.deltaMax ? e.deltaMax : i) / e.delta, e.delta = i), 0 !== e.timeScalePrev && (s *= a.timeScale / e.timeScalePrev), 0 === a.timeScale && (s = 0), e.timeScalePrev = a.timeScale, e.correction = s, e.frameCounter += 1, n - e.counterTimestamp >= 1e3 && (e.fps = e.frameCounter * ((n - e.counterTimestamp) / 1e3), e.counterTimestamp = n, e.frameCounter = 0), o.trigger(e, "tick", l), o.trigger(e, "beforeUpdate", l), r.update(t, i, s), o.trigger(e, "afterUpdate", l), o.trigger(e, "afterTick", l) }, i.stop = function(e) { t(e.frameRequestId) }, i.start = function(e, t) { i.run(e, t) } }() }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(8),
+ r = n(0).deprecated;
+ i.collides = function(e, t) { return o.collides(e, t) }, r(i, "collides", "SAT.collides ➤ replaced by Collision.collides") }, function(e, t, n) { var i = {};
+ e.exports = i;
+ n(1); var o = n(0);
+ i.pathToVertices = function(e, t) { "undefined" == typeof window || "SVGPathSeg" in window || o.warn("Svg.pathToVertices: SVGPathSeg not defined, a polyfill is required."); var n, r, a, s, l, c, u, d, p, f, v, y = [],
+ m = 0,
+ g = 0,
+ x = 0;
+ t = t || 15; var h = function(e, t, n) { var i = n % 2 == 1 && n > 1; if (!p || e != p.x || t != p.y) { p && i ? (f = p.x, v = p.y) : (f = 0, v = 0); var o = { x: f + e, y: v + t };!i && p || (p = o), y.push(o), g = f + e, x = v + t } },
+ b = function(e) { var t = e.pathSegTypeAsLetter.toUpperCase(); if ("Z" !== t) { switch (t) {
+ case "M":
+ case "L":
+ case "T":
+ case "C":
+ case "S":
+ case "Q":
+ g = e.x, x = e.y; break;
+ case "H":
+ g = e.x; break;
+ case "V":
+ x = e.y } h(g, x, e.pathSegType) } }; for (i._svgPathToAbsolute(e), a = e.getTotalLength(), c = [], n = 0; n < e.pathSegList.numberOfItems; n += 1) c.push(e.pathSegList.getItem(n)); for (u = c.concat(); m < a;) { if ((l = c[e.getPathSegAtLength(m)]) != d) { for (; u.length && u[0] != l;) b(u.shift());
+ d = l } switch (l.pathSegTypeAsLetter.toUpperCase()) {
+ case "C":
+ case "T":
+ case "S":
+ case "Q":
+ case "A":
+ s = e.getPointAtLength(m), h(s.x, s.y, 0) } m += t } for (n = 0, r = u.length; n < r; ++n) b(u[n]); return y }, i._svgPathToAbsolute = function(e) { for (var t, n, i, o, r, a, s = e.pathSegList, l = 0, c = 0, u = s.numberOfItems, d = 0; d < u; ++d) { var p = s.getItem(d),
+ f = p.pathSegTypeAsLetter; if (/[MLHVCSQTA]/.test(f)) "x" in p && (l = p.x), "y" in p && (c = p.y);
+ else switch ("x1" in p && (i = l + p.x1), "x2" in p && (r = l + p.x2), "y1" in p && (o = c + p.y1), "y2" in p && (a = c + p.y2), "x" in p && (l += p.x), "y" in p && (c += p.y), f) {
+ case "m":
+ s.replaceItem(e.createSVGPathSegMovetoAbs(l, c), d); break;
+ case "l":
+ s.replaceItem(e.createSVGPathSegLinetoAbs(l, c), d); break;
+ case "h":
+ s.replaceItem(e.createSVGPathSegLinetoHorizontalAbs(l), d); break;
+ case "v":
+ s.replaceItem(e.createSVGPathSegLinetoVerticalAbs(c), d); break;
+ case "c":
+ s.replaceItem(e.createSVGPathSegCurvetoCubicAbs(l, c, i, o, r, a), d); break;
+ case "s":
+ s.replaceItem(e.createSVGPathSegCurvetoCubicSmoothAbs(l, c, r, a), d); break;
+ case "q":
+ s.replaceItem(e.createSVGPathSegCurvetoQuadraticAbs(l, c, i, o), d); break;
+ case "t":
+ s.replaceItem(e.createSVGPathSegCurvetoQuadraticSmoothAbs(l, c), d); break;
+ case "a":
+ s.replaceItem(e.createSVGPathSegArcAbs(l, c, p.r1, p.r2, p.angle, p.largeArcFlag, p.sweepFlag), d); break;
+ case "z":
+ case "Z":
+ l = t, c = n }
+ "M" != f && "m" != f || (t = l, n = c) } } }, function(e, t, n) { var i = {};
+ e.exports = i; var o = n(5);
+ n(0);
+ i.create = o.create, i.add = o.add, i.remove = o.remove, i.clear = o.clear, i.addComposite = o.addComposite, i.addBody = o.addBody, i.addConstraint = o.addConstraint }]) }));
\ No newline at end of file
diff --git a/ngon/style.css b/ngon/style.css
new file mode 100644
index 00000000..3971c413
--- /dev/null
+++ b/ngon/style.css
@@ -0,0 +1,1379 @@
+:root {
+ --build-bg-color: #aeb6c2;
+ --card-color: #fafcfd;
+ --hover-card-color: #e5e5ed;
+}
+
+body {
+ font-family: "Helvetica", "Arial", sans-serif;
+ margin: 0;
+ overflow: hidden;
+ cursor: auto;
+ /* transition: background-color 0.2s ease-in-out; */
+}
+
+canvas {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 0;
+ user-select: none;
+}
+
+select {
+ font-size: 0.8em;
+ border: 1px #333 solid;
+ border-radius: 6px;
+}
+
+select option {
+ background-color: #fff;
+}
+
+input {
+ padding: 0px 4px;
+ font-size: 0.8em;
+ border: 1px #333 solid;
+ border-radius: 4px;
+}
+
+a {
+ text-decoration: none;
+ color: #08c;
+}
+
+em {
+ opacity: 0.7;
+}
+
+#splash {
+ user-select: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 2;
+ transition: opacity 5s ease-in;
+}
+
+*:focus {
+ outline: none;
+}
+
+table {
+ border-collapse: collapse;
+ width: 360px;
+}
+
+tr {
+ padding: 10px;
+ text-align: left;
+}
+
+td {
+ padding-left: 10px;
+}
+
+.key-input-train {
+ padding: 0px 5px;
+ border: 2px solid #444;
+ color: #444;
+ border-radius: 4px;
+ background-color: #d0d0d0;
+ text-align: center;
+ font-weight: 400;
+}
+
+.key-input {
+ padding: 3px 8px;
+ border: 2px solid #333;
+ background-color: #fff;
+ text-align: center;
+}
+
+.pause-table {
+ width: auto;
+}
+
+.key-input-pause {
+ width: 15px;
+ padding: 0px 2px;
+ border: 2px solid #333;
+ background-color: #fff;
+ text-align: center;
+}
+
+.key-used {
+ color: #777;
+ font-size: 80%;
+}
+
+summary {
+ font-size: 1.2em;
+}
+
+.SVG-button {
+ border: 1.5px #333 solid;
+ border-radius: 8px;
+ background-color: #fff;
+}
+
+.SVG-button:hover {
+ background-color: #eee;
+}
+
+#experiment-button {
+ position: absolute;
+ bottom: 4px;
+ right: 4px;
+ z-index: 12;
+ transition: opacity 5s ease-in;
+}
+
+#training-button {
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ z-index: 12;
+ transition: opacity 5s ease-in;
+}
+
+#construct {
+ display: none;
+ position: absolute;
+ bottom: 0%;
+ right: 0%;
+ z-index: 1;
+ width: 250px;
+ height: 200px;
+ background-color: #fff;
+ color: #000;
+ font-size: 0.9em;
+ white-space: pre;
+ padding: 3px;
+ border: 1px #333 solid;
+}
+
+#flex-center {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+}
+
+.choose-grid {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ padding: 10px 1px;
+ margin: 0px;
+ border: 0px;
+ z-index: 12;
+ max-height: 99vh;
+ font-size: 1.3em;
+ display: grid;
+ grid-template-columns: repeat(3, 384px);
+ align-items: stretch;
+ visibility: hidden;
+ opacity: 0;
+ transition: opacity 0.25s linear;
+ overflow: auto;
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+}
+
+
+
+
+.choose-grid-no-images {
+ border-radius: 8px;
+ border: 10px solid #444;
+ gap: 10px;
+ background-color: #444;
+ /* padding: 10px 1px; */
+
+
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ margin: 0px;
+ z-index: 12;
+ max-height: 99vh;
+ font-size: 1.3em;
+ display: grid;
+ grid-template-columns: 384px;
+ align-items: stretch;
+ visibility: hidden;
+ opacity: 0;
+ transition: opacity 0.25s linear;
+ overflow: auto;
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+}
+
+
+#choose-grid::-webkit-scrollbar {
+ display: none;
+}
+
+.choose-grid-module {
+ line-height: 160%;
+ background-color: var(--card-color);
+ font-size: 0.75em;
+ /* transform-style: preserve-3d;
+ transition: transform 2s;
+ transform: rotateX(180deg); */
+}
+
+.choose-grid-module:hover {
+ background-color: var(--hover-card-color);
+}
+
+.choose-grid-module:hover .card-text {
+ background-color: var(--hover-card-color);
+}
+
+.research-select {
+ float: right;
+ margin-right: 10px;
+}
+
+.pause-grid {
+ padding: 2px;
+ margin: 0px;
+ display: none;
+ grid-template-columns: 384px;
+ grid-auto-rows: minmax(auto, auto);
+ align-content: start;
+ align-items: start;
+ z-index: 2;
+ font-size: 1.3em;
+}
+
+#pause-grid-right {
+ position: absolute;
+ top: -2px;
+ right: -4px;
+ overflow: auto;
+ max-height: 100vh;
+ -ms-overflow-style: none;
+ /* IE and Edge */
+ scrollbar-width: none;
+ /* Firefox */
+ padding: 1px;
+}
+
+#pause-grid-right::-webkit-scrollbar {
+ display: none;
+}
+
+#pause-grid-left {
+ position: absolute;
+ top: -2px;
+ left: -4px;
+ overflow: auto;
+ max-height: 100vh;
+ -ms-overflow-style: none;
+ /* IE and Edge */
+ scrollbar-width: none;
+ /* Firefox */
+}
+
+.pause-console {
+ padding: 10px;
+ margin: 5px;
+ border-radius: 10px;
+}
+
+#pause-grid-left::-webkit-scrollbar {
+ display: none;
+}
+
+.pause-grid-module {
+ line-height: 160%;
+ background-color: var(--card-color);
+ font-size: 0.75em;
+}
+
+.sort {
+ padding: 0.1em 0.3em;
+ border: 1px solid #444;
+ /* min-height: 88px; */
+ line-height: 100%;
+ background-color: #fff;
+}
+
+.sort-button {
+ border: 1px #333 solid;
+ border-radius: 0.5em;
+ background-color: #fff;
+ font-size: 0.5em;
+ /* padding: 0.3em; */
+
+}
+
+.sort-button:hover {
+ background-color: #eee;
+}
+
+.pause-eject .card-text {
+ animation: techColorCycle 1s linear infinite alternate;
+}
+
+#experiment-grid {
+ display: flex;
+ justify-content: center;
+ padding: 0px;
+ margin: 0px;
+ border: 0px;
+ background-color: var(--build-bg-color);
+ display: none;
+ grid-template-columns: repeat(auto-fit, 384px);
+ grid-auto-flow: row;
+ /* grid-auto-rows: minmax(auto, auto); */
+ position: relative;
+ /* bottom: 0px; */
+ z-index: 10;
+ font-size: 1.3em;
+ -ms-overflow-style: none;
+ /* IE and Edge */
+ scrollbar-width: none;
+ /* Firefox */
+}
+
+#experiment-grid::-webkit-scrollbar {
+ display: none;
+}
+
+.experiment-grid-module {
+ line-height: 160%;
+ background-color: var(--card-color);
+ font-size: 0.75em;
+}
+
+.experiment-grid-hide {
+ display: none;
+}
+
+.grid-title {
+ padding-bottom: 6px;
+ padding-top: 4px;
+ font-size: 1.4em;
+ font-weight: 600;
+}
+
+.experiment-grid-module:hover:not(.build-tech-selected, .build-field-selected, .build-gun-selected) {
+ background-color: var(--card-color);
+}
+
+.experiment-start-box {
+ background-color: var(--card-color);
+ /* font-size: 1em; */
+ position: sticky;
+ top: 0;
+ z-index: 10;
+ align-self: start;
+ width: 276px;
+ line-height: 200%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ border: 2px #333 solid;
+ border-top: 0px;
+ border-radius: 10px;
+ border-top-left-radius: 0px;
+ /* border-bottom-left-radius: 0px; */
+ border-top-right-radius: 0px;
+ padding: 0.2em 0px;
+ /* height: 210px; */
+ box-shadow: 8px 8px 7px rgba(0, 0, 50, 0.15);
+}
+
+.card-background {
+ height: 340px;
+ background-size: contain;
+ background-repeat: no-repeat;
+ display: flex;
+ justify-content: flex-end;
+ flex-direction: column;
+}
+
+.card-text {
+ background-color: rgba(255, 255, 255, 1);
+ padding: 0.5em 1em;
+ border: 1px solid #444;
+ margin-top: -1px;
+ margin-right: -1px;
+ font-size: 0.92em;
+ min-height: 88px;
+ /* border-radius: 5px; */
+}
+
+.cancel-card {
+ text-align: center;
+ font-size: 1.1em;
+ font-weight: 100;
+ justify-self: end;
+ border: 1px solid #444;
+ margin-top: -1px;
+ margin-right: -1px;
+ padding: 1px;
+ line-height: 160%;
+ background-color: var(--card-color);
+}
+
+.cancel-card:hover {
+ background-color: var(--hover-card-color);
+}
+
+.research-card {
+ font-size: 1.1em;
+ font-weight: 100;
+ border: 1px solid #444;
+ margin-top: -1px;
+ margin-right: -1px;
+ padding: 1px 0px 1px 10px;
+ line-height: 160%;
+ background-color: var(--card-color);
+}
+
+.research-card:hover {
+ background-color: var(--hover-card-color);
+}
+
+.research-cancel {
+ display: flex;
+ gap: 10px;
+ line-height: 160%;
+ /* background-color: var(--card-color); */
+ font-size: 1em;
+}
+
+/* keeps 5 columns at 1440px */
+@media (min-width: 1710px) and (max-width: 1950px) {
+
+ .experiment-grid-module,
+ .choose-grid-module,
+ .pause-grid-module,
+ .research-cancel {
+ line-height: 143%;
+ font-size: 0.68em;
+ }
+
+ .research-cancel {
+ font-size: 0.9em;
+ }
+
+ #experiment-grid,
+ .choose-grid,
+ .pause-grid {
+ grid-template-columns: repeat(auto-fit, 340px);
+ }
+
+ .card-background {
+ height: 290px;
+ }
+
+ .card-text {
+ min-height: 75px;
+ }
+}
+
+/* (min-width: 30em) and (max-width: 80em) */
+@media (max-width: 1709px) {
+
+ .experiment-grid-module,
+ .choose-grid-module,
+ .pause-grid-module {
+ line-height: 139%;
+ font-size: 0.58em;
+ }
+
+ .research-cancel {
+ font-size: 0.8em;
+ }
+
+ #experiment-grid,
+ .choose-grid,
+ .pause-grid {
+ grid-template-columns: repeat(auto-fit, 285px);
+ }
+
+ .card-background {
+ height: 240px;
+ }
+
+ .card-text {
+ min-height: 64px;
+ }
+}
+
+/* .card-text */
+.choose-grid-no-images .card-text,
+.choose-grid-no-images .research-card,
+.choose-grid-no-images .cancel-card {
+ border-radius: 5px;
+}
+
+/* keeps 4 columns at 1440px */
+/* @media (1500px <= width < 1950px) {
+ .experiment-grid-module, .choose-grid-module, .pause-grid-module {
+ line-height: 150%;
+ font-size: 0.72em;
+ }
+ #experiment-grid, #choose-grid, .pause-grid{
+ grid-template-columns: repeat(auto-fit, 360px);
+ }
+ .card-background{
+ height:315px;
+ }
+ .card-text {
+ min-height: 82px;
+ }
+}
+@media (width < 1500px) {
+ .experiment-grid-module, .choose-grid-module, .pause-grid-module {
+ line-height: 143%;
+ font-size: 0.68em;
+ }
+ #experiment-grid, #choose-grid, .pause-grid{
+ grid-template-columns: repeat(auto-fit, 340px);
+ }
+ .card-background{
+ height:290px;
+ }
+ .card-text {
+ min-height: 75px;
+ }
+} */
+
+.experiment-grid-module:hover .card-text {
+ background-color: var(--hover-card-color);
+}
+
+.build-tech-selected .card-text {
+ background-color: hsl(253, 100%, 84%);
+}
+
+.build-tech-selected.experiment-grid-module:hover .card-text {
+ background-color: hsl(253, 100%, 81%);
+}
+
+.build-gun-selected .card-text {
+ background-color: hsl(218, 100%, 81%);
+}
+
+.build-gun-selected.experiment-grid-module:hover .card-text {
+ background-color: hsl(218, 100%, 76%);
+}
+
+.build-field-selected .card-text {
+ background-color: hsl(193, 100%, 75%);
+}
+
+.build-field-selected.experiment-grid-module:hover .card-text {
+ background-color: hsl(193, 100%, 68%);
+}
+
+.experiment-grid-disabled {
+ /* background-color: var(--build-bg-color); */
+ /* color: #000; */
+ opacity: 0.35;
+}
+
+.experiment-grid-disabled[data-descr] {
+ position: relative;
+}
+
+.experiment-grid-disabled[data-descr]:hover::after {
+ content: '\a \00a0 \00a0 \00a0 REQUIRES:\a \00a0 \00a0 \00a0 ' attr(data-descr);
+ white-space: pre-wrap;
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: var(--build-bg-color);
+ z-index: 1;
+ opacity: 1;
+ transition: opacity 0.5s ease;
+}
+
+#info {
+ position: absolute;
+ bottom: 3px;
+ left: 3px;
+ z-index: 12;
+ font-size: 1.5em;
+ transition: opacity 5s ease-in;
+}
+
+.details-div {
+ padding: 10px;
+ border-radius: 8px;
+ border: 2px #333 solid;
+ background-color: #fff;
+}
+
+#dmg {
+ position: absolute;
+ z-index: 2;
+ width: 100%;
+ height: 100%;
+ display: none;
+ /* background-color also set in mass-energy tech */
+ background-color: #f67;
+ opacity: 0;
+ transition: opacity 1s;
+}
+
+#damage-bar {
+ position: absolute;
+ /* top: 1px;
+ left: 15px;
+ height: 7px;
+ width: 0px;
+ transition: width 0.3s linear; */
+ top: 16px;
+ right: 4px;
+ height: 0px;
+ width: 7px;
+ transition: height 0.25s linear;
+ opacity: 1;
+ z-index: 2;
+ pointer-events: none;
+ background-color: rgb(255, 55, 95);
+ /* border-bottom: 1.5px solid #701; */
+ /* border-right: 1.5px solid #701; */
+ display: none;
+}
+
+#defense-bar {
+ position: absolute;
+ top: 8px;
+ left: 15px;
+ height: 7px;
+ width: 0px;
+ transition: width 0.25s linear;
+ opacity: 1;
+ z-index: 2;
+ pointer-events: none;
+ background-color: #fff;
+ border-right: 1.5px solid #777;
+ display: none;
+}
+
+#health {
+ position: absolute;
+ top: 15px;
+ left: 15px;
+ height: 20px;
+ width: 0px;
+ transition: width 1s ease-out;
+ z-index: 2;
+ pointer-events: none;
+ background-color: rgb(9, 245, 166);
+ border-right: 2px solid rgb(51, 162, 125);
+ display: none;
+}
+
+#health-bg {
+ position: absolute;
+ top: 15px;
+ left: 15px;
+ height: 20px;
+ width: 0px;
+ transition: width 1s ease-out;
+ background-color: #032;
+ opacity: 0.1;
+ z-index: 1;
+ pointer-events: none;
+ display: none;
+}
+
+/* #damage-bar {
+ position: absolute;
+ top: 0px;
+ left: 15px;
+ height: 6px;
+ width: 0px;
+ transition: width 0.3s linear;
+ opacity: 1;
+ z-index: 2;
+ pointer-events: none;
+ background-color: #f03;
+ border: 1px solid #701;
+ display: none;
+}
+
+#defense-bar {
+ position: absolute;
+ top: 9px;
+ left: 15px;
+ height: 5px;
+ width: 0px;
+ transition: width 0.3s linear;
+ opacity: 1;
+ z-index: 2;
+ pointer-events: none;
+ background-color: #fff;
+ border: 1px solid #333;
+ display: none;
+}
+#health {
+ position: absolute;
+ top: 16px;
+ left: 15px;
+ height: 20px;
+ width: 0px;
+ transition: width 1s ease-out; z-index: 2;
+ pointer-events: none;
+ background-color: #0fa;
+ border: 2px solid rgb(51, 162, 125);
+ border-radius: 8px;
+ display: none;
+}
+#health-bg {
+ position: absolute;
+ top: 18px;
+ left: 15px;
+ height: 20px;
+ width: 0px;
+ transition: width 1s ease-out;
+ background-color: #000;
+ opacity: 0.1;
+ z-index: 1;
+ pointer-events: none;
+ border-radius: 8px;
+ display: none;
+} */
+
+/* .low-health {
+ animation: blink 250ms infinite alternate;
+}
+
+@keyframes blink {
+ from {
+ opacity: 1;
+ }
+
+ to {
+ opacity: 0.6;
+ }
+} */
+
+/* background on title page */
+#fade-out {
+ position: absolute;
+ z-index: 2;
+ width: 100%;
+ height: 100%;
+ background-color: #e2e9ec;
+ opacity: 1;
+ transition: opacity 3s;
+ pointer-events: none;
+}
+
+#guns {
+ position: absolute;
+ top: 82px;
+ left: 15px;
+ z-index: 2;
+ font-size: 23px;
+ color: #222;
+ /* background-color: rgba(255, 255, 255, 0.4); */
+ background-color: rgba(255, 255, 255, 0.2);
+ line-height: 120%;
+ user-select: none;
+ pointer-events: none;
+ padding: 0px 5px 0px 5px;
+ border-radius: 5px;
+ /*border: 2px solid rgba(0, 0, 0, 0.4);*/
+}
+
+#field {
+ position: absolute;
+ top: 45px;
+ left: 15px;
+ z-index: 2;
+ font-size: 23px;
+ color: #000;
+ text-align: right;
+ opacity: 0.7;
+ /* line-height: 140%; */
+ background-color: rgba(190, 210, 245, 0.25);
+ user-select: none;
+ pointer-events: none;
+ padding: 0px 5px 0px 5px;
+ border-radius: 5px;
+ /*border: 2px solid rgba(0, 0, 0, 0.4);*/
+}
+
+#tech {
+ position: absolute;
+ top: 15px;
+ right: 15px;
+ z-index: 2;
+ font-size: 20px;
+ color: #222;
+ text-align: right;
+ opacity: 0.35;
+ line-height: 120%;
+ background-color: rgba(255, 255, 255, 0.4);
+ user-select: none;
+ pointer-events: none;
+ padding: 0px 5px 0px 5px;
+ border-radius: 5px;
+ /*border: 2px solid rgba(0, 0, 0, 0.4);*/
+}
+
+#text-log {
+ z-index: 2;
+ position: absolute;
+ bottom: 10px;
+ left: 10px;
+ padding: 10px;
+ border-radius: 4px;
+ line-height: 140%;
+ font-size: 1.15em;
+ color: #555;
+ background-color: rgba(255, 255, 255, 0.5);
+ /* transition: opacity 0.15s; */
+ pointer-events: none;
+ user-select: none;
+}
+
+/* color for in game console output */
+/* .ammo-flash {
+ color: #f33;
+ transition: color 2s;
+} */
+
+
+.color-text {
+ color: #000;
+}
+
+.color-var {
+ color: hsl(253, 100%, 58%);
+}
+
+.color-symbol {
+ color: hsl(290, 100%, 40%);
+}
+
+.color-gun {
+ color: hsl(218, 100%, 58%);
+}
+
+.highlight {
+ border-radius: 6px;
+ background-color: #ff0;
+ padding: 3px;
+}
+
+.color-f {
+ color: #0ad;
+ letter-spacing: 1px;
+}
+
+.color-s {
+ color: #04f;
+ letter-spacing: 1px;
+}
+
+.color-d {
+ color: #f03;
+ letter-spacing: 1px;
+}
+
+.color-p {
+ color: #067;
+ letter-spacing: 1px;
+}
+
+.color-h {
+ color: #0b7;
+ letter-spacing: 1px;
+}
+
+.color-e {
+ color: #d60;
+ letter-spacing: 1px;
+}
+
+.color-m {
+ color: hsl(253, 100%, 50%);
+ letter-spacing: 1px;
+}
+
+.color-g {
+ color: hsl(218, 80%, 40%);
+ letter-spacing: 1px;
+}
+
+.color-ammo {
+ color: #356;
+}
+
+.color-dup {
+ font-variant: small-caps;
+ letter-spacing: 1px;
+ text-shadow: 1.5px -1.5px hsla(243, 100%, 38%, 0.2);
+}
+
+.color-cloaked {
+ letter-spacing: 2px;
+ animation: cloak 6s linear infinite alternate;
+ color: rgba(0, 0, 0, 0);
+}
+
+@keyframes cloak {
+ 0% {
+ text-shadow: 0px 0px 0px #000;
+ opacity: 1;
+ }
+
+ 50% {
+ text-shadow: 0px 0px 0px #000;
+ opacity: 1;
+ }
+
+ 100% {
+ text-shadow: 0px 0px 15px #000;
+ opacity: 0;
+ }
+}
+
+.color-laser {
+ color: #f02;
+ font-weight: 100;
+ letter-spacing: -0.8px;
+}
+
+.color-plasma {
+ color: #c0e;
+ letter-spacing: 1px;
+ background-color: rgba(132, 0, 255, 0.06);
+ padding: 2px;
+ border-radius: 9px;
+ letter-spacing: 1px;
+}
+
+.color-worm {
+ color: #fff;
+ text-shadow: 1px 0px 2px #234;
+}
+
+.color-defense {
+ background-color: hsla(227, 9%, 71%, 0.279);
+ padding: 2px;
+ border-radius: 4px;
+ letter-spacing: 1px;
+ font-weight: 100;
+}
+
+.color-block {
+ background-color: rgba(0, 0, 0, 0.04);
+ border: 1px solid rgba(0, 0, 0, 0.5);
+ padding: 0.5px;
+ font-weight: 100;
+}
+
+.color-cancel {
+ background-color: var(--card-color);
+ border: 0.15em #444 solid;
+ padding: 0.2em;
+ border-radius: 0.2em;
+ font-weight: 800;
+ font-size: 1em;
+}
+
+.color-junk {
+ letter-spacing: 1px;
+ font-family: Lucida Console, Courier, monospace;
+}
+
+.color-r {
+ color: #f7b;
+ letter-spacing: 1px;
+}
+
+.color-flop {
+ text-decoration: underline;
+ font-weight: 100;
+ letter-spacing: -1px;
+}
+
+.color-alt {
+ text-decoration: underline;
+ font-weight: 100;
+ letter-spacing: -1px;
+}
+
+.faded {
+ opacity: 0.7;
+ font-size: 90%;
+}
+
+.circle-grid {
+ width: 1.35em;
+ height: 1.35em;
+ border-radius: 50%;
+ display: inline-block;
+ margin-bottom: -0.3em;
+}
+
+.circle-grid-skin {
+ width: 1.25em;
+ height: 1.25em;
+ border-radius: 50%;
+ display: inline-block;
+ background-color: #fff;
+ opacity: 0.8;
+ border: 0.08em solid #222;
+ position: absolute;
+ top: -0.05em;
+ left: 0em;
+ margin-bottom: -0.3em;
+}
+
+.circle-grid-skin-eye {
+ width: 0.18em;
+ height: 0.18em;
+ border-radius: 50%;
+ display: inline-block;
+ background-color: #fff;
+ border: 0.08em solid #222;
+ position: absolute;
+ top: 0.45em;
+ left: 0.9em;
+ margin-bottom: -0.3em;
+}
+
+.junk {
+ background-color: hsl(254, 44%, 75%);
+ border-radius: 25%;
+}
+
+.research-circle {
+ width: 0.9em;
+ height: 0.9em;
+ border-radius: 50%;
+ display: inline-block;
+ background-color: #f7b;
+ border: 0.065em #fff solid;
+ opacity: 0.85;
+ margin-bottom: -0.1em;
+}
+
+.ammo-circle {
+ width: 0.75em;
+ height: 0.75em;
+ border-radius: 50%;
+ display: inline-block;
+ background-color: #467;
+ border: 0.05em #fff solid;
+ opacity: 0.95;
+ margin-bottom: -1.5px;
+}
+
+.heal-circle {
+ width: 0.95em;
+ height: 0.95em;
+ border-radius: 50%;
+ display: inline-block;
+ background-color: #0d9;
+ border: 0.05em #fff solid;
+ opacity: 0.85;
+ margin-bottom: -3px;
+}
+
+.heal-circle-energy {
+ width: 0.95em;
+ height: 0.95em;
+ border-radius: 50%;
+ display: inline-block;
+ background-color: #ff0;
+ border: 0.05em #000 solid;
+ opacity: 0.85;
+ margin-bottom: -3px;
+}
+
+.coupling-circle {
+ width: 0.7em;
+ height: 0.7em;
+ border-radius: 50%;
+ display: inline-block;
+ background-color: #0ae;
+ border: 0.05em #fff solid;
+ margin-bottom: -0.5px;
+}
+
+.boost-circle {
+ width: 0.7em;
+ height: 0.7em;
+ border-radius: 50%;
+ display: inline-block;
+ background-color: #f03;
+ border: 0.05em #fff solid;
+ opacity: 0.9;
+ margin-bottom: -0.5px;
+}
+
+@keyframes pulse {
+ 0% {
+ border-radius: 0%;
+ }
+
+ 100% {
+ border-radius: 50%;
+ }
+}
+
+.field {
+ background-color: #0cf;
+}
+
+.tech {
+ background-color: hsl(255, 100%, 71%);
+}
+
+.gun {
+ background-color: rgb(0, 80, 218);
+}
+
+.heal {
+ background-color: #0d9;
+}
+
+.research {
+ background-color: #f7b;
+}
+
+.alt {
+ animation: alt 8s linear infinite alternate;
+ font-weight: 400;
+ letter-spacing: 1px;
+}
+
+@keyframes alt {
+ 0% {
+ text-shadow: 3px 0px 0px;
+ }
+
+ 100% {
+ text-shadow: -3px 0px 0px;
+ }
+
+}
+
+.flicker {
+ animation: flicker 4s linear infinite;
+}
+
+@keyframes flicker {
+ 0% {
+ opacity: 1;
+ }
+
+ 80% {
+ opacity: 1;
+ }
+
+ 90% {
+ opacity: 0;
+ }
+
+ 100% {
+ opacity: 1;
+ }
+}
+
+.color-coupling {
+ text-shadow: 0px 0px 1.5px #0cf;
+ letter-spacing: 1px;
+ font-weight: 100;
+}
+
+.box {
+ padding: 3px 8px 3px 8px;
+ border: 2px solid #444;
+ border-radius: 4px;
+ background-color: rgba(255, 255, 255, 0.5);
+}
+
+.wrapper {
+ display: grid;
+ grid-template-columns: 360px 10px;
+ align-self: center;
+ justify-content: center;
+}
+
+.grid-box {
+ align-self: center;
+ justify-self: center;
+}
+
+.right {
+ text-align: right;
+}
+
+.lore {
+ animation: bgColor 3.5s linear infinite;
+}
+
+.lore-text {
+ animation: textColor 3s linear infinite;
+}
+
+.entanglement {
+ font-size: 1.1em;
+ font-weight: 100;
+ text-align: center;
+ letter-spacing: 10px;
+ border: none;
+ background-color: var(--card-color);
+}
+
+.flipX {
+ animation: 14s anim-flipX linear infinite;
+}
+
+@keyframes anim-flipX {
+ 0% {
+ transform: rotateX(0.5turn);
+ }
+
+ 50% {
+ transform: rotateX(1turn);
+ }
+
+ 100% {
+ transform: rotateX(0.5turn);
+ }
+}
+
+@keyframes fieldColorCycle {
+ 0% {
+ background-color: rgb(255, 255, 255)
+ }
+
+ 100% {
+ background-color: rgb(200, 255, 255)
+ }
+}
+
+@keyframes techColorCycle {
+ 0% {
+ background-color: hsl(253, 100%, 100%)
+ }
+
+ 100% {
+ background-color: hsl(253, 100%, 90%)
+ }
+}
+
+@keyframes bgColor {
+ 0% {
+ background-color: rgb(63, 218, 216)
+ }
+
+ 10% {
+ background-color: rgb(47, 201, 226)
+ }
+
+ 20% {
+ background-color: rgb(28, 127, 238)
+ }
+
+ 30% {
+ background-color: rgb(95, 21, 242)
+ }
+
+ 40% {
+ background-color: rgb(186, 12, 248)
+ }
+
+ 50% {
+ background-color: rgb(251, 7, 217)
+ }
+
+ 60% {
+ background-color: rgba(255, 0, 0)
+ }
+
+ 70% {
+ background-color: rgb(255, 0, 0)
+ }
+
+ 80% {
+ background-color: rgb(255, 154, 0)
+ }
+
+ 90% {
+ background-color: rgb(208, 222, 33)
+ }
+
+ 100% {
+ background-color: rgb(79, 220, 74)
+ }
+}
+
+@keyframes textColor {
+ 0% {
+ color: rgb(63, 218, 216)
+ }
+
+ 10% {
+ color: rgb(47, 201, 226)
+ }
+
+ 20% {
+ color: rgb(28, 127, 238)
+ }
+
+ 30% {
+ color: rgb(95, 21, 242)
+ }
+
+ 40% {
+ color: rgb(186, 12, 248)
+ }
+
+ 50% {
+ color: rgb(251, 7, 217)
+ }
+
+ 60% {
+ color: rgba(255, 0, 0)
+ }
+
+ 70% {
+ color: rgb(255, 0, 0)
+ }
+
+ 80% {
+ color: rgb(255, 154, 0)
+ }
+
+ 90% {
+ color: rgb(208, 222, 33)
+ }
+
+ 100% {
+ color: rgb(79, 220, 74)
+ }
+}
+
+.link {
+ color: #000;
+}
+
+.link:hover {
+ text-decoration: underline;
+}
\ No newline at end of file
diff --git a/ngon/todo.txt b/ngon/todo.txt
new file mode 100644
index 00000000..19f18e7f
--- /dev/null
+++ b/ngon/todo.txt
@@ -0,0 +1,1183 @@
+******************************************************** NEXT PATCH **************************************************
+
+on later levels spawn 2 bosses, but 1 power up each
+ starts at simulation.difficulty > 23 //on hard mode level 6, level 12 on easy, level 4 on why?
+ makes combat harder, but also means that you will always get at least 2 drops per level
+ you used to have a chance to only get 1 near the end of the game
+ I'm guessing this will lead to about 3 more total tech by the final boss
+ abiogenesis - removed
+ parthenogenesis - doesn't duplicate bosses anymore, +8% duplication
+
+
+*********************************************************** TODO *****************************************************
+
+more (all) bosses need to be made of parts
+ good examples: spiderBoss, dragonFlyBoss, beetleBoss
+ methods:
+ spawn adds in phases, like beetle and tether
+ constraints, like spider
+ be nice if each constrained part does something different
+ constrained mobs that regen after phases
+ flock, like cellBoss, blockBoss
+ Bosses that could be converted to more parts
+ "orbitalBoss", "shooterBoss", "bomberBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "pulsarBoss", "grenadierBoss", "blinkBoss", "laserBombingBoss", "blockBoss", "revolutionBoss", "slashBoss", "timeSkipBoss", "sneakBoss"
+ "sneakBoss" could get sneaker adds after each hide phase
+ "laserTargetingBoss" could have close range stabbers constrained, a few long range shooters, and a few laser shooters
+
+defense power up - a short term defense boost, like the ones for damage.
+ Or maybe it would last until you take one hit.
+ Or last until you lost a total of 20 health.
+
+use cross product rotation for other mobs?
+ snipers, shooters?
+ //gently rotate towards the player with a torque, use cross product to decided clockwise or counterclockwise
+ const laserStartVector = Vector.sub(this.position, this.vertices[this.swordVertex])
+ const playerVector = Vector.sub(this.position, m.pos)
+ const cross = Matter.Vector.cross(laserStartVector, playerVector)
+ this.torque = 0.00002 * this.inertia * (cross > 0 ? 1 : -1)
+
+super-bot: fires super balls
+
+tech - only allow 1,2 turrets at time. spawning a new mine removes the oldest mine
+ turrets never run out of ammo
+ or turrets automatically use one of your mine ammos when they run out?
+ good with multi gun builds
+ conflict with booby trap?
+
+tech: after a needle hits a mobs
+ the needle splits into 3 needles?
+ reset your fire CD?
+ 2x damage for each consecutive mob hit?
+
+mob non-combat behaviors, like Rain World
+ gathering
+ blocks
+ eating blocks to heal?
+ power ups
+ eating power ups and ejecting them on death
+ flocking
+ grouping near mobs
+ keeping distance from mobs
+ sharing velocity with other mobs: boids
+ wander
+ random walk with a bias towards the player
+ play
+ fight other mobs
+
+consider increasing the base player horizontal movement
+ maybe only increase ground movement, air control seems fine
+ would this unbalance any maps?
+
+tech stubs should be a tech unlocked by skins
+ nitinol, tungsten?
+ maybe give another benefit?
+ defense?
+ make a shared variable for skin defense, since you can only have one skin
+
+make a lemming that walks until it hits a wall and then turns around robotically
+ body or mob?
+ can't be killed?
+
+use ephemera to replace some bad code
+ JUNK?
+ request animation stuff
+ simulation checks
+ damage and defense bars
+ disable and enable ephemera with settings
+
+perfect diamagnatism - invulnerable while field is active?
+ also drain energy while field is active?
+
+mobs attack mines
+ mines periodically set all mobs to have player location to be the mine
+ is this going to work with all mob vision types?
+
+tech circular polarization - wave gun bullets move in a circle
+
+Tech: relativity
+ Simulation speed scales with movement speed. When still, time moves at 0.4 speed, at full walking speed it’s 1. (So if you’re falling or something and you move faster the simulation will be faster than usual)
+ Also a damage and/or defense boost to make it worth using
+
+wormhole tech - teleport away mobs with mass below 3 when they get too near the player
+ short CD, small energy cost, only mobs below a mass
+
+extend brainstorming animation timers to fps cap?
+ will it be smoother or choppier?
+ anything else needs to hit limited fps on a high fps monitor?
+
+perfect diamagnatism could bounce on mobs, or even map elements?
+ could work like a rocket jump?
+
+tech: Bose Einstein condensate - freezes enemies in pilot wave, and drains some energy?
+
+make super balls with Zectron deflectable with field
+ but is there a simple way to do this?
+
+set mob health bar colors based on status effects?
+ make mob damage immunity a mob status effect?
+
+tech: rail gun area damage effect, but for all harpoon mode
+
+mob status effect - vulnerability
+ mobs take 4x damage for __ time
+ afterwards mobs go back to normal damage taken
+ graphical effect while they take extra damage
+ needs to come from a "rare"ish effect
+ merge with the decloaking damage effect
+ decloaking gives all mobs (nearby??) a 3x damage taken status?
+ this can be merged with the stun crit damage tech
+ also the increased damage every hit tech?
+ bad idea because the graphical effect will be too annoying
+
+tech: sporangium that grow little trees
+ the trees have an area of effect damage for about 6-10 seconds
+ maybe something similar to radioactive drones, but maybe a few smaller shapes
+
+hookBoss fires a hook that pulls player towards it
+ hook does a bit of damage
+ player targeted unless cloaking
+ also add effect to finalBoss
+
+finalBoss
+ add synergies between modes:
+ new modes:
+ something that needs to be killed quickly
+ if you don't kill it boss gets a shield
+ rotating quadrant immunity shield, can't take damage from that quadrant
+ maybe also attack player near that quadrant
+ but how to tell the angle of incoming damage
+ maybe a physics body like the shield but it only covers 1/3 of mob?
+ falling object warps to ceiling after hitting floor
+ doesn't end, player needs to kill it
+ slowly grows?
+ slow effect zones
+ random placement or place over player or both!
+ draw white dot and an outline of area of effect
+ expanding circle stroke, freeze effect triggers when stroke circle hits fill circle
+ after 1-2 seconds freeze player if in the zone
+ also freeze mobs
+ effect that makes player have to be close to boss
+ hook that tries to yank the player into hitting finalBoss
+ does damage
+ pulls player into center
+ counter with wormhole, negative mass
+ player targeted unless cloaking
+
+
+mob status effect - emit - mobs fire lasers for a few seconds
+ tech: phosphorescence - mobs emit after being hit with laser beams
+
+Tech: "Solid rocket motor": Missiles would start at 300% speed and 200% missile damage upon explosion, but the speed and damage would decrease to 40% speed and damage as time goes on
+tech: every time shotgun fires it's a different shotgun mode: nails, ice, needles, worms, fleas, rivets, ... but you get more ammo
+
+for tech power ups no tech options are displayed until you research once
+ or display only JUNK until you research once
+ increase the number of options after each research
+
+When receiving damage, in addition to becoming invulnerable to attacks, also become intangible for the set period of time
+
+tech increase max energy and energy to 5000, but you can no longer regen energy through any process
+
+it would be nice if there was incentive to go slow when choosing tech so n-gon is more relaxing
+ add some css based visual effects for opening up a tech,gun,field
+
+make a new coupling effect for perfect diamagnetism or standing wave
+
+make a faster smaller version of cell boss that also has map collisions
+
+laserMines need a copy of laser-bot method
+ this is a very rare bug, so not a priority
+
+JUNK tech description that changes similar to cards in inscription
+ that changes based on mouse position
+ can you tell if mouse is over card?
+
+tech - buff MACHO range, effect, move speed?
+while you are inside MACHO it will damage mobs?
+
+PWA?
+ https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps
+ https://codeburst.io/how-to-easily-turn-your-static-website-to-a-progressive-web-app-pwa-b0af08da9693
+ https://github.com/landgreen/n-gon/pull/32/files
+
+bug blocks and power ups falling through map
+ always foam gun (4-5 times)
+ might be about tech pressure vessel
+ happens rarely, doesn't repeat
+ only occurs for 3 people so far
+ normally after level 6
+ occurred once on the first level, didn't fire gun and was able to walk through a body
+
+Tech:when relay switch/flip flop is on, turn ammo powerups into boosts, when relay swicth/flip flop is off, ammo powerups remain ammo powerups
+ or toggle other power ups
+ health/ammo
+
+JUNK: what the golf?
+ trying to throw a block throws you instead
+
+tech for lens - you can only fire through the lens
+ and some buff? damage or energy?
+
+complete blowSuckBoss... or don't
+
+tech: laser reflections increase damage
+
+JUNK tech different effects based on night or day
+ use system time
+
+Boss that shoots out a ring of bullets, then after a few seconds it gravitates the bullets back
+
+coupling
+ put coupling description as 4th line on field description
+ raw text no function call
+ no need for coupling description in power ups, pause
+ negative coupling?
+ wouldn't work for iceIX
+coupling tech
+ names: strongly coupled, Vibronic coupling, NMR coupling
+ tech: +x% field coupling, your field changes randomly every y seconds
+ tech: coupling starts at 200%, but decays when the field is in use, coupling recharges when the field is not in use
+ some fields aren't used much (that's ok?)
+
+tech give laser mines more lasers (3->4? 5?)
+
+rewindBoss: after hitting 1/5 damage thresholds the boss rewinds back in time to where it was a few seconds ago
+ track it's data like player history
+
+make orbitals increase orbital rotation speed after Orbital boss takes damage
+
+worms can target player, buff their damage
+ can't target player in first few seconds?
+
+plasma field tech - similar to regression, but for plasma ticks
+
+greatly increase walking speed
+ not mid air control?
+ for time dilation field
+ make jumping normal
+
+junk tech: charged shot
+immediately fire all of your ammo
+
+after taking damage explode while invulnerable
+ scale explosion radius with damage
+
+quantum immortality: send you to a new tab after you die with a random load out
+ basically everything is the same as it is now, but you switch tabs
+
+Tech: Tech/guns/fields can no longer be duplicated. Duplication applies twice
+
+tech: get sent to a new tab that closes in 3 minutes
+ in the new tab you play reactor
+ if you die in reactor you die in game, if you win you get 2-3 tech in the original game?
+ give player equipment like many-worlds
+ count guns, field, tech and give random stuff on new tab
+ i-frame instead of tab?
+
+reduce the amount of research and nerf anti randomization tech
+ increase possible synergies that go nuts
+
+tech expansion: field coupling also expands each fields in different ways
+ how to make the description work
+ change description based on your current field?
+ perfect diamagnetism moves forward when you hold down the shield
+ it's great, but maybe annoying?
+ maybe only with crouch?
+ perfect diamagnetism just replace or increase Messier effect
+ time dilation drains 1/2 as much energy when paused
+ grow plasma torch as you hold it down
+ negative mass effects much more space
+ needs more benefit?
+ reduces the cloaking vision effect?
+ needs more benefit?
+
+tech: missiles explode a 2nd time after 1/2 a second (with a slightly different position determined by original velocity)
+
+The tech that makes blocks that fall into a wormhole give energy should scale with block size, with the same formula as tokomak
+
+junk suggestion: useless machine - ejects itself and removes itself from the item pool
+
+
+
+seed isn't working right from shared URL
+
+mob mechanics
+ bullets hit player and stay attached for 4-5 seconds, slowing player
+ hopperBullets?
+ black hole sucker effect on tail
+ vines
+ attached to map and grows, a series of spheres connected by vines
+ if node dies it's removed from tree
+ vine do
+ keeps track of connection tree
+ nested object with nesting to show connection
+ spawns new nodes
+ draws connections as quad lines
+
+tech: You can place an extra perfect diamagnatism field on the map
+
+standing wave no longer pushes mobs away, but it can do damage to mobs caught in area effect
+ Standing wave harmonics no longer deflects, but instead discharges excess energy as lightning toward nearby enemies
+negative mass field does damage to mobs inside field
+ combine with standing wave effect? pilot wave?
+
+store value of last hit health lost
+ tech: killing the mob that caused the last hit spawns a heal power up equal to 1/2 of last hit
+ time limit for effect?
+ need to also store who hit player
+
+add small SVG pics to in-game console
+ when?
+ one for each field?
+ use stuff on physics notes:
+simulation.makeTextLog(`
+
+
+
+
+
+
+
+
+
+
+`);
+
+path-finding
+ build a path-finding map on level load
+ how to convert vertices into block grid?
+ check points for map collisions and build grid
+ is there a path-finding algorithm for vertices, instead of block grid
+ use for:
+ mobs,
+ drones?
+ bots that can go far from player and return
+
+make plasma ball power up and block pick up still work when you have no no energy
+ make a unique CD var for plasma ball?
+
+tech: entropic gravity - gain defense for each research
+ requires wormhole or pilot wave or negative mass field?
+
+mitosis: after needle,bullets or rivets hit a surface split off into two smaller less damaging versions that have their velocity reset -firerate
+
+after killing a mob go invulnerable for 1 second
+ critical hit with laser, harpoon, nails, needle, rivet
+
+spawn 2 bots after exiting 1 level
+ or spawn 3 after 2 levels?
+ (randomize 2-5 bots)
+ replace all bot tech with this?
+
+cloaking field
+ for 6 seconds after de-cloaking tell all active mobs that the player is in the wrong position?
+ how to code?
+ just delay setting the m.isCloak for a couple seconds
+ and also set all active bots to remember player in the de-cloaked stop
+
+scrap bots can't move?
+ only works for nail, foam, laser
+ might be tricky code?
+ make a new bot type called scrap bot?
+
+JUNK tech: Pacifism
+ You cannot attack mobs, mobs cannot attack you
+ over write the mob.damage and player.damage methods
+
+mob mechanic: beacon
+ periodically add locations to an array
+ teleport back to a location in the array
+ at random
+ if velocity not facing player?
+
+super balls do more damage after bouncing?
+ how to check for bounce?
+ maybe just increases damage after hitting a mob
+
+super short range foam that acts like flame thrower
+ high fire rate
+ short life spawn
+ start large?
+ extra ammo?
+ or only 1/2 of ammo is used?
+
+laser tech where bots move around and follow you while firing lasers in the direction you are looking
+ they fire when you fire?
+ they aim at player history aim location, with 1s delay
+ bots position spread out perpendicular to the direction you are looking
+ can they get stuck?
+ maybe absolution position, no collide
+ do they need to be physics objects then?
+ make a special bot type for this
+ beam is similar to diffuse beam
+
+
+
+
+double research
+
+map ban option in settings
+ dropdown list with checkboxes by each map
+
+bullets that can target the player
+ occurs if no mobs targets around
+ worms? drones? missiles? spores?
+ all of the above?
+
+Currently, the mob just deals higher damage on impact, which is annoying although not hard to compete with nor unique
+By "redesign" I mean replacing instances of the regular mob, since the same code is used for the tiny red projectiles (I think) just add a new mob and remove the old one from the rotation
+The new mob should be as such, a "real" exploding mob:
+Deals regular damage on impact, but breaks apart on touch into several red dots (like the ones thrown out by the going through walls boss) and a chance for also throwing a bomb or two (increases with difficulty)
+If the mob is close to the player or heading into the player fast it will shatter as well (and the projectiles will inherit its speed)
+By a formula such as
+ShouldShatter(distToPlayer, speed) = distToPlayer * speed > threshold
+Optionally (and a part I can do as I'm good at it and it doesn't revolve around a lot of functional code which you don't like other people doing):
+Color changing based on the mob explosion status
+Regular state: red
+About to explode: animation to dark red
+Exploding: several shockwaves from the explosion points and tiny trails given to the shrapnel for a second or two until they deaccelerate
+
+pause time like invariant for other things...
+ throwing blocks
+ charging railgun
+ charging anything?
+
+guntech fire a bullet that fires nail fragments after 1s in the same direction as the original bullet
+ like overwatch roadhog
+
+bring back:
+ the old phase decoherence field
+ make cloak only active on input.field down
+ could be a tech
+ would need some other buff
+ how to make it good enough
+ combine with not killing tech?
+ stun mobs that touch you while phased
+ firing doesn't exit you from cloak
+ but it does drain some energy
+ tech pilot wave: Bose Einstein condensate - freeze mobs in superposition with pilot wave
+
+tech: plasma drip
+
+plasma ball
+ graphics should look more like a real plasma ball
+ gently scale damage with circleRadius
+ balance corona discharge
+ delay on returning to player is annoying
+ scale float effect with ball size
+ tech upgrades
+ greatly improve floating effects while holding
+ black hole: gives the plasma ball gravity
+ stun on expansion
+ plasma orb increases in size and power as it eats enemies
+ while attached?
+
+flashlight effect
+ make level.do() graphic that only shows direction player is facing
+ pattern it after cloaking field, or timeSkipBoss
+ will it work with cloaking field at the same time
+
+double jump?
+
+tech: coyote time
+ you can still jump for 2 seconds after falling off a ledge
+ make it a JUNK tech? so you can keep the name
+ some other benefit
+ reduce your gravity also?
+ increase jump?
+
+tech smoke grenades - mobs inside a cloud can't see player
+ draw on the region so it's hard for player to see as well
+ you'd have to make something similar to MACHO that exists after an explosion goes off
+ maybe just keep it simple:
+ stun mobs for a long time, and draw a 99& alpha grey circle for the same time
+ don't worry about mobs seeing you inside the circle, the circle is kinda small so it doesn't matter
+
+
+tech mines: mines fire _____ instead of nails
+ needles
+ super balls?
+ foam?
+
+tech: frozen mobs die at 10% life
+
+tech: harpoons stick into enemies
+ detonate after a short delay
+ attaches mob to wall if possible
+ firing while harpoon is stuck into an enemy rips it out of them, inflicting damage and stun and pulling them towards you
+
+
+
+enemies stuck with foam receive upward force over time
+ only form aerogel tech?
+
+Tech: superglue
+Requires: foam + another gun or plasma torch or molecular assembler
+ Foam bubbles decay 50% slower
+ Enemies stuck with foam cannot move
+ Foam does 0 damage
+ Enemies stuck with foam take 25% more damage
+ should foam bots gets this also or is that too strong
+
+const ctx = canvas.getContext('2d', {‘willReadFrequently': true});
+
+//deal with game crashes?
+canvas.addEventListener("contextlost", onContextLost);
+canvas.addEventListener("contextrestored", redraw);
+ctx.reset();
+
+a mine tech that makes mines you can stand on
+ works similar to the field block throwing system
+ but you don't need to find a block to throw
+ blocks explode after mobs touch them
+ or 3 seconds after you touch them
+ benefits from all block tech
+
+go non-collide with mobs when immune to damage?
+
+mobs that are invulnerable from the front
+
+vertical reversed version of reservoir level, start at top and press buttons to lower slime
+ mechanic: push a very large block into slime in order to stand on it and avoid slime
+
+add anticipation to more mob attacks
+ stabber
+ striker
+
+can mob bullets damage other mob?
+ maybe if they switch collisions and classType === "body" or obj.classType === "bullet"
+
+figure out how to get friction effects on map/body to apply to player
+also horizontal moving platform?
+
+growBoss and cellBoss are too similar
+
+variant of Occam's razor - remove 50% of your tech for each removed get:
+ 2 bots?
+ 50 energy max
+
+tech immune to harm after mob kill
+ require no other mob kill tech?
+ cloaking field tech?
+
+final boss invulnerability
+ until mobs are cleared?
+ in between phases
+ for all of one phase
+
+JUNK tech - do something fun to the mob display health method
+
+new platform element, spring
+ toggle to on when player touches platform
+ platform extends in any direction
+
+boss that gives nearby mobs invulnerability
+ invulnerability needs to toggle off and on
+ boss is only mildly aggressive
+ repulsed by player up to a point
+ attracted to mobs
+
+training
+ save training level progress as local variable
+ reset progress to zero if you clear all training levels
+ maybe only save progress if you made if past the trainingHeal level
+ make the training button more obvious if the account has only played 1-2 times
+ larger?
+ position?
+ animated text?
+ uses the lore voice/text code?
+ replace all mob clear triggers with button triggers?
+ tutorial rooms:
+ look around with your mouse?
+ easier deflecting level, with 1-2 attacking mobs
+ gun rooms: (different mobs type in each room)
+ different mobs in each room
+ how to introduce mob shields?
+ "hopper" "slasher" "shooter "grenadier" "striker" "laser" "stabber" "springer" "pulsar" "launcher" "launcherOne" "exploder" "sneaker" "sucker" "sniper" "spinner" "grower" "beamer" "focuser" "spawner" "ghoster"
+ spores - use 1 ammo to take out several mobs at once, you have to block with your shield until the mobs die
+ drones - use mouse to bring drones around a couple corners
+ foam - slow boss mob, and run away
+ laser - reflect off walls to hit mobs
+ field rooms:
+ standing wave - bullets come from every direction
+ perfect diamagnetism - drop field to rapid stream of bullets and fire gun at them
+ negative mass - fly over a bunch of ground based mobs , hoppers
+ molecular assembler - guide drones around the corner
+ plasma torch - nothing fancy, just kill mobs
+ time dilation - get past some mobs
+ cloaking - sneak past mobs to collect some heals
+ pilot wave - toss blocks at mobs
+ worm hole - teleport past lasers
+ puzzle/platforming rooms:
+ use the double constrained platforms
+ stealth room
+ probably should make 2+
+ combat rooms:
+ boss gauntlet, spawn with nothing but a few power ups and fight 10 bosses
+ use no gun, just bots to kil stuff
+
+balance time dilation with bose einstein (you can freeze everything and take no damage)
+ code is still there, need to balance
+ balance with energy drain?
+
+make a line of constrained mobs move like a snake
+ apply forces with directions determined by time and position on the snake
+
+tech: basic research - heal power ups spawn as research power ups instead, and using research heals you (needs to be pretty low, like 3% health)
+tech: maintenance - heals no longer spawn, but using research heals you 100%
+
+foam tech - make it move slower, last much longer, and push away other foam bullets
+ not sure about bouncing off walls, but that might be fun too
+
+tech extend fracture analysis to give bonus damage to frozen also, but reduce the 400%->300%?
+
+pulsar mobs retarget too easily
+also they drift around too much
+
+convert blocked mobs into bullets
+ only for the very small bullets that move fast after being blocked
+ delete bulletmob and spawn a nail-like bullet with the same properties as the bulletmob
+
+electric motors: increases movement speed and jump height, but jumping and moving costs energy
+ overwrite the key event listeners?
+ JUNK tech?
+
+mob that fires bullets in 4,5,6,7 different directions at once, no aiming
+ grow a bit before it fires to indicate state
+
+quasarBoss: inverted pulsar boss that hits everything except where its aiming
+
+intro map: diegeticly draw a mouse with field highlighted
+ also indicate space?
+ dynamically adjust drawing after picking up a gun
+
+increase mass and movement speed at the same time
+ increase jump differently because it scales extra with mass
+ m.defaultMass = 4.5
+ m.definePlayerMass()
+
+give history boss legs?
+
+field tech - disable blocking, but does high damage to mobs inside field
+ and maybe slows mobs it damages
+
+mob/boss that fires a laser at player, but give player time to avoid
+ laser isn't always on
+ they target where player was 1 second ago
+ they turn to face player?
+
+tech rocket jump - jumping produces an explosion at your feet that lets you jump extra high, but does some damage
+ require electric reactive armor?
+
+Plasma Burner: upgrade for plasma torch, basically just a jet engine. does high damage, but short range, mostly for player movement.
+ maybe reduce gravity to really low then apply a vector away from mouse direction
+
+auto-gon - auto battler with n-gon mob AI and tech
+ you build a group of mobs and bosses from n-gon
+ they fight other mobs and bosses
+ similar research and tech system to n-gon
+ some mobs can fire player weapons
+
+tech: relativistic jets:
+ small particles that shot out from front and back poles and end up in a wide variety of spirals
+ slow trickle when charging and several more when firing
+
+Tech: Make player smol
+
+adapt the cloaking graphics to make a flashlight cone visual effect
+ put code in level.do?
+
+be nice if block throwing had a projected path
+
+Pilot wave tech
+ Energy use is increased, but you can now shape blocks using pressure
+ Grouping blocks will merge them into a massive ball
+ Size, density is determined by total mass
+
+aoe effect pushes mobs away, then rapidly pulls them in
+ for mines?
+
+mob: spawning seekers on death
+
+drones can combine with other drones to get bigger?
+drones that grab powers ups can grab more then one and get even bigger each time
+
+it would be helpful if there was a mechanism to recover mobs that fly off the map
+ add a ceiling system and a left/right walls system similar to the floor checks but only for mobs
+make non moving bosses not move after getting hit
+ shooter, shielding,
+
+scrolling console history in pause menu?
+pause should at least show the last in game console message
+
+in testing mode console log the body you click on
+
+tech: Standing Wave: Shockwave. Use FIELD button to shrink your shield and charge up, release to unleash a Shockwave.
+
+tech: quantized shields - harmonic standing wave field can only lose 33 energy per hit
+ draw 1,2,3 levels of the field based on energy?
+ the blocked value only scales up to 2x or 4x (33 energy) blocked
+ doesn't stack with spherical tech
+
+make a tech that improves all charge guns
+ for: pulse, foam, railgun
+ effect:
+ faster charge rate?
+ fire speed already does that...
+ harm reduction while charging
+ less ammo/energy used while charging?
+
+tech plasma : plasma length increases then decreases as you hold down the field button (like stabbing with a spear)
+ grows to 1.5 longer after 0.3 seconds, then returns to normal length over 1 second, until field is pressed again
+ extra energy is drained when field is longer
+
+energy conservation 6% damage recovered as energy
+ there is space for a negative effect in the text...
+
+tech: use the ability for power ups to have custom code
+ (note: this code is half way done, it just needs to be completed)
+ attracted to player
+ attracted to other power ups
+ explode if they touch?
+
+apply the new gun.do functions to other guns
+ railgun
+ crouching missile?
+ works similar to foam
+ performance issues?
+
+look into improving mouse lag with pointer lock?
+https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API
+https://www.vsynctester.com/game.html
+https://news.ycombinator.com/item?id=26530272
+
+tech: time dilation - when you exit time dilation rewind to the state you entered
+ position, velocity, and health
+ no energy cost
+
+be able to open up custom mode in the normal game
+ might need to be rebuilt from scratch
+ while in through testing mode?
+ have a way to make limited changes as allowed by tech you pick up in game
+ disable the in custom setting flag
+
+make different move methods
+ tech crouch charge jump
+ tech double jump
+
+tech when mobs are at full health you do 40% to them
+
+tech- move super fast, go intangible, drain energy very fast
+ this is like a dodge roll
+ tech for standing wave?, cloaking?
+
+tech pilot wave: mini black hole - pull mobs and blocks in with more force
+ also from farther away
+ also do damage?
+tech pilot wave: antigravity - blocks have no gravity for a few seconds after exiting the field
+ maybe they bounce too?
+ maybe they explode?
+
+new power up - increase damage and fire speed, for 15 seconds
+ named boost?
+ enabled by a tech
+ power up color: ?
+ how to indicate effect duration
+ or just give the effect after picking up a reroll
+
+tech- do 50% more damage in close, but 50% less at a distance
+ code it like techisFarAwayDmg
+ have these tech disable each other
+
+new status effect: weakness, mobs do 75% les damage
+ graphic indication?
+
+new status effect: fear - push mob away from player for a time
+
+new status effect - apply status effect to mobs that makes blocks attracted to them
+ only lasts a few cycles
+ or zero cycles and it doesn't need to be a status
+
+have some mobs spawn in later in the level (in hard and why modes)
+ where
+ at defined points in array levelSpawns = [{x:0,y:0},{x:0,y:0}]
+ store the locations of mobs when the level starts to use as respawn points
+ remove the locations that are close to player
+ when?
+ after some mobs are dead
+ after the boss is killed
+
+look for tech that could update description text with count and tech is information
+ can only use variables that change in effect() and remove()
+ this.description = `8% chance to duplicate spawned power ups chance to duplicate = ${techduplicateChance} `
+
+use mac automator to speed up your n-gon -> git sync
+
+movement fluidity
+ let legs jump on mobs, but player will still take damage
+ like: ori and the blind forest, celeste
+ many of the movement abilities in these games require levels to be built around the ability
+ general feeling of responsiveness and control
+ coyote time: can still jump a few cycles after leaving ground
+ tech double jump
+ tech air dash
+ tech wall jump
+ wall grab?
+ maybe remove falling damage and block damage?
+
+have a mob apply a positive status effect on other mobs,
+ heal?
+ make it yellow
+ damage bonus, but how?
+ possible balance issues
+
+css transition for pause menu
+
+animate new level spawn by having the map aspects randomly fly into place
+
+n-gon outreach ideas
+ blips - errant signal on youtube
+ reddit - r/IndieGaming
+ hacker news - show hacker news post
+ twitch - lets play
+
+******************************************************** BUGS ********************************************************
+
+bug: maybe I can put in an event listener to reset inputs to false when you tab out to prevent key sticking
+
+bug - url sharing still broken sometimes
+
+tech upgrade to anthropic principle to make it trigger at 50% life and 0% once per map
+
+bug? cloaking field doesn't show energy over max
+
+run more profiles of n-gon to fix performance issues
+
+bug - death while paused crashes game?
+
+bug: possibly clearing away all bullets causes a problem
+ bullet.js 255 (.do() is missing)
+ I died and quantum immortality triggered (I had needles and ice-IX)
+ game crashed but recovered
+
+vanish element bug, crashes on touching element, happens for 1 person maybe with junk tech?
+
+safari issues
+ once: can't pick up blocks
+ fixed on new map
+ cloaking field
+ once: after damage, locked into slow time mode
+ fixed on damage
+ 3 times player head graphics not rotating
+ left/right leg flip broke
+ walk leg direction, legs are walking backwards
+ happened maybe after power up selection menu??
+ cloaking field(at least once)
+ aiming still works
+ fixed on new map, although flip still broken (is flip a separate issue?)
+ flip fixed on new game
+
+sharing builds as html doesn't work for long lists...
+ it shouldn't be sharing undefined at all
+ probably some other problems too
+ (this might be fixed...)
+
+blocks on buttons teleport into the button endlessly if they are being slowly floated away
+ maybe add a cooldown?
+ can't reproduce
+
+ants marching outline doesn't sync right on safari anymore.
+
+door to exit in level: vats does nothing
+ did I do that?
+
+death while in power up selection menu doesn't reset properly
+ of course it's not possible to die in this menu unless you use testing and shift+X
+
+player can become crouched while not touching the ground if they exit the ground while crouched
+
+a couple times people have reported the final boss dropping extra bodies on death
+
+blue triangle boss can move backwards and aim away from you if set up properly
+ issues with dot product probably, but might not be worth fixing
+
+mouse event e.which is deprecated
+
+fix door.isClosing actually meaning isClosed?
+
+make it so that when you are immune to harm you can either jump on mobs or you pass through them
+
+is there a way to check if the player is stuck inside the map or block
+ trigger a short term non-collide if that occurs
+
+(intermittent, but almost every time) bug - capping the fps causes random slow downs, that can be fixed with pause
+
+******************************************************** LEVELS ********************************************************
+
+map: observatory
+ button controls rotation of telescope
+ laser beam shoots out of telescope
+ button opens the dome
+
+level with mobs that follow a genetic algorithm
+ mobs have genes
+ the last mob that did damage saves it's genes to local storage
+ new mobs have the saved genes, but with some random mutations
+ mutations need to be balanced to prevent a gene from moving towards infinity
+ total genome must equal 1 (100%)
+ binary genes have a flat cost
+ example: phasing through walls might cost 0.2
+ spectrum genes have a rate
+ example: acceleration cost 0.01 per 0.001
+ possible genes
+ genes should only effect it's ability to touch the player
+ so not damage?
+ genome: spectrum
+ acceleration
+ top speed / air friction
+ damageReduction
+ duration?
+ health decreases naturally?
+ or they just go away like bullets?
+ spawn rate
+ look frequency / memory?
+ genome: binary
+ go through walls
+ blink/teleport (like striker)
+ grow when near target
+ split into two
+ shielded
+ occurs in a specialized level
+ named: gene lab, gene factory, genetic lab, genome facility
+ in the level sequence after lab and before gauntlet?
+ level ends after a period of time
+ exit is hidden until time is up and it appears
+ the level tests player durability/evasion
+ this is a nice contrast to the final level that tests damage output, and the gauntlet which tests AoE damage
+
+rename intro level to something lore related
+
+buttons can now on/off boosts
+
+repeat map in vertical when you fall teleport to above the mab, as if the map repeats
+ camera looks strange when you teleport player with a high velocity
+
+map element - player rotates a rotor that makes a platform go up or down
+
+level element: a zone with wind, anti-gravity, extra gravity
+ control with button
+
+******************************************************** MOBS ********************************************************
+
+mob that charges up and then fires many bullets at once in a connect
+
+mob that draws a lin from it to the player, and past. then it charges across that line
+
+mob that spawns eggs after they die
+ eggs don't attack but grow back into a mob after about 10s
+
+mob mechanics
+ use the force at a location effect, like the plasma field
+ Matter.Body.applyForce(who, path[1], force)
+
+mob - after taking damage
+ release seekers
+ teleports
+
+hop boss:
+ AoE damage when landing
+ pull in player? and blocks?
+ extra gravity on falling?
+ immune to damage while falling?
+
+mob: molecule shapes - 2 separate mobs joined by a bond
+ use constraints: just spawn 2x or 3x groupings
+ low friction so they can spin around
+ spin when attacking player?
+ increase constraint length when attacking
+
+Mob: "Tentacle": Sits on wall. Is a black blob. When you get near it, reaches out and grabs you, similar to wires. Does not deal damage.
+ maybe it could be immune to damage? but it is spawned by an actual mob
+
+level Boss: fractal Sierpiński triangle
+ https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle
+ spawns a 1/2 size version of the boss, this version can also spawn a smaller version, but it is capped at some size level
+ they spawn once at the start of the level
+ if a version dies, one can be replaced every ten seconds by the largest version
+
+mob: wall mounted guns / lasers
+ not part of randomized mob pool, customized to each level
+
+level boss: fires a line intersection in a random direction every few seconds.
+ the last two intersections have a destructive laser between them.
+
+******************************************************** SOUND ********************************************************
+
+add sounds
+ https://developer.mozilla.org/en-US/docs/Web/API/OscillatorNode
+ https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Advanced_techniques
+ style
+ interesting chords, like music, mixolyd
+ can fade into the background
+ chords gradual rise and fall in volume
+ shouldn't be traditional effects
+ adjust volume with distance
+ mute option to settings
+ end all sounds with each new level
+ write some functions to produce sounds
+ will this effect performance?
+ https://padenot.github.io/web-audio-perf/
+ "Web Audio API implementation use two threads", so it probably isn't much of an issue
+ when to make sounds?
+ if near some strange thing in the level
+ after grabbing a power up, in the selection menu
+ from mobs, damage,inside field
+ when activating fields: time, negative mass,
+
+ //setup audio context
+ function tone(frequency) {
+ const audioCtx = new(window.AudioContext || window.webkitAudioContext)();
+ const oscillator = audioCtx.createOscillator();
+ const gainNode = audioCtx.createGain();
+ gainNode.gain.value = 0.25; //controls volume
+ oscillator.connect(gainNode);
+ gainNode.connect(audioCtx.destination);
+ oscillator.type = "sine"; // 'sine' 'square', 'sawtooth', 'triangle' and 'custom'
+ oscillator.frequency.value = frequency; // value in hertz
+ oscillator.start();
+ return { oscillator: oscillator, audioCtx: audioCtx }
+ }
+ // https://www.fresnostate.edu/folklore/Olson/JUSTINT.HTM
+ // mixolyd. C D E F+ G A+ B
+ // key=G 264 297 330 356.40 396* 445.50 495
+ // const t264 = tone(264)
+ // t264.oscillator.stop(t264.audioCtx.currentTime + 2) //in seconds, not milliseconds for some reason
+ // tone(297)
+ // tone(330)
+ // tone(356.40)
+ // tone(396)
+ // tone(445.50)
+ // tone(495)
+
+
+******************************************************** LORE ********************************************************
+
+possible names for tech
+ strange loop
+ holonomy - parallel transport of a vector leads to movement (applies to curved space)
+ hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other.
+ swarm intelligence - for a drone tech
+ genetic algorithm
+ metaheuristic - is a higher-level procedure or heuristic designed to find, generate, or select a heuristic (partial search algorithm) that may provide a sufficiently good solution to an optimization problem, especially with incomplete or imperfect information or limited computation capacity
+ stochastic optimization
+ electrostatic discharge
+ Gödel's incompleteness
+ quantum zeno effect (perturbation of a system prevents some systems from evolving because it scrambles coherence) (apply to lasers, fields)
+ counterfactual - something false
+ regression to the mean
+ phlogiston theory is a superseded scientific theory that postulated the existence of a fire-like element called phlogiston
+ Laplace's demon was a notable published articulation of causal determinism on a scientific basis by Pierre-Simon Laplace in 1814.[1] According to determinism, if someone (the demon) knows the precise location and momentum of every atom in the universe, their past and future values for any given time are entailed; they can be calculated from the laws of classical mechanics.
+ evolutionary cosmology
+ eternal inflation
+ hypergraph
+ SQUID (for superconducting quantum interference device) is a very sensitive magnetometer used to measure extremely subtle magnetic fields, based on superconducting loops containing Josephson junctions.
+ Josephson junction - superconducting junction used in SQUIDS and quantum computers
+ nuclear pasta - hard matter in neutron star
+ nonlocal, nonlocality: maybe use for pilot wave
+ fine-tuned universe
+ nonperturbative
+ D-branes
+ instanton or pseudoparticle
+ soliton (wave packet)
+ hall effect thrusters
+ spaghettification
+ particle accelerator
+ superluminal signalling
+ NP-complete
+ lenticular lens: is an array of lenses, designed so that when viewed from slightly different angles, different parts of the image underneath are shown.
+ p-hacking JUNK tech
+ https://en.wikipedia.org/wiki/High-entropy_alloys high yield strength and low ductility, high temp resistance
+ https://en.wikipedia.org/wiki/Refractory_metals hard, high temp resistance
+ https://en.wikipedia.org/wiki/Upper-atmospheric_lightning#Elves
+ prion quine - self replicating protein
+ Unitarity - https://en.wikipedia.org/wiki/Unitarity_(physics) - all probabilities add up to 1, calculations work the same forward and backwards in time
+ this is violated by expansion of the universe
+ https://en.wikipedia.org/wiki/Cosmic_censorship_hypothesis - black holes can't leak
+ Alcubierre warp drive (FTL with negative mass)
+ Spherules - A spherule is a small sphere or spherical body. It can also refer to a thick-walled spherical structure that contains endospores and occurs in the parasitic form of fungi
+ negative entropy
+ memetics
+ magnetorquers - produce spin by pushing on earth's magnetic field
+ Josephson junction - superconducting junction
+ Pyroelectricity - voltage from temp changes - upgrade from piezoelectricity
+ dark star - upgrade to WIMPs
+
+******************************************************** CARS IMAGES ********************************************************
+
+process: discord midjourney prompts -> "pixelmator pro" adjust color, repair, scale to 384x256, export PNG -> webP? -> place in /img folder
+make n-gon a progressive web app to manage image downloads, cache
+wave function collapse opens the pause menu after it triggers alternate reality
+ this is actually good, maybe reuse this code to get pause menu to open at any time
+if pause is pressed while selecting power ups, display pause menu on top of selection menu
+***styles***
+ try --- Pastel drawing, Psychedelic art, Arabesque (cool patterns), knolling (everything spread out and placed on a flat mat)
+ try taking screen shots of fields graphics and feeding them into midJourney V4
+ technology stuff --- Dan Matutina (cute complex technology),
+ Katsuhiro Otomo (intricate space technology), Tsutomu Nihei (black and white detailed future tech)
+ infographics of all know multiverses. 1980s Japanese graphic design, dimensional astrolabe,
+ Japanese poster graphics, Ralph McQuarrie (looks like star wars), Simon Stålenhag (retro-futuristic), Yoshiyuki Tomino (detailed anime future technology)
+ isometric: low-poly, box cutout, made in blender, Materials: matte clay
+ subtractive sculpture
+ kinetic sculpture
+ quantum stuff -- Hypertorus, Glowing Opal Pearlescent, Physics, Hydro-Dipping Hydrodipped, Vija Celmins, Matt Molloy (photo of golden waves in the sky)
+***maybe redo***
+ laser
+ supercritical fission
+***past style themes***
+ base prompt for player on 5.2: clean white robot spherical turret on bird legs test chamber
+ standing wave - a 3-D cyan transparent nested concentric aligned centered sphere with rings
+ by Philippe Starck
+ perfect diamagnetism - physics magnetic field chalk diagram
+ time dilation - graphic of a hyperbolic equation Luminogram
+ negative mass - Blacklight painting by Moebius
+ plasma torch - by Dan Mumford
+
+ metamaterial cloaking - Scientific photography by Miki Asai, by Bruce Munro
+ molecular assembler - by Laurie Greasley 16-bit Isometric
+ wormhole - by Tim White
+ pilot wave - none
+
+ nail gun - Screenprint
+ shotgun - blueprint by Dan McPharlin
+ grenades, missiles, explosions - vibrant fireball explosion sonic shockwave ring art by Victo Ngai --ar 3:2 --v 5 --s 750
+ spores - turquoise black spores on a white background full color scientific anatomy by Ernst Haeckel
+ drones - insect quadcopter tilt-shift photography
+ super balls - By Akari Toriyama
+ wave - sound wave oscilloscope by Paul Catherall, concentric circles by Paul Catherall
+ Barbara Takenaga's painting depicting a clean sound wave on aoscilloscope device --ar 3:2 --v 5
+ foam - black blobs Ink doodle
+ harpoon - iron harpoon on a rope weapon art white background by Eiichiro Oda --no fish --ar 3:2 --v 5 --s 750
+ mine - by Dan McPharlin
+ laser - complex optical scientific equipment
+ knolling photography
+
+ guns, ammo - isometric clean pixel art image cutaway of , style of tekkonkinkreet
+ defensive - Paper cutout
+ bots - hovering drone by Laurie Greasley 16-bit Isometric
+ generic energy tech - by Laurie Greasley
+ duplication, cancel - by Kazumasa Nagai
+ anti-shear topology, fracture analysis, shear stress - Chemigram
+ ON/OFF - ASCII art
+ block throwing - Bauhaus style
+ tech that adds JUNK - by Choi Jeong-hwa
+ ice IX - microscope images of ice crystals
+ tech that spawns health - glowing green balls by Enki Bilal
+ invulnerable - by Nick Veasey (photos that look like x-rays)
+ alternate reality - Fractal art
+ tech choice - mandala tile Mosaic
+ time, CPT, pause - by Lee Bontecou
+ boost, coupling power ups tech - cyan electron orbiting a black nucleus electric field as bas-relief //(by Kazumasa Nagai)
+ radioactive - volumetric atomic nucleus diagram by Paul Catherall
+
+
+
diff --git a/resent-client/assets.epk b/online-mc/assets.epk
similarity index 100%
rename from resent-client/assets.epk
rename to online-mc/assets.epk
diff --git a/resent-client/classes.js b/online-mc/classes.js
similarity index 100%
rename from resent-client/classes.js
rename to online-mc/classes.js
diff --git a/resent-client/favicon.png b/online-mc/favicon.png
similarity index 100%
rename from resent-client/favicon.png
rename to online-mc/favicon.png
diff --git a/resent-client/fix-webm-duration.js b/online-mc/fix-webm-duration.js
similarity index 100%
rename from resent-client/fix-webm-duration.js
rename to online-mc/fix-webm-duration.js
diff --git a/resent-client/index.html b/online-mc/index.html
similarity index 99%
rename from resent-client/index.html
rename to online-mc/index.html
index 20510920..b280885d 100644
--- a/resent-client/index.html
+++ b/online-mc/index.html
@@ -307,8 +307,8 @@
assetsURI: "assets.epk",
localesURI: "lang/",
servers: [
- { addr: "wss://asianf4rmer.minecraft.pe", name: "AsianF4rmer SMP" },
- { addr: "wss://legendsmp.minecraft.pe", name: "LegendSMP" }
+ { addr: "wss://asian.minecraft.pe", name: "AsianF4rmer SMP" },
+ { addr: "wss://legendsmp.minecraft.pe", name: "blocked :(" }
],
};
diff --git a/resent-client/logo.png b/online-mc/logo.png
similarity index 100%
rename from resent-client/logo.png
rename to online-mc/logo.png
diff --git a/projects.html b/projects.html
new file mode 100644
index 00000000..64df3618
--- /dev/null
+++ b/projects.html
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Projects | Selenite
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Download Save
+ Upload Save
+
+
+
+ Play a random game!
+
+
+ Click to view recommended games!
+
+
+
+ Pinned Games
+ pin some games for things to show up here!
+
+
+
+ All Games
+
+
+
+
+
+
+
diff --git a/quotes.json b/quotes.json
new file mode 100644
index 00000000..de352d79
--- /dev/null
+++ b/quotes.json
@@ -0,0 +1,34 @@
+[
+ "pay attention during school",
+ "yall playing games while im making the website ur using",
+ "\"p-p-p-p-pwettier code ><\" - sky 2023",
+ "\"im jumping off a FUCKING BRIDGE\" - also sky 2023",
+ "shout out to whoever spent 2 hours on snake",
+ "selenite >>> byvolp",
+ "Lorem ipsum dolor sit amet, adipiscing consequat adipiscing sit amet. In tortor dolor, sollicitudin quis urna vitae, rutrum selecrelico dolor. Ut facilisis ornare lacus, ut dictum felis aliquam ut. Omnino interdum fit cum cura. Non est aequum, non solum, sed nec refert quis sit terra. Sed vestibulum a tellus non semper. Aliquam a neque euismod dolor dapibus aliquet ultricies ut nibh. Sed eget auctor ante. Aliquam dictum volutpat vestibulum. Putasti ovum paschale futurum. Nullo modo.",
+ "FAGGOT",
+ "ive currently lost $5 on this website",
+ "join the discord NOW",
+ "have any of you played on the og padlet?",
+ "linux is so much better than windows",
+ "chromebooks suck",
+ "technoblade never dies",
+ "Selenite has shut down.",
+ "theres at least 2, maybe 3 games on this website",
+ "yall failing ur classes while im a straight A student in all honors",
+ "just maybe stole a bunch ideas from 3kh0",
+ "why tf is cookie clicker the most popular game",
+ "https://discord.gg/7jyufnwJNf",
+ "buy smth from the patreon so i dont have to be in debt anymore",
+ "https://skysthelimit.dev",
+ "https://github.com/skysthelimitt",
+ "selenite.pages.dev",
+ "the square root of OGNUM1 is SQRTNUM1",
+ "ZG8geW91ciBzY2hvb2wgd29yaw",
+ "use the transfer tool to keep ur data from other websites",
+ "best way to bypass the filter is on my patreon!",
+ "best proxy ever only on my patreon",
+ "🥺👉👈",
+ "what website is this?",
+ "btw, hcps leaked 30k+ private emails and are hiding it :)"
+]
\ No newline at end of file
diff --git a/settings.html b/settings.html
index 17a05725..01f762e2 100644
--- a/settings.html
+++ b/settings.html
@@ -1,118 +1,101 @@
-
-
+
-
-
-
-
-
+
-
-
+
+
+
+
- Selenite
+ Settings | Selenite
-
+
-
-
+
+
-
+
+
-
-
-
-
+
+
-
-
-
selenite
-
-
-
+
+ Settings
Clear your current tab cloak
Themes
- Selenite
- Selenite - Blinding Edition
- e-gamepass
+
+ Selenite
+ Light Mode
+ Dark Mode
+ e-gamepass
+ cools1te
+
-
-
+
+
+
+
+
diff --git a/snake/assets/logos/fnbx/snake_arcade/v3/apple_00.png b/snake/assets/apple_00.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v3/apple_00.png
rename to snake/assets/apple_00.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_01.png b/snake/assets/apple_01.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_01.png
rename to snake/assets/apple_01.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_02.png b/snake/assets/apple_02.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_02.png
rename to snake/assets/apple_02.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_03.png b/snake/assets/apple_03.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_03.png
rename to snake/assets/apple_03.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_04.png b/snake/assets/apple_04.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_04.png
rename to snake/assets/apple_04.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_05.png b/snake/assets/apple_05.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_05.png
rename to snake/assets/apple_05.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_06.png b/snake/assets/apple_06.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_06.png
rename to snake/assets/apple_06.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_07.png b/snake/assets/apple_07.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_07.png
rename to snake/assets/apple_07.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_08.png b/snake/assets/apple_08.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_08.png
rename to snake/assets/apple_08.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_09.png b/snake/assets/apple_09.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_09.png
rename to snake/assets/apple_09.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_10.png b/snake/assets/apple_10.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_10.png
rename to snake/assets/apple_10.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_11.png b/snake/assets/apple_11.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_11.png
rename to snake/assets/apple_11.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_12.png b/snake/assets/apple_12.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_12.png
rename to snake/assets/apple_12.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_13.png b/snake/assets/apple_13.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_13.png
rename to snake/assets/apple_13.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_14.png b/snake/assets/apple_14.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_14.png
rename to snake/assets/apple_14.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_15.png b/snake/assets/apple_15.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_15.png
rename to snake/assets/apple_15.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_16.png b/snake/assets/apple_16.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_16.png
rename to snake/assets/apple_16.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_17.png b/snake/assets/apple_17.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_17.png
rename to snake/assets/apple_17.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_18.png b/snake/assets/apple_18.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_18.png
rename to snake/assets/apple_18.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_19.png b/snake/assets/apple_19.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_19.png
rename to snake/assets/apple_19.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_20.png b/snake/assets/apple_20.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_20.png
rename to snake/assets/apple_20.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_21.png b/snake/assets/apple_21.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/apple_21.png
rename to snake/assets/apple_21.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/blink.png b/snake/assets/blink.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/blink.png
rename to snake/assets/blink.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/box.png b/snake/assets/box.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v4/box.png
rename to snake/assets/box.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_00.png b/snake/assets/color_00.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_00.png
rename to snake/assets/color_00.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_01.png b/snake/assets/color_01.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_01.png
rename to snake/assets/color_01.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_02.png b/snake/assets/color_02.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_02.png
rename to snake/assets/color_02.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_03.png b/snake/assets/color_03.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_03.png
rename to snake/assets/color_03.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_04.png b/snake/assets/color_04.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_04.png
rename to snake/assets/color_04.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_05.png b/snake/assets/color_05.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_05.png
rename to snake/assets/color_05.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_06.png b/snake/assets/color_06.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_06.png
rename to snake/assets/color_06.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_07.png b/snake/assets/color_07.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_07.png
rename to snake/assets/color_07.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_08.png b/snake/assets/color_08.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_08.png
rename to snake/assets/color_08.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_09.png b/snake/assets/color_09.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_09.png
rename to snake/assets/color_09.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_10.png b/snake/assets/color_10.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_10.png
rename to snake/assets/color_10.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_11.png b/snake/assets/color_11.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_11.png
rename to snake/assets/color_11.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_12.png b/snake/assets/color_12.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_12.png
rename to snake/assets/color_12.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_13.png b/snake/assets/color_13.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_13.png
rename to snake/assets/color_13.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_14.png b/snake/assets/color_14.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_14.png
rename to snake/assets/color_14.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_15.png b/snake/assets/color_15.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_15.png
rename to snake/assets/color_15.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_16.png b/snake/assets/color_16.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_16.png
rename to snake/assets/color_16.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_17.png b/snake/assets/color_17.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_17.png
rename to snake/assets/color_17.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v5/color_18.png b/snake/assets/color_18.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v5/color_18.png
rename to snake/assets/color_18.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v3/count_00.png b/snake/assets/count_00.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v3/count_00.png
rename to snake/assets/count_00.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v3/count_01.png b/snake/assets/count_01.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v3/count_01.png
rename to snake/assets/count_01.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/v3/count_02.png b/snake/assets/count_02.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/v3/count_02.png
rename to snake/assets/count_02.png
diff --git a/snake/assets/css.css b/snake/assets/css.css
index 6b683c26..abca5352 100644
--- a/snake/assets/css.css
+++ b/snake/assets/css.css
@@ -53,4 +53,4 @@
font-weight: 500;
src: url(https://fonts.gstatic.com/s/roboto/v29/KFOlCnqEu92Fr1MmEU9fBBc4.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
-}
+}
\ No newline at end of file
diff --git a/snake/assets/logos/fnbx/snake_arcade/default_end.png b/snake/assets/default_end.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/default_end.png
rename to snake/assets/default_end.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/die.png b/snake/assets/die.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/die.png
rename to snake/assets/die.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/eat.png b/snake/assets/eat.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/eat.png
rename to snake/assets/eat.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/effect.png b/snake/assets/effect.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/effect.png
rename to snake/assets/effect.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/end_empty.png b/snake/assets/end_empty.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/end_empty.png
rename to snake/assets/end_empty.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/gradient_end.png b/snake/assets/gradient_end.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/gradient_end.png
rename to snake/assets/gradient_end.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/key_types.png b/snake/assets/key_types.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/key_types.png
rename to snake/assets/key_types.png
diff --git a/snake/assets/logos/fnbx/snake_arcade/key_types_dark.png b/snake/assets/key_types_dark.png
similarity index 100%
rename from snake/assets/logos/fnbx/snake_arcade/key_types_dark.png
rename to snake/assets/key_types_dark.png
diff --git a/snake/assets/keys.svg b/snake/assets/keys.svg
new file mode 100644
index 00000000..54f7356b
--- /dev/null
+++ b/snake/assets/keys.svg
@@ -0,0 +1 @@
+NEWSVG1
\ No newline at end of file
diff --git a/snake/assets/logos/fnbx/snake_arcade/keys.svg b/snake/assets/logos/fnbx/snake_arcade/keys.svg
deleted file mode 100644
index 44a72984..00000000
--- a/snake/assets/logos/fnbx/snake_arcade/keys.svg
+++ /dev/null
@@ -1 +0,0 @@
-NEWSVG1
\ No newline at end of file
diff --git a/snake/assets/logos/fnbx/snake_arcade/poison_audio.bin b/snake/assets/logos/fnbx/snake_arcade/poison_audio.bin
deleted file mode 100644
index 256b3fb9..00000000
Binary files a/snake/assets/logos/fnbx/snake_arcade/poison_audio.bin and /dev/null differ
diff --git a/snake/assets/logos/fnbx/snake_arcade/v3/trophy_00.png b/snake/assets/logos/fnbx/snake_arcade/v3/trophy_00.png
deleted file mode 100644
index 6ba4527b..00000000
Binary files a/snake/assets/logos/fnbx/snake_arcade/v3/trophy_00.png and /dev/null differ
diff --git a/snake/assets/logos/fnbx/snake_arcade/v4/apple_00.png b/snake/assets/logos/fnbx/snake_arcade/v4/apple_00.png
deleted file mode 100644
index 9a5156d0..00000000
Binary files a/snake/assets/logos/fnbx/snake_arcade/v4/apple_00.png and /dev/null differ
diff --git a/snake/assets/m_aLUfP.js b/snake/assets/m_aLUfP.js
index 75778296..97ce0cce 100644
--- a/snake/assets/m_aLUfP.js
+++ b/snake/assets/m_aLUfP.js
@@ -365,11 +365,11 @@ b();a.Lc({dispose:function(){},isDisposed:function(){return d}});return function
try{
s_a("pKhWu");
-var s_Fwd={sUb:new s_jD("/logos/fnbx/snake_arcade/","end_audio",{DEATH:0,WIN:49},418)},s_Gwd={pUb:new s_iD(s_Fwd.sUb,"DEATH",626.939),WIN:new s_iD(s_Fwd.sUb,"WIN",914.286)},s_Hwd=function(){s_hD.call(this,s_Fwd,s_Gwd)};s_m(s_Hwd,s_hD);
-var s_AD={Hw:new s_jD("/logos/fnbx/snake_arcade/","game_audio.4",{BOX:0,DOWN:59,EAT:78,KEY:101,LEFT:132,PORTAL:151,REVERSE:212,RIGHT:273,UP:292},418)},s_BD={mGc:new s_iD(s_AD.Hw,"BOX",757.551),AFa:new s_iD(s_AD.Hw,"DOWN",235.102),qHc:new s_iD(s_AD.Hw,"EAT",287.347),EQc:new s_iD(s_AD.Hw,"KEY",391.837),LEFT:new s_iD(s_AD.Hw,"LEFT",235.102),wSc:new s_iD(s_AD.Hw,"PORTAL",783.673),TSc:new s_iD(s_AD.Hw,"REVERSE",783.673),RIGHT:new s_iD(s_AD.Hw,"RIGHT",235.102),UP:new s_iD(s_AD.Hw,"UP",235.102)},s_Iwd=function(){s_hD.call(this,
+var s_Fwd={sUb:new s_jD("/stack/","end_audio",{DEATH:0,WIN:49},418)},s_Gwd={pUb:new s_iD(s_Fwd.sUb,"DEATH",626.939),WIN:new s_iD(s_Fwd.sUb,"WIN",914.286)},s_Hwd=function(){s_hD.call(this,s_Fwd,s_Gwd)};s_m(s_Hwd,s_hD);
+var s_AD={Hw:new s_jD("/stack/","game_audio.4",{BOX:0,DOWN:59,EAT:78,KEY:101,LEFT:132,PORTAL:151,REVERSE:212,RIGHT:273,UP:292},418)},s_BD={mGc:new s_iD(s_AD.Hw,"BOX",757.551),AFa:new s_iD(s_AD.Hw,"DOWN",235.102),qHc:new s_iD(s_AD.Hw,"EAT",287.347),EQc:new s_iD(s_AD.Hw,"KEY",391.837),LEFT:new s_iD(s_AD.Hw,"LEFT",235.102),wSc:new s_iD(s_AD.Hw,"PORTAL",783.673),TSc:new s_iD(s_AD.Hw,"REVERSE",783.673),RIGHT:new s_iD(s_AD.Hw,"RIGHT",235.102),UP:new s_iD(s_AD.Hw,"UP",235.102)},s_Iwd=function(){s_hD.call(this,
s_AD,s_BD)};s_m(s_Iwd,s_hD);
-var s_Jwd={cva:new s_jD("/logos/fnbx/snake_arcade/","poison_audio",{BURP:0,DIZZY_1:27,DIZZY_2:42,DIZZY_3:57,DIZZY_4:72,SQUISH:87},418)},s_CD={nGc:new s_iD(s_Jwd.cva,"BURP",339.592),gHc:new s_iD(s_Jwd.cva,"DIZZY_1",182.857),hHc:new s_iD(s_Jwd.cva,"DIZZY_2",182.857),iHc:new s_iD(s_Jwd.cva,"DIZZY_3",182.857),jHc:new s_iD(s_Jwd.cva,"DIZZY_4",182.857),Ujb:new s_iD(s_Jwd.cva,"SQUISH",470.204)},s_Kwd=function(){s_hD.call(this,s_Jwd,s_CD)};s_m(s_Kwd,s_hD);
-var s_DD=function(a,b,c){this.path=a;this.Aa=b;this.context=c;this.loaded=!1;this.Eo=new Image;this.Eo.crossOrigin="Anyonymous";this.wa=document.createElement("canvas").getContext("2d");this.oa=document.createElement("canvas").getContext("2d");this.Ca=this.Ba="";this.Ea=-1;s_Lwd(this)},s_Lwd=function(a){a.Eo.src="./assets/logos/fnbx/"+a.path;s_Ii(a.Eo,"load",function(){a.loaded=!0;s_Mwd(a);""!==a.Ba&&""!==a.Ca&&(s_ED(a,a.Ba,a.Ca,a.Ea),a.Ba="",a.Ca="",a.Ea=0)})},s_Mwd=function(a){a.wa.canvas.width=
+var s_Jwd={cva:new s_jD("/stack/","poison_audio",{BURP:0,DIZZY_1:27,DIZZY_2:42,DIZZY_3:57,DIZZY_4:72,SQUISH:87},418)},s_CD={nGc:new s_iD(s_Jwd.cva,"BURP",339.592),gHc:new s_iD(s_Jwd.cva,"DIZZY_1",182.857),hHc:new s_iD(s_Jwd.cva,"DIZZY_2",182.857),iHc:new s_iD(s_Jwd.cva,"DIZZY_3",182.857),jHc:new s_iD(s_Jwd.cva,"DIZZY_4",182.857),Ujb:new s_iD(s_Jwd.cva,"SQUISH",470.204)},s_Kwd=function(){s_hD.call(this,s_Jwd,s_CD)};s_m(s_Kwd,s_hD);
+var s_DD=function(a,b,c){this.path=a;this.Aa=b;this.context=c;this.loaded=!1;this.Eo=new Image;this.Eo.crossOrigin="Anyonymous";this.wa=document.createElement("canvas").getContext("2d");this.oa=document.createElement("canvas").getContext("2d");this.Ca=this.Ba="";this.Ea=-1;s_Lwd(this)},s_Lwd=function(a){a.Eo.src="./assets/"+a.path;s_Ii(a.Eo,"load",function(){a.loaded=!0;s_Mwd(a);""!==a.Ba&&""!==a.Ca&&(s_ED(a,a.Ba,a.Ca,a.Ea),a.Ba="",a.Ca="",a.Ea=0)})},s_Mwd=function(a){a.wa.canvas.width=
a.Eo.width;a.wa.canvas.height=a.Eo.height;a.wa.clearRect(0,0,a.wa.canvas.width,a.wa.canvas.height);a.wa.drawImage(a.Eo,0,0);a.oa.canvas.width=a.Eo.width;a.oa.canvas.height=a.Eo.height;a.oa.clearRect(0,0,a.oa.canvas.width,a.oa.canvas.height);a.oa.drawImage(a.Eo,0,0)},s_ED=function(a,b,c,d){d=void 0===d?-1:d;if(a.loaded){s_Mwd(a);b=s_HSc(b);c=s_HSc(c);for(var e=0===b[2]?1:c[2]/b[2],f=a.wa.getImageData(0,0,a.wa.canvas.width,a.wa.canvas.height),g=f.data,h=0;h=d;1>k[2]&&!l&&(k[0]=c[0],k[1]=c[1],k[2]*=e);k=s_ESc(k[0],k[1],k[2]);g[h]=k[0];g[h+1]=k[1];g[h+2]=k[2]}a.oa.putImageData(f,0,0)}else a.Ba=b,a.Ca=c,a.Ea=d};s_DD.prototype.render=function(a,b,c,d,e){this.loaded&&(this.context.translate(b.x,b.y),this.context.rotate(d),this.context.drawImage(this.oa.canvas,0,this.ld()*a,this.Dd(),this.ld(),c.x*e,c.y*e,this.Dd()*e,this.ld()*e),this.context.rotate(-d),this.context.translate(-b.x,-b.y))};
s_DD.prototype.Dd=function(){return this.Eo.width};s_DD.prototype.ld=function(){return this.Eo.height/this.Aa};var s_FD=function(a){return a.wa.canvas};
@@ -380,9 +380,9 @@ threshold:10},{base:"#fc2d00",target:"#808080",threshold:10}],s_Swd="#4E7CF6 #54
[];this.kva=0;this.yb=[];this.hj=!1;this.Ya=0;this.HRb=this.$k=!1;this.Ye=this.Vb=0;this.muted=!1;this.closed=!0;this.Yda=this.Ve=0;this.fW="";this.qR=this.xu=0;this.gW="";this.Wda=this.ticks=this.oR=this.Mf=this.Bx=this.qB=this.lR=this.Oc=0;this.aW=[];this.iHa=1;this.jHa=4;this.cW=10;this.zD=0;this.kkb=8;this.tgb=7;this.IK=0;this.lzb=6;this.yu=0;this.Ga={YL:0,YR:0,QJ:0,Hx:0,jt:!1,WQ:0,tV:0,zY:!1};this.Ja={YL:0,YR:0,QJ:0,Hx:0,jt:!1,WQ:0,tV:0,zY:!1};this.Uc=this.uc=this.pR=this.Rda=0;this.DTb=this.lva=
!1;this.TYb=this.J_b=null;this.Ds=!1;this.wL=-1;this.yUb=this.getData("si").Cb(!1);this.hHa=new s_Iwd;this.gCb=new s_Hwd;this.rTb=new s_Kwd;this.Yc=a.service.Yc;this.Ek=new s_Sg(0,0);this.oa=new s_Sg(0,0);this.FUb=function(){};this.canvas=this.Da("UzWXSb").Vd();this.context=this.canvas.getContext("2d");this.zr=this.Da("kAVrAc").Vd();this.ii=this.zr.getContext("2d");this.Ca=s_Uwd();this.Cc=s_Uwd();this.Oa=s_Uwd();this.Oa.fillStyle="#000000";this.Iv=s_Uwd();this.Mn=s_Uwd();s_BA(this);this.dVc=new s_Is(document);
s_i(this.dVc,"key",function(g){return b.PB(g)});s_i(this.getRoot().el(),"touchstart",function(g){return b.kE(g)});s_i(this.getRoot().el(),"touchmove",function(g){return b.nK(g)});s_i(this.getRoot().el(),"touchend",function(g){return b.yT(g)});this.Yc.addListener(function(){s_Vwd(b)});this.direction="NONE";this.Ra="RIGHT";this.Ab=this.wy="NONE";this.Sda=new s_Og(0,0);this.Ax=new s_Og(0,0);this.kb=new Set;this.Ib=new Set;this.Ze=new s_Og(0,0);this.X3=new s_Og(0,0);this.lW=new s_Og(0,0);this.vo=new Map;
-this.bW=new Set;this.yg=new Map;this.ECb=new Map;s_Wwd(this);this.Vi=s_Owd*s_Xwd(this);for(a=0;21>a;a++){var c=new s_DD("snake_arcade/v4/apple_"+((10>a?"0":"")+a)+".png",1,this.Ca),d=s_Rwd[a];s_ED(c,d.base,d.target,d.threshold);this.aW.push(c)}this.Em=new s_DD("snake_arcade/blink.png",9,this.Ca);this.ED=new s_DD("snake_arcade/eat.png",15,this.Ca);this.hz=new s_DD("snake_arcade/die.png",37,this.Ca);this.Es=new s_DD("snake_arcade/tongue.png",21,this.Ca);this.uJ=new s_DD("snake_arcade/effect.png",21,
-this.Ca);this.vf=new s_Og;this.cZb=new s_DD("snake_arcade/key_types.png",5,this.Ca);this.YZb=new s_DD("snake_arcade/key_types_dark.png",5,this.Ca);this.Zd=new s_DD("snake_arcade/v4/box.png",8,this.Ca);this.TJb=new s_DD("snake_arcade/blink.png",9,this.Ca);this.QZb=new s_DD("snake_arcade/eat.png",15,this.Ca);this.HZb=new s_DD("snake_arcade/die.png",37,this.Ca);this.TZb=new s_DD("snake_arcade/tongue.png",21,this.Ca);this.CTb=new s_DD("snake_arcade/blink.png",9,this.Ca);this.D_b=new s_DD("snake_arcade/eat.png",
-15,this.Ca);this.k_b=new s_DD("snake_arcade/die.png",37,this.Ca);s_ED(this.CTb,"#5282F2","#909090");s_ED(this.D_b,"#5282F2","#909090");s_ED(this.k_b,"#5282F2","#909090");this.Be=new s_DD("snake_arcade/end_empty.png",1,this.ii);this.Uda=new s_DD("snake_arcade/default_end.png",1,this.ii);this.iVc=new s_DD("snake_arcade/rainbow_end.png",1,this.ii);this.XUb=new s_DD("snake_arcade/gradient_end.png",1,this.ii);this.lCb=new s_DD("snake_arcade/v3/speed_01.png",1,this.ii);this.GTb=new s_DD("snake_arcade/v3/speed_02.png",
+this.bW=new Set;this.yg=new Map;this.ECb=new Map;s_Wwd(this);this.Vi=s_Owd*s_Xwd(this);for(a=0;21>a;a++){var c=new s_DD("apple_"+((10>a?"0":"")+a)+".png",1,this.Ca),d=s_Rwd[a];s_ED(c,d.base,d.target,d.threshold);this.aW.push(c)}this.Em=new s_DD("blink.png",9,this.Ca);this.ED=new s_DD("eat.png",15,this.Ca);this.hz=new s_DD("die.png",37,this.Ca);this.Es=new s_DD("tongue.png",21,this.Ca);this.uJ=new s_DD("effect.png",21,
+this.Ca);this.vf=new s_Og;this.cZb=new s_DD("key_types.png",5,this.Ca);this.YZb=new s_DD("key_types_dark.png",5,this.Ca);this.Zd=new s_DD("box.png",8,this.Ca);this.TJb=new s_DD("blink.png",9,this.Ca);this.QZb=new s_DD("eat.png",15,this.Ca);this.HZb=new s_DD("die.png",37,this.Ca);this.TZb=new s_DD("tongue.png",21,this.Ca);this.CTb=new s_DD("blink.png",9,this.Ca);this.D_b=new s_DD("eat.png",
+15,this.Ca);this.k_b=new s_DD("die.png",37,this.Ca);s_ED(this.CTb,"#5282F2","#909090");s_ED(this.D_b,"#5282F2","#909090");s_ED(this.k_b,"#5282F2","#909090");this.Be=new s_DD("end_empty.png",1,this.ii);this.Uda=new s_DD("default_end.png",1,this.ii);this.iVc=new s_DD("rainbow_end.png",1,this.ii);this.XUb=new s_DD("gradient_end.png",1,this.ii);this.lCb=new s_DD("speed_01.png",1,this.ii);this.GTb=new s_DD("speed_02.png",
1,this.ii);this.$Uc="./assets/volume_up_white_24dp.png";this.RUc="./assets/volume_off_white_24dp.png";this.vy=s_ID[0][0];this.ugb=s_ID[0][1];this.T8=new s_Og(0,0);s_C(this.Da("y7GBZ").el(),"visibility","hidden");this.Gc="score";a=this.Da("wXSCdb").el();c=[];for(d=0;d
+
-
-
- Snake
-
-
-
-
+
+
+
+ Google Snake | 3kh0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Play
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/snake/inframe.html b/snake/inframe.html
deleted file mode 100644
index 7516a83a..00000000
--- a/snake/inframe.html
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-Snake
Play
\ No newline at end of file
diff --git a/style.css b/style.css
index 79adb9eb..09b3894c 100644
--- a/style.css
+++ b/style.css
@@ -1,249 +1,251 @@
-html {
- text-align: center;
- align-content: center;
- font-family: "Share Tech Mono", monospace;
- padding: 0;
- margin: 0;
-}
-.content {
- animation: fadeIn 5s;
- width: 90%;
- margin: 0 auto;
-}
-* {
- z-index: 1;
-}
-button {
- background-color: var(--input-bg-color);
- color: var(--main-text-color);
- border: 2px solid var(--border-color);
- border-radius: 6px;
- padding: 5px 13px;
- margin-bottom: 6px;
- margin: 10px;
- transition-duration: 0.45s;
- font-size: 20px;
- color: var(--main-text-color);
- font-family: "Share Tech Mono", monospace;
- text-underline-position: under;
- opacity: 70%;
-}
-button:hover {
- cursor: pointer;
- opacity: 90%;
-}
-
-h2 {
- font-size: 42px;
- color: var(--main-text-color);
- margin-top: 3%;
-}
-
-.game {
- width: 13%;
- display: inline-block;
- background-color: var(--game-color);
- padding: 1%;
- border-radius: 10%;
- margin: 2%;
- transition-duration: 0.5s;
- box-shadow: 0px 0px 5px 5px var(--game-color);
- height: 100%;
-}
-
-.game:hover {
- transform: scale(1.05);
- filter: brightness(120%);
-}
-
-.game h1 {
- float: right;
- font-size: 0.85em;
- color: var(--main-text-color);
-}
-.game img {
- width: 100%;
- height: 100%;
- border-radius: 10%;
- aspect-ratio: 1/1;
-}
-
-a {
- font-size: 20px;
- color: var(--main-text-color);
- margin: 10px;
- transition-duration: 0.5s;
-}
-
-a:hover {
- filter: brightness(150%);
-}
-
-.bookmarklet {
- font-size: 25px;
-}
-
-.title {
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-@keyframes fadeIn {
+@import url('https://fonts.googleapis.com/css2?family=Prompt:wght@300&display=swap');
+@keyframes loadInAnimation {
0% {
opacity: 0;
}
- 20% {
- opacity: 40;
- }
- 80% {
- opacity: 90;
- }
- 90% {
- opacity: 92;
- }
100% {
opacity: 100;
}
}
-@keyframes fadeInPadding {
- 0% {
- padding-left: 0%;
- padding-right: 0%;
- }
- 100% {
- padding-left: 5%;
- padding-right: 5%;
- }
-}
-
-body {
- background: repeating-linear-gradient(
- 45deg,
- var(--bg-1) 0%,
- var(--bg-2) 33%,
- var(--bg-1) 66%,
- var(--bg-2) 100%
- );
- background-size: 400% 400%;
- background-attachment: fixed;
- animation: gradient 30s linear infinite;
- height: 100vh;
-}
-
-@keyframes gradient {
- 0% {
- background-position: 100% 0%;
- }
- 100% {
- background-position: 15% 100%;
- }
-}
-
-input[type="text"] {
- width: 50%;
- box-sizing: border-box;
- font-size: 20px;
- background-color: var(--input-bg-color);
- padding: 0.8% 0.8%;
- text-align: center;
- color: var(--main-text-color);
- border: 2px solid var(--border-color);
- border-radius: 5px;
+* {
+ transition-duration: 0.5s;
outline: none;
- opacity: 70%;
- transition: opacity 0.25s ease-in-out;
- font-family: "Share Tech Mono", monospace;
+ border: none;
+ box-sizing: border-box;
+ align-content: center;
+ text-align: center;
+ font-family: 'Prompt', sans-serif;
+ color: var(--textcolor);
}
-input[type="text"]:hover {
- opacity: 80%;
+body {
+ margin: 0;
+ padding: 0;
+ background-color: var(--bg);
+ color: var(--textcolor);
}
-input[type="text"]:focus {
- opacity: 100%;
+header,
+footer {
+ background-color: var(--uibg);
+ display: flex;
+ padding: 0.7rem;
+ width: 100%;
+ z-index: 1;
+ justify-content: center;
+}
+header {
+ top: 0;
+ position: fixed;
+ box-shadow: 0 5px 10px var(--uibg);
+}
+footer.noscroll {
+ position: fixed;
+ overflow: hidden;
+}
+footer {
+ bottom: 0;
+ box-shadow: 0 -5px 10px var(--uibg);
+}
+footer a,
+footer a:visited,
+header a,
+header a:visited {
+ text-align: center;
+ font-weight: 700;
+ text-decoration: none;
+ margin-right: 2rem;
+ margin-left: 1rem;
}
-::placeholder {
- /* Chrome, Firefox, Opera, Safari 10.1+ */
- color: var(--main-text-color);
- opacity: 0.6; /* Firefox */
+footer a:hover,
+header a:hover {
+ text-shadow: 2px 2px 6px var(--textcolor);
+}
+main {
+ animation: 1.25s ease-in-out 0s 1 loadInAnimation;
+ align-items: center;
+ flex-direction: column;
+ display: flex;
+ min-height: calc(100vh - (2 * 0.7rem));
+ gap: 0;
+ flex-wrap: wrap;
+ margin: auto;
+ margin-top: 4rem;
+ width: 90%;
+}
+main#main.noscroll {
+ justify-content: center;
}
-ul {
- list-style-type: none;
+h1,
+h2,
+h3,
+p,
+a {
+ margin: 0;
padding: 0;
}
-li {
- display: inline;
- padding: 8px;
- top: 10px;
+.samerow {
+ display: flex;
+ justify-content: center;
+ gap: 0;
+ flex-wrap: wrap;
+}
+h1 {
+ font-size: 60px;
}
-#footer {
- font-size: 10px;
+h2 {
+ font-size: 40px;
}
-
-p {
- font-size: 20px;
- color: var(--p-text-color);
-}
-
-#webname #webicon {
- width: 20%;
- box-sizing: border-box;
- font-size: 20px;
- background-color: var(--input-bg-color);
- padding: 0.8% 0.8%;
- text-align: center;
- color: var(--main-text-color);
- border: 2px solid var(--border-color);
- border-radius: 5px;
- outline: none;
- opacity: 70%;
- transition: opacity 0.25s ease-in-out;
- font-family: "Share Tech Mono", monospace;
-}
-
h3 {
font-size: 20px;
- color: var(--main-text-color);
+}
+p, a {
+ font-size: 16px;
}
-.submit {
- background-color: var(--input-bg-color);
- color: var(--main-text-color);
- border: 2px solid var(--border-color);
- border-radius: 6px;
- padding: 5px 13px;
- margin-bottom: 6px;
- margin: 10px;
- transition-duration: 0.45s;
- font-size: 20px;
- color: var(--main-text-color);
- font-family: "Share Tech Mono", monospace;
- text-underline-position: under;
- opacity: 70%;
-}
-.submit:hover {
+button, input#websubmit.submit, input[type=submit]#panic {
cursor: pointer;
- opacity: 90%;
+ background-color: var(--inputbg);
+ border-color: var(--inputborder);
+ border-width: 5px;
+ border-radius: 10px;
+ border-style: solid;
+ padding: 7px;
+ margin-left: 20px;
+ margin-right: 20px;
+ margin: 10px;
+}
+
+button:hover, input#websubmit.submit:hover, input[type=submit]#panic:hover {
+ filter: brightness(80%);
+ transform: scale(1.07);
+}
+
+img {
+ width: 100%;
+ aspect-ratio: auto;
+ user-select: none;
+}
+
+.img-container a {
+ width: 100%;
+}
+
+.img-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: row;
+ gap: 0;
+ flex-wrap: wrap;
+ width: 6%;
+ aspect-ratio: 1 / 1;
+ margin: 2%;
+}
+
+.game {
+ width: 15%;
+ border-radius: 20px;
+ display: inline-block;
+ background-color: var(--uibg);
+ margin: 15px;
+ cursor: pointer;
+ box-shadow: 0px 0px 5px 5px var(--uibg);
+}
+
+.game:hover {
+ transform: scale(1.1);
+ filter: brightness(85%);
+ box-shadow: 0px 0px 5px 5px var(--uibg);
+}
+
+.game h1 {
+ font-size: 13px;
+ float: right;
+ margin-right: 10px;
+ margin-top: 3px;
+ margin-bottom: 3px;
+}
+
+.game img {
+ width: 100%;
+ border-radius: 20px;
+ aspect-ratio: 1 / 1;
}
img.star {
float: left;
- filter: invert(var(--invert-logo, 0));
- width: 20%;
- transition-duration: 0.75s;
+ width: 10%;
+ margin-top: 3px;
+ margin-bottom: 3px;
+ margin-left: 10px;
}
-#random {
- padding: 0.8% 0.8%;
+#noscroll {
+ overflow-y: hidden;
+ justify-content: center;
}
-#particles-js {
- position: fixed;
+
+#games,
+#pinned {
width: 100%;
- height: 100%;
- background-position: 50% 50%;
- z-index: -127321;
+ justify-content: center;
}
+
+a {
+ font-size: 16px;
+}
+
+input[type="text"] {
+ width: 50%;
+ background-color: var(--inputbg);
+ box-sizing: border-box;
+ font-size: 20px;
+ padding: 0.8% 0.8%;
+ text-align: center;
+ border-radius: 5px;
+ outline: none;
+ margin: 10px;
+ border: 2px solid var(--inputborder);
+ border-radius: 5px;
+ transition: opacity 0.25s ease-in-out;
+ opacity: 100%;
+}
+input[type=text]:hover {
+ opacity: 80%;
+}
+
+.bookmarkletdiv {
+ width: 30%;
+ background-color: var(--uibg);
+ box-shadow: 0px 0px 5px 5px var(--uibg);
+ padding: 5px;
+ margin: 15px;
+ border-radius: 10px;
+ display: inline-block;
+}
+
+.bookmarkletdiv a {
+ font-size: 30px;
+}
+
+form {
+ width: 100%;
+}
+.samerow.themebtns {
+ width: 70%;
+}
+
+select {
+ border-radius: 5px;
+ background-color: var(--inputbg);
+ border-color: var(--inputborder);
+ border-width: 5px;
+ border-radius: 10px;
+ border-style: solid;
+ padding: 0.5% 0.5%;
+ margin: 0.25%;
+}
\ No newline at end of file
diff --git a/subway-surfers-ny/NewYorkIcon.png b/subway-surfers-ny/NewYorkIcon.png
new file mode 100644
index 00000000..185297c3
Binary files /dev/null and b/subway-surfers-ny/NewYorkIcon.png differ
diff --git a/subway-surfers-ny/assets/audio/guard_catch.ogg b/subway-surfers-ny/assets/audio/guard_catch.ogg
new file mode 100644
index 00000000..7ba35b52
Binary files /dev/null and b/subway-surfers-ny/assets/audio/guard_catch.ogg differ
diff --git a/subway-surfers-ny/assets/audio/guard_proximity.ogg b/subway-surfers-ny/assets/audio/guard_proximity.ogg
new file mode 100644
index 00000000..e032642c
Binary files /dev/null and b/subway-surfers-ny/assets/audio/guard_proximity.ogg differ
diff --git a/subway-surfers-ny/assets/audio/guard_start.ogg b/subway-surfers-ny/assets/audio/guard_start.ogg
new file mode 100644
index 00000000..dd59ce1a
Binary files /dev/null and b/subway-surfers-ny/assets/audio/guard_start.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_death.ogg b/subway-surfers-ny/assets/audio/hero_death.ogg
new file mode 100644
index 00000000..84622137
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_death.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_death_hitcam.ogg b/subway-surfers-ny/assets/audio/hero_death_hitcam.ogg
new file mode 100644
index 00000000..beffaf70
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_death_hitcam.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_dodge.ogg b/subway-surfers-ny/assets/audio/hero_dodge.ogg
new file mode 100644
index 00000000..2cbd368e
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_dodge.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_foot_l.ogg b/subway-surfers-ny/assets/audio/hero_foot_l.ogg
new file mode 100644
index 00000000..789457fa
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_foot_l.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_foot_r.ogg b/subway-surfers-ny/assets/audio/hero_foot_r.ogg
new file mode 100644
index 00000000..6a708003
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_foot_r.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_hoverboard_crash.ogg b/subway-surfers-ny/assets/audio/hero_hoverboard_crash.ogg
new file mode 100644
index 00000000..8c55f94a
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_hoverboard_crash.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_jump.ogg b/subway-surfers-ny/assets/audio/hero_jump.ogg
new file mode 100644
index 00000000..a266e570
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_jump.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_revive.ogg b/subway-surfers-ny/assets/audio/hero_revive.ogg
new file mode 100644
index 00000000..448309b3
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_revive.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_roll.ogg b/subway-surfers-ny/assets/audio/hero_roll.ogg
new file mode 100644
index 00000000..efe7e394
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_roll.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_sneakers_foot_l.ogg b/subway-surfers-ny/assets/audio/hero_sneakers_foot_l.ogg
new file mode 100644
index 00000000..5b17d906
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_sneakers_foot_l.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_sneakers_foot_r.ogg b/subway-surfers-ny/assets/audio/hero_sneakers_foot_r.ogg
new file mode 100644
index 00000000..856e875b
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_sneakers_foot_r.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_sneakers_jump.ogg b/subway-surfers-ny/assets/audio/hero_sneakers_jump.ogg
new file mode 100644
index 00000000..41f91da3
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_sneakers_jump.ogg differ
diff --git a/subway-surfers-ny/assets/audio/hero_stumble.ogg b/subway-surfers-ny/assets/audio/hero_stumble.ogg
new file mode 100644
index 00000000..2b9ea27b
Binary files /dev/null and b/subway-surfers-ny/assets/audio/hero_stumble.ogg differ
diff --git a/subway-surfers-ny/assets/audio/pickup_coin.ogg b/subway-surfers-ny/assets/audio/pickup_coin.ogg
new file mode 100644
index 00000000..09048fdb
Binary files /dev/null and b/subway-surfers-ny/assets/audio/pickup_coin.ogg differ
diff --git a/subway-surfers-ny/assets/audio/pickup_powerup.ogg b/subway-surfers-ny/assets/audio/pickup_powerup.ogg
new file mode 100644
index 00000000..227ea648
Binary files /dev/null and b/subway-surfers-ny/assets/audio/pickup_powerup.ogg differ
diff --git a/subway-surfers-ny/assets/audio/special_jetpack.ogg b/subway-surfers-ny/assets/audio/special_jetpack.ogg
new file mode 100644
index 00000000..8aeaefcc
Binary files /dev/null and b/subway-surfers-ny/assets/audio/special_jetpack.ogg differ
diff --git a/subway-surfers-ny/assets/audio/special_jetpack_start.ogg b/subway-surfers-ny/assets/audio/special_jetpack_start.ogg
new file mode 100644
index 00000000..b74fdd58
Binary files /dev/null and b/subway-surfers-ny/assets/audio/special_jetpack_start.ogg differ
diff --git a/subway-surfers-ny/assets/audio/special_magnet.ogg b/subway-surfers-ny/assets/audio/special_magnet.ogg
new file mode 100644
index 00000000..139f3dfc
Binary files /dev/null and b/subway-surfers-ny/assets/audio/special_magnet.ogg differ
diff --git a/subway-surfers-ny/assets/audio/theme.ogg b/subway-surfers-ny/assets/audio/theme.ogg
new file mode 100644
index 00000000..0c1e01b4
Binary files /dev/null and b/subway-surfers-ny/assets/audio/theme.ogg differ
diff --git a/subway-surfers-ny/assets/audio/ui_button.ogg b/subway-surfers-ny/assets/audio/ui_button.ogg
new file mode 100644
index 00000000..2d3fb893
Binary files /dev/null and b/subway-surfers-ny/assets/audio/ui_button.ogg differ
diff --git a/subway-surfers-ny/assets/data/chunks_game.json b/subway-surfers-ny/assets/data/chunks_game.json
new file mode 100644
index 00000000..4c9c533a
--- /dev/null
+++ b/subway-surfers-ny/assets/data/chunks_game.json
@@ -0,0 +1 @@
+{"routeChunk_default_b-s-b":{"name":"routeChunk_default_b-s-b","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":8,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_b-s-b","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"random_end","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"10"}},"children":[{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":-10,"y":0,"z":630},"$type":"TransformData"}},"children":[]},{"name":"ramp_and_egg","components":{"Transform":{"position":{"x":0,"y":0,"z":690},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":690},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":0,"y":50.5,"z":720},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":50.5,"z":720},"$type":"TransformData"}},"children":[]}]}]}]},{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":90},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"random_path","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"11"}},"children":[{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":-20,"y":7,"z":360},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":360},"$type":"TransformData"}},"children":[]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":540},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"blocker_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"161"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurveParent":{"$ref":"161"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"173"},"customOut":{"$id":"174"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"173"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"174"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":271},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"185"},"customOut":{"$id":"186"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"185"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"186"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"199"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurveParent":{"$ref":"199"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"211"},"customOut":{"$id":"212"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"211"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"212"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":301},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"223"},"customOut":{"$id":"224"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"223"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"224"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"237"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurveParent":{"$ref":"237"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"249"},"customOut":{"$id":"250"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"249"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"250"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":331},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"261"},"customOut":{"$id":"262"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"261"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"262"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-10,"y":0,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"275"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-10,"y":0,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"275"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-10,"y":0,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"287"},"customOut":{"$id":"288"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"287"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"288"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-10,"y":0,"z":346},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"299"},"customOut":{"$id":"300"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"299"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"300"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"313"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurveParent":{"$ref":"313"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"325"},"customOut":{"$id":"326"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePointTangent":{"$ref":"325"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePointTangent":{"$ref":"326"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":361},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"337"},"customOut":{"$id":"338"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"337"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"338"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"351"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"},"CurveParent":{"$ref":"351"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"363"},"customOut":{"$id":"364"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"363"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"364"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":391},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"375"},"customOut":{"$id":"376"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":391},"$type":"TransformData"},"CurvePointTangent":{"$ref":"375"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":391},"$type":"TransformData"},"CurvePointTangent":{"$ref":"376"}},"children":[]}]}]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":20,"y":7,"z":390},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":7,"z":390},"$type":"TransformData"}},"children":[]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"403"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurveParent":{"$ref":"403"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"415"},"customOut":{"$id":"416"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurvePointTangent":{"$ref":"415"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurvePointTangent":{"$ref":"416"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":421},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"427"},"customOut":{"$id":"428"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":421},"$type":"TransformData"},"CurvePointTangent":{"$ref":"427"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":421},"$type":"TransformData"},"CurvePointTangent":{"$ref":"428"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"441"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"},"CurveParent":{"$ref":"441"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"453"},"customOut":{"$id":"454"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"},"CurvePointTangent":{"$ref":"453"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"},"CurvePointTangent":{"$ref":"454"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":451},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"465"},"customOut":{"$id":"466"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":451},"$type":"TransformData"},"CurvePointTangent":{"$ref":"465"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":451},"$type":"TransformData"},"CurvePointTangent":{"$ref":"466"}},"children":[]}]}]}]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":480},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"487"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"},"CurveParent":{"$ref":"487"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"499"},"customOut":{"$id":"500"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"},"CurvePointTangent":{"$ref":"499"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"},"CurvePointTangent":{"$ref":"500"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":481},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"511"},"customOut":{"$id":"512"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":481},"$type":"TransformData"},"CurvePointTangent":{"$ref":"511"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":481},"$type":"TransformData"},"CurvePointTangent":{"$ref":"512"}},"children":[]}]}]}]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":540},"$type":"TransformData"}},"children":[]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":390},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},"routeChunk_default_choice":{"name":"routeChunk_default_choice","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":8,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"18"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"},{"$id":"23"},{"$id":"24"},{"$id":"25"},{"$id":"26"},{"$id":"27"},{"$id":"28"},{"$id":"29"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_choice","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"10"}},"children":[{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"random_path","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"14"}},"children":[{"name":"2","components":{"Transform":{"position":{"x":19.24548,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":-20.75452,"y":0,"z":120},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":19.24548,"y":0,"z":315},"$type":"TransformData"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20.75452,"y":29,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"68"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20.75452,"y":29,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"68"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20.75452,"y":29,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"80"},"customOut":{"$id":"81"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20.75452,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"80"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20.75452,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"81"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20.75452,"y":29,"z":416},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"92"},"customOut":{"$id":"93"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20.75452,"y":29,"z":416},"$type":"TransformData"},"CurvePointTangent":{"$ref":"92"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20.75452,"y":29,"z":416},"$type":"TransformData"},"CurvePointTangent":{"$ref":"93"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":19.24548,"y":29,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"106"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":19.24548,"y":29,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"106"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":19.24548,"y":29,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"118"},"customOut":{"$id":"119"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":19.24548,"y":29,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"118"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":19.24548,"y":29,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"119"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":19.24548,"y":29,"z":686},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"130"},"customOut":{"$id":"131"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":19.24548,"y":29,"z":686},"$type":"TransformData"},"CurvePointTangent":{"$ref":"130"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":19.24548,"y":29,"z":686},"$type":"TransformData"},"CurvePointTangent":{"$ref":"131"}},"children":[]}]}]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":19.24548,"y":37,"z":705},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":19.24548,"y":37,"z":705},"$type":"TransformData"}},"children":[]}]}]},{"name":"1","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":90},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"161"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":90},"$type":"TransformData"},"CurveParent":{"$ref":"161"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":90},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"173"},"customOut":{"$id":"174"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"173"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"174"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":91},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"185"},"customOut":{"$id":"186"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":91},"$type":"TransformData"},"CurvePointTangent":{"$ref":"185"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":91},"$type":"TransformData"},"CurvePointTangent":{"$ref":"186"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"199"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"CurveParent":{"$ref":"199"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"211"},"customOut":{"$id":"212"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"CurvePointTangent":{"$ref":"211"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"CurvePointTangent":{"$ref":"212"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":121},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"223"},"customOut":{"$id":"224"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":121},"$type":"TransformData"},"CurvePointTangent":{"$ref":"223"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":121},"$type":"TransformData"},"CurvePointTangent":{"$ref":"224"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"237"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"CurveParent":{"$ref":"237"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"249"},"customOut":{"$id":"250"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"CurvePointTangent":{"$ref":"249"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"CurvePointTangent":{"$ref":"250"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":151},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"261"},"customOut":{"$id":"262"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":151},"$type":"TransformData"},"CurvePointTangent":{"$ref":"261"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":151},"$type":"TransformData"},"CurvePointTangent":{"$ref":"262"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"275"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"CurveParent":{"$ref":"275"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"287"},"customOut":{"$id":"288"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"287"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"288"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":181},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"299"},"customOut":{"$id":"300"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"299"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"300"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":330},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":600},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":-20,"y":7,"z":45},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":45},"$type":"TransformData"}},"children":[]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":270},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":540},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"random_coins","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"18"}},"children":[{"name":"2","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":126},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"386"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"386"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"398"},"customOut":{"$id":"399"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"398"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"399"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":291},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"410"},"customOut":{"$id":"411"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":291},"$type":"TransformData"},"CurvePointTangent":{"$ref":"410"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":291},"$type":"TransformData"},"CurvePointTangent":{"$ref":"411"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":126},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"424"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurveParent":{"$ref":"424"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"436"},"customOut":{"$id":"437"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePointTangent":{"$ref":"436"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePointTangent":{"$ref":"437"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":486},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"448"},"customOut":{"$id":"449"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":486},"$type":"TransformData"},"CurvePointTangent":{"$ref":"448"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":486},"$type":"TransformData"},"CurvePointTangent":{"$ref":"449"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":29,"z":555},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":126},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"462"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":555},"$type":"TransformData"},"CurveParent":{"$ref":"462"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":555},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"474"},"customOut":{"$id":"475"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":555},"$type":"TransformData"},"CurvePointTangent":{"$ref":"474"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":555},"$type":"TransformData"},"CurvePointTangent":{"$ref":"475"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":681},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"486"},"customOut":{"$id":"487"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":681},"$type":"TransformData"},"CurvePointTangent":{"$ref":"486"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":681},"$type":"TransformData"},"CurvePointTangent":{"$ref":"487"}},"children":[]}]}]}]}]},{"name":"1","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"503"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"503"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"515"},"customOut":{"$id":"516"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"515"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"516"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"527"},"customOut":{"$id":"528"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"527"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"528"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"541"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"541"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"553"},"customOut":{"$id":"554"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"553"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"554"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":346},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"565"},"customOut":{"$id":"566"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"565"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"566"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":375},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"579"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":375},"$type":"TransformData"},"CurveParent":{"$ref":"579"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":375},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"591"},"customOut":{"$id":"592"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"591"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"592"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":376},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"603"},"customOut":{"$id":"604"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":376},"$type":"TransformData"},"CurvePointTangent":{"$ref":"603"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":376},"$type":"TransformData"},"CurvePointTangent":{"$ref":"604"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":405},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"617"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":405},"$type":"TransformData"},"CurveParent":{"$ref":"617"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":405},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"629"},"customOut":{"$id":"630"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":405},"$type":"TransformData"},"CurvePointTangent":{"$ref":"629"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":405},"$type":"TransformData"},"CurvePointTangent":{"$ref":"630"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":406},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"641"},"customOut":{"$id":"642"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":406},"$type":"TransformData"},"CurvePointTangent":{"$ref":"641"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":406},"$type":"TransformData"},"CurvePointTangent":{"$ref":"642"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":495},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"655"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.33,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":495},"$type":"TransformData"},"CurveParent":{"$ref":"655"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":495},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"667"},"customOut":{"$id":"668"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":495},"$type":"TransformData"},"CurvePointTangent":{"$ref":"667"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":593.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"668"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":593.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"679"},"customOut":{"$id":"680"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":495},"$type":"TransformData"},"CurvePointTangent":{"$ref":"679"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":593.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"680"}},"children":[]}]}]}]}]}]},{"name":"random","components":{"Transform":{"position":{"x":-20,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"19"}},"children":[{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":135},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":315},"$type":"TransformData"}},"children":[]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":270},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":300},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":540},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":600},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":20,"y":37,"z":705},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":37,"z":705},"$type":"TransformData"}},"children":[]}]}]}]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":7,"z":210},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":7,"z":210},"$type":"TransformData"}},"children":[]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":540},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":570},"$type":"TransformData"}},"children":[]}]},"routeChunk_default_s-b-s-b":{"name":"routeChunk_default_s-b-s-b","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":8,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_s-b-s-b","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-10,"y":0,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"48"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-10,"y":0,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"48"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-10,"y":0,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"60"},"customOut":{"$id":"61"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"60"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"61"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-10,"y":0,"z":166},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"72"},"customOut":{"$id":"73"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"72"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"73"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"86"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"CurveParent":{"$ref":"86"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"98"},"customOut":{"$id":"99"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"98"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"99"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":181},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"110"},"customOut":{"$id":"111"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"110"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"111"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":210},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"124"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":210},"$type":"TransformData"},"CurveParent":{"$ref":"124"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":210},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"136"},"customOut":{"$id":"137"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"136"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"137"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":211},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"148"},"customOut":{"$id":"149"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":211},"$type":"TransformData"},"CurvePointTangent":{"$ref":"148"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":211},"$type":"TransformData"},"CurvePointTangent":{"$ref":"149"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":240},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"162"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":240},"$type":"TransformData"},"CurveParent":{"$ref":"162"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":240},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"174"},"customOut":{"$id":"175"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"174"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"175"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":241},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"186"},"customOut":{"$id":"187"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"186"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"187"}},"children":[]}]}]}]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"209"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurveParent":{"$ref":"209"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"221"},"customOut":{"$id":"222"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePointTangent":{"$ref":"221"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePointTangent":{"$ref":"222"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":361},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"233"},"customOut":{"$id":"234"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"233"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"234"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"247"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"},"CurveParent":{"$ref":"247"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"259"},"customOut":{"$id":"260"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"259"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"260"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":391},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"271"},"customOut":{"$id":"272"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":391},"$type":"TransformData"},"CurvePointTangent":{"$ref":"271"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":391},"$type":"TransformData"},"CurvePointTangent":{"$ref":"272"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"285"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurveParent":{"$ref":"285"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"297"},"customOut":{"$id":"298"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurvePointTangent":{"$ref":"297"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurvePointTangent":{"$ref":"298"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":421},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"309"},"customOut":{"$id":"310"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":421},"$type":"TransformData"},"CurvePointTangent":{"$ref":"309"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":421},"$type":"TransformData"},"CurvePointTangent":{"$ref":"310"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-10,"y":0,"z":435},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"323"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-10,"y":0,"z":435},"$type":"TransformData"},"CurveParent":{"$ref":"323"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-10,"y":0,"z":435},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"335"},"customOut":{"$id":"336"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"335"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"336"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-10,"y":0,"z":436},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"347"},"customOut":{"$id":"348"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"347"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"348"}},"children":[]}]}]}]}]},{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":480},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":35.8,"z":630},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":35.8,"z":630},"$type":"TransformData"}},"children":[]}]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":-30,"y":0,"z":690},"$type":"TransformData"}},"children":[]}]},{"name":"coins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"411"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurveParent":{"$ref":"411"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"423"},"customOut":{"$id":"424"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurvePointTangent":{"$ref":"423"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurvePointTangent":{"$ref":"424"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":61},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"435"},"customOut":{"$id":"436"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":61},"$type":"TransformData"},"CurvePointTangent":{"$ref":"435"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":61},"$type":"TransformData"},"CurvePointTangent":{"$ref":"436"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"449"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurveParent":{"$ref":"449"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"461"},"customOut":{"$id":"462"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"461"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"462"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":91},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"473"},"customOut":{"$id":"474"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":91},"$type":"TransformData"},"CurvePointTangent":{"$ref":"473"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":91},"$type":"TransformData"},"CurvePointTangent":{"$ref":"474"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"487"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"CurveParent":{"$ref":"487"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"499"},"customOut":{"$id":"500"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"CurvePointTangent":{"$ref":"499"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"CurvePointTangent":{"$ref":"500"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":121},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"511"},"customOut":{"$id":"512"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":121},"$type":"TransformData"},"CurvePointTangent":{"$ref":"511"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":121},"$type":"TransformData"},"CurvePointTangent":{"$ref":"512"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"525"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"CurveParent":{"$ref":"525"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"537"},"customOut":{"$id":"538"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"CurvePointTangent":{"$ref":"537"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"CurvePointTangent":{"$ref":"538"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":151},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"549"},"customOut":{"$id":"550"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":151},"$type":"TransformData"},"CurvePointTangent":{"$ref":"549"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":151},"$type":"TransformData"},"CurvePointTangent":{"$ref":"550"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":450},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"563"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":450},"$type":"TransformData"},"CurveParent":{"$ref":"563"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":450},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"575"},"customOut":{"$id":"576"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":450},"$type":"TransformData"},"CurvePointTangent":{"$ref":"575"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":450},"$type":"TransformData"},"CurvePointTangent":{"$ref":"576"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":451},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"587"},"customOut":{"$id":"588"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":451},"$type":"TransformData"},"CurvePointTangent":{"$ref":"587"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":451},"$type":"TransformData"},"CurvePointTangent":{"$ref":"588"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"601"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"},"CurveParent":{"$ref":"601"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"613"},"customOut":{"$id":"614"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"},"CurvePointTangent":{"$ref":"613"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"},"CurvePointTangent":{"$ref":"614"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":481},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"625"},"customOut":{"$id":"626"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":481},"$type":"TransformData"},"CurvePointTangent":{"$ref":"625"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":481},"$type":"TransformData"},"CurvePointTangent":{"$ref":"626"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":510},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"639"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":510},"$type":"TransformData"},"CurveParent":{"$ref":"639"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":510},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"651"},"customOut":{"$id":"652"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":510},"$type":"TransformData"},"CurvePointTangent":{"$ref":"651"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":510},"$type":"TransformData"},"CurvePointTangent":{"$ref":"652"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":511},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"663"},"customOut":{"$id":"664"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":511},"$type":"TransformData"},"CurvePointTangent":{"$ref":"663"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":511},"$type":"TransformData"},"CurvePointTangent":{"$ref":"664"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":540},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"677"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":540},"$type":"TransformData"},"CurveParent":{"$ref":"677"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":540},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"689"},"customOut":{"$id":"690"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":540},"$type":"TransformData"},"CurvePointTangent":{"$ref":"689"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":540},"$type":"TransformData"},"CurvePointTangent":{"$ref":"690"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":541},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"701"},"customOut":{"$id":"702"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":541},"$type":"TransformData"},"CurvePointTangent":{"$ref":"701"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":541},"$type":"TransformData"},"CurvePointTangent":{"$ref":"702"}},"children":[]}]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":210},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":675},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":675},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_s-s-s-s":{"name":"routeChunk_default_s-s-s-s","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":8,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_s-s-s-s","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"29"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurveParent":{"$ref":"29"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"41"},"customOut":{"$id":"42"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurvePointTangent":{"$ref":"41"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurvePointTangent":{"$ref":"42"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":61},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"53"},"customOut":{"$id":"54"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":61},"$type":"TransformData"},"CurvePointTangent":{"$ref":"53"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":61},"$type":"TransformData"},"CurvePointTangent":{"$ref":"54"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"67"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurveParent":{"$ref":"67"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"79"},"customOut":{"$id":"80"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"79"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"80"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":91},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"91"},"customOut":{"$id":"92"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":91},"$type":"TransformData"},"CurvePointTangent":{"$ref":"91"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":91},"$type":"TransformData"},"CurvePointTangent":{"$ref":"92"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"105"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"CurveParent":{"$ref":"105"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"117"},"customOut":{"$id":"118"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"CurvePointTangent":{"$ref":"117"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"CurvePointTangent":{"$ref":"118"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":121},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"129"},"customOut":{"$id":"130"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":121},"$type":"TransformData"},"CurvePointTangent":{"$ref":"129"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":121},"$type":"TransformData"},"CurvePointTangent":{"$ref":"130"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"143"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurveParent":{"$ref":"143"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"155"},"customOut":{"$id":"156"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"155"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"156"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":301},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"167"},"customOut":{"$id":"168"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"167"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"168"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"181"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurveParent":{"$ref":"181"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"193"},"customOut":{"$id":"194"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"193"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"194"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":331},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"205"},"customOut":{"$id":"206"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"205"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"206"}},"children":[]}]}]}]}]},{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":10,"y":0,"z":135},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"234"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":10,"y":0,"z":135},"$type":"TransformData"},"CurveParent":{"$ref":"234"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":10,"y":0,"z":135},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"246"},"customOut":{"$id":"247"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"246"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"247"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":10,"y":0,"z":136},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"258"},"customOut":{"$id":"259"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"258"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"259"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"272"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"CurveParent":{"$ref":"272"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"284"},"customOut":{"$id":"285"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"CurvePointTangent":{"$ref":"284"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"CurvePointTangent":{"$ref":"285"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":151},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"296"},"customOut":{"$id":"297"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":151},"$type":"TransformData"},"CurvePointTangent":{"$ref":"296"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":151},"$type":"TransformData"},"CurvePointTangent":{"$ref":"297"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"310"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"CurveParent":{"$ref":"310"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"322"},"customOut":{"$id":"323"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"322"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"323"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":181},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"334"},"customOut":{"$id":"335"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"334"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"335"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":210},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"348"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":210},"$type":"TransformData"},"CurveParent":{"$ref":"348"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":210},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"360"},"customOut":{"$id":"361"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"360"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"361"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":211},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"372"},"customOut":{"$id":"373"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":211},"$type":"TransformData"},"CurvePointTangent":{"$ref":"372"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":211},"$type":"TransformData"},"CurvePointTangent":{"$ref":"373"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":240},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"386"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":240},"$type":"TransformData"},"CurveParent":{"$ref":"386"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":240},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"398"},"customOut":{"$id":"399"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"398"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"399"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":241},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"410"},"customOut":{"$id":"411"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"410"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"411"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":270},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"424"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":270},"$type":"TransformData"},"CurveParent":{"$ref":"424"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":270},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"436"},"customOut":{"$id":"437"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"436"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"437"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":271},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"448"},"customOut":{"$id":"449"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"448"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"449"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":10,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"462"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":10,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"462"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":10,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"474"},"customOut":{"$id":"475"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"474"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"475"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":10,"y":0,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"486"},"customOut":{"$id":"487"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"486"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"487"}},"children":[]}]}]}]}]},{"name":"random_path","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"10"}},"children":[{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":450},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":-20,"y":37,"z":495},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":37,"z":495},"$type":"TransformData"}},"children":[]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":525},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"550"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":525},"$type":"TransformData"},"CurveParent":{"$ref":"550"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":525},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"562"},"customOut":{"$id":"563"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":525},"$type":"TransformData"},"CurvePointTangent":{"$ref":"562"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":623.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"563"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":623.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"574"},"customOut":{"$id":"575"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":525},"$type":"TransformData"},"CurvePointTangent":{"$ref":"574"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":623.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"575"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":600},"$type":"TransformData"}},"children":[]}]},{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"600"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurveParent":{"$ref":"600"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"612"},"customOut":{"$id":"613"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurvePointTangent":{"$ref":"612"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"CurvePointTangent":{"$ref":"613"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":421},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"624"},"customOut":{"$id":"625"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":421},"$type":"TransformData"},"CurvePointTangent":{"$ref":"624"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":421},"$type":"TransformData"},"CurvePointTangent":{"$ref":"625"}},"children":[]}]}]}]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":450},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"647"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"},"CurveParent":{"$ref":"647"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"659"},"customOut":{"$id":"660"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"},"CurvePointTangent":{"$ref":"659"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"},"CurvePointTangent":{"$ref":"660"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":451},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"671"},"customOut":{"$id":"672"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":451},"$type":"TransformData"},"CurvePointTangent":{"$ref":"671"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":451},"$type":"TransformData"},"CurvePointTangent":{"$ref":"672"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"685"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"},"CurveParent":{"$ref":"685"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"697"},"customOut":{"$id":"698"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"},"CurvePointTangent":{"$ref":"697"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"},"CurvePointTangent":{"$ref":"698"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":481},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"709"},"customOut":{"$id":"710"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":481},"$type":"TransformData"},"CurvePointTangent":{"$ref":"709"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":481},"$type":"TransformData"},"CurvePointTangent":{"$ref":"710"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":510},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"723"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":510},"$type":"TransformData"},"CurveParent":{"$ref":"723"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":510},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"735"},"customOut":{"$id":"736"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":510},"$type":"TransformData"},"CurvePointTangent":{"$ref":"735"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":510},"$type":"TransformData"},"CurvePointTangent":{"$ref":"736"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":511},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"747"},"customOut":{"$id":"748"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":511},"$type":"TransformData"},"CurvePointTangent":{"$ref":"747"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":511},"$type":"TransformData"},"CurvePointTangent":{"$ref":"748"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":540},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"761"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":540},"$type":"TransformData"},"CurveParent":{"$ref":"761"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":540},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"773"},"customOut":{"$id":"774"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":540},"$type":"TransformData"},"CurvePointTangent":{"$ref":"773"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":540},"$type":"TransformData"},"CurvePointTangent":{"$ref":"774"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":541},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"785"},"customOut":{"$id":"786"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":541},"$type":"TransformData"},"CurvePointTangent":{"$ref":"785"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":541},"$type":"TransformData"},"CurvePointTangent":{"$ref":"786"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":570},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"799"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":570},"$type":"TransformData"},"CurveParent":{"$ref":"799"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":570},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"811"},"customOut":{"$id":"812"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":570},"$type":"TransformData"},"CurvePointTangent":{"$ref":"811"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":570},"$type":"TransformData"},"CurvePointTangent":{"$ref":"812"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":571},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"823"},"customOut":{"$id":"824"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":571},"$type":"TransformData"},"CurvePointTangent":{"$ref":"823"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":571},"$type":"TransformData"},"CurvePointTangent":{"$ref":"824"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-10,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"837"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-10,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"837"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-10,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"849"},"customOut":{"$id":"850"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"849"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"850"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-10,"y":0,"z":586},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"861"},"customOut":{"$id":"862"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"861"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"862"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":600},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"875"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":600},"$type":"TransformData"},"CurveParent":{"$ref":"875"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":600},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"887"},"customOut":{"$id":"888"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":600},"$type":"TransformData"},"CurvePointTangent":{"$ref":"887"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":600},"$type":"TransformData"},"CurvePointTangent":{"$ref":"888"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":601},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"899"},"customOut":{"$id":"900"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":601},"$type":"TransformData"},"CurvePointTangent":{"$ref":"899"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":601},"$type":"TransformData"},"CurvePointTangent":{"$ref":"900"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":630},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"913"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":630},"$type":"TransformData"},"CurveParent":{"$ref":"913"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":630},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"925"},"customOut":{"$id":"926"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":630},"$type":"TransformData"},"CurvePointTangent":{"$ref":"925"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":630},"$type":"TransformData"},"CurvePointTangent":{"$ref":"926"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":631},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"937"},"customOut":{"$id":"938"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":631},"$type":"TransformData"},"CurvePointTangent":{"$ref":"937"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":631},"$type":"TransformData"},"CurvePointTangent":{"$ref":"938"}},"children":[]}]}]}]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":10,"y":0,"z":660},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":675},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":675},"$type":"TransformData"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":0,"y":7,"z":375},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":375},"$type":"TransformData"}},"children":[]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":390},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},"routeChunk_default_s-s":{"name":"routeChunk_default_s-s","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":8,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_s-s","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-10,"y":0,"z":75},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"25"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-10,"y":0,"z":75},"$type":"TransformData"},"CurveParent":{"$ref":"25"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-10,"y":0,"z":75},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"37"},"customOut":{"$id":"38"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":75},"$type":"TransformData"},"CurvePointTangent":{"$ref":"37"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":75},"$type":"TransformData"},"CurvePointTangent":{"$ref":"38"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-10,"y":0,"z":76},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"49"},"customOut":{"$id":"50"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":76},"$type":"TransformData"},"CurvePointTangent":{"$ref":"49"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":76},"$type":"TransformData"},"CurvePointTangent":{"$ref":"50"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":90},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"63"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":90},"$type":"TransformData"},"CurveParent":{"$ref":"63"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":90},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"75"},"customOut":{"$id":"76"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"75"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"76"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":91},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"87"},"customOut":{"$id":"88"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":91},"$type":"TransformData"},"CurvePointTangent":{"$ref":"87"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":91},"$type":"TransformData"},"CurvePointTangent":{"$ref":"88"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"101"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"},"CurveParent":{"$ref":"101"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"113"},"customOut":{"$id":"114"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"},"CurvePointTangent":{"$ref":"113"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"},"CurvePointTangent":{"$ref":"114"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":121},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"125"},"customOut":{"$id":"126"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":121},"$type":"TransformData"},"CurvePointTangent":{"$ref":"125"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":121},"$type":"TransformData"},"CurvePointTangent":{"$ref":"126"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-10,"y":0,"z":135},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"139"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-10,"y":0,"z":135},"$type":"TransformData"},"CurveParent":{"$ref":"139"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-10,"y":0,"z":135},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"151"},"customOut":{"$id":"152"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"151"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"152"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-10,"y":0,"z":136},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"163"},"customOut":{"$id":"164"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"163"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"164"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":0,"z":390},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"198"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":390},"$type":"TransformData"},"CurveParent":{"$ref":"198"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":390},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"210"},"customOut":{"$id":"211"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"210"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"211"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":541},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"222"},"customOut":{"$id":"223"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":541},"$type":"TransformData"},"CurvePointTangent":{"$ref":"222"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":541},"$type":"TransformData"},"CurvePointTangent":{"$ref":"223"}},"children":[]}]}]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":26.2,"z":570},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":26.2,"z":570},"$type":"TransformData"}},"children":[]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":660},"$type":"TransformData"}},"children":[]}]},{"name":"coins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"262"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurveParent":{"$ref":"262"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"274"},"customOut":{"$id":"275"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurvePointTangent":{"$ref":"274"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"CurvePointTangent":{"$ref":"275"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":61},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"286"},"customOut":{"$id":"287"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":61},"$type":"TransformData"},"CurvePointTangent":{"$ref":"286"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":61},"$type":"TransformData"},"CurvePointTangent":{"$ref":"287"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"300"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"CurveParent":{"$ref":"300"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"312"},"customOut":{"$id":"313"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"CurvePointTangent":{"$ref":"312"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"CurvePointTangent":{"$ref":"313"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":151},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"324"},"customOut":{"$id":"325"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":151},"$type":"TransformData"},"CurvePointTangent":{"$ref":"324"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":151},"$type":"TransformData"},"CurvePointTangent":{"$ref":"325"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"338"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"CurveParent":{"$ref":"338"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"350"},"customOut":{"$id":"351"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"350"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"351"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":241},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"362"},"customOut":{"$id":"363"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"362"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"363"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"376"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurveParent":{"$ref":"376"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"388"},"customOut":{"$id":"389"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"388"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"389"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":271},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"400"},"customOut":{"$id":"401"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"400"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"401"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"414"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurveParent":{"$ref":"414"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"426"},"customOut":{"$id":"427"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"426"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"427"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":301},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"438"},"customOut":{"$id":"439"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"438"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"439"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"452"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurveParent":{"$ref":"452"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"464"},"customOut":{"$id":"465"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"464"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"465"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":331},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"476"},"customOut":{"$id":"477"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"476"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"477"}},"children":[]}]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":390},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":630},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":true,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":630},"$type":"TransformData"}},"children":[]}]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":-30,"y":0,"z":690},"$type":"TransformData"}},"children":[]}]},"routeChunk_default_train_tops_1":{"name":"routeChunk_default_train_tops_1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":10,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"},{"$id":"23"},{"$id":"24"},{"$id":"25"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_train_tops_1","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_end","components":{"Transform":{"position":{"x":0,"y":0,"z":-900},"$type":"TransformData"}},"children":[{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":-900},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":75},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"39"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":75},"$type":"TransformData"},"CurveParent":{"$ref":"39"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":75},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"51"},"customOut":{"$id":"52"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":75},"$type":"TransformData"},"CurvePointTangent":{"$ref":"51"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":75},"$type":"TransformData"},"CurvePointTangent":{"$ref":"52"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":76},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"63"},"customOut":{"$id":"64"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":76},"$type":"TransformData"},"CurvePointTangent":{"$ref":"63"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":76},"$type":"TransformData"},"CurvePointTangent":{"$ref":"64"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":105},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"77"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":105},"$type":"TransformData"},"CurveParent":{"$ref":"77"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":105},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"89"},"customOut":{"$id":"90"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"89"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"90"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":106},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"101"},"customOut":{"$id":"102"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":106},"$type":"TransformData"},"CurvePointTangent":{"$ref":"101"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":106},"$type":"TransformData"},"CurvePointTangent":{"$ref":"102"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":135},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"124"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":135},"$type":"TransformData"},"CurveParent":{"$ref":"124"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":135},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"136"},"customOut":{"$id":"137"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"136"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"137"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":136},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"148"},"customOut":{"$id":"149"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"148"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"149"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"173"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"173"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"185"},"customOut":{"$id":"186"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"185"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"186"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":166},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"197"},"customOut":{"$id":"198"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"197"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"198"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"211"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"211"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"223"},"customOut":{"$id":"224"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"223"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"224"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":166},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"235"},"customOut":{"$id":"236"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"235"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"236"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":195},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"249"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":195},"$type":"TransformData"},"CurveParent":{"$ref":"249"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":195},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"261"},"customOut":{"$id":"262"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"261"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"262"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":196},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"273"},"customOut":{"$id":"274"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"273"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"274"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":225},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"287"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":225},"$type":"TransformData"},"CurveParent":{"$ref":"287"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":225},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"299"},"customOut":{"$id":"300"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"299"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"300"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":226},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"311"},"customOut":{"$id":"312"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"311"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"312"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"325"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"325"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"337"},"customOut":{"$id":"338"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"337"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"338"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"349"},"customOut":{"$id":"350"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"349"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"350"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"363"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"363"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"375"},"customOut":{"$id":"376"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"375"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"376"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"387"},"customOut":{"$id":"388"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"387"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"388"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"409"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"409"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"421"},"customOut":{"$id":"422"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"421"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"422"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"433"},"customOut":{"$id":"434"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"433"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"434"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":330},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":360},"$type":"TransformData"}},"children":[]}]},{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":-900},"$type":"TransformData"},"Randomizer":{"$ref":"13"}},"children":[{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":-900},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":540},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":29,"z":540},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"489"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.84,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":540},"$type":"TransformData"},"CurveParent":{"$ref":"489"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":540},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"501"},"customOut":{"$id":"502"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":540},"$type":"TransformData"},"CurvePointTangent":{"$ref":"501"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":109,"z":638.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"502"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":638.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"513"},"customOut":{"$id":"514"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":109,"z":540},"$type":"TransformData"},"CurvePointTangent":{"$ref":"513"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":638.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"514"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":29,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"527"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"527"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"539"},"customOut":{"$id":"540"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"539"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":109,"z":683.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"540"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":683.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"551"},"customOut":{"$id":"552"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":109,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"551"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":683.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"552"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":660},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":-900},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":300},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":540},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":29,"z":540},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"598"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.82,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":540},"$type":"TransformData"},"CurveParent":{"$ref":"598"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":540},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"610"},"customOut":{"$id":"611"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":540},"$type":"TransformData"},"CurvePointTangent":{"$ref":"610"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":109,"z":638.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"611"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":638.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"622"},"customOut":{"$id":"623"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":109,"z":540},"$type":"TransformData"},"CurvePointTangent":{"$ref":"622"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":638.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"623"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":780},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":29,"z":780},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"644"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.85,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":780},"$type":"TransformData"},"CurveParent":{"$ref":"644"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":780},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"656"},"customOut":{"$id":"657"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":780},"$type":"TransformData"},"CurvePointTangent":{"$ref":"656"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":109,"z":878.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"657"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":878.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"668"},"customOut":{"$id":"669"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":109,"z":780},"$type":"TransformData"},"CurvePointTangent":{"$ref":"668"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":878.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"669"}},"children":[]}]}]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":0,"y":35.8,"z":210},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":35.8,"z":210},"$type":"TransformData"}},"children":[]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":-20,"y":7,"z":570},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":570},"$type":"TransformData"}},"children":[]}]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":10,"y":0,"z":630},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":720},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":720},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":47,"z":855},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":47,"z":855},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_train_tops_2":{"name":"routeChunk_default_train_tops_2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":10,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"},{"$id":"23"},{"$id":"24"},{"$id":"25"},{"$id":"26"},{"$id":"27"},{"$id":"28"},{"$id":"29"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_train_tops_2","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"random_trains","components":{"Transform":{"position":{"x":0,"y":0,"z":-30},"$type":"TransformData"},"Randomizer":{"$ref":"10"}},"children":[{"name":"trains_mid2left","components":{"Transform":{"position":{"x":0,"y":0,"z":-30},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":0,"y":29,"z":-30},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":29,"z":735},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"45"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":735},"$type":"TransformData"},"CurveParent":{"$ref":"45"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":735},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"57"},"customOut":{"$id":"58"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"57"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"58"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":736},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"69"},"customOut":{"$id":"70"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"69"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"70"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":29,"z":765},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"83"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":765},"$type":"TransformData"},"CurveParent":{"$ref":"83"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":765},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"95"},"customOut":{"$id":"96"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":765},"$type":"TransformData"},"CurvePointTangent":{"$ref":"95"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":765},"$type":"TransformData"},"CurvePointTangent":{"$ref":"96"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":766},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"107"},"customOut":{"$id":"108"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":766},"$type":"TransformData"},"CurvePointTangent":{"$ref":"107"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":766},"$type":"TransformData"},"CurvePointTangent":{"$ref":"108"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":29,"z":795},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"121"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":795},"$type":"TransformData"},"CurveParent":{"$ref":"121"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":795},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"133"},"customOut":{"$id":"134"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":795},"$type":"TransformData"},"CurvePointTangent":{"$ref":"133"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":795},"$type":"TransformData"},"CurvePointTangent":{"$ref":"134"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":796},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"145"},"customOut":{"$id":"146"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":796},"$type":"TransformData"},"CurvePointTangent":{"$ref":"145"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":796},"$type":"TransformData"},"CurvePointTangent":{"$ref":"146"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":29,"z":825},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"159"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":825},"$type":"TransformData"},"CurveParent":{"$ref":"159"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":825},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"171"},"customOut":{"$id":"172"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":825},"$type":"TransformData"},"CurvePointTangent":{"$ref":"171"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":825},"$type":"TransformData"},"CurvePointTangent":{"$ref":"172"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":826},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"183"},"customOut":{"$id":"184"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":826},"$type":"TransformData"},"CurvePointTangent":{"$ref":"183"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":826},"$type":"TransformData"},"CurvePointTangent":{"$ref":"184"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":29,"z":855},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"197"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":855},"$type":"TransformData"},"CurveParent":{"$ref":"197"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":855},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"209"},"customOut":{"$id":"210"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":855},"$type":"TransformData"},"CurvePointTangent":{"$ref":"209"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":855},"$type":"TransformData"},"CurvePointTangent":{"$ref":"210"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":856},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"221"},"customOut":{"$id":"222"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":856},"$type":"TransformData"},"CurvePointTangent":{"$ref":"221"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":856},"$type":"TransformData"},"CurvePointTangent":{"$ref":"222"}},"children":[]}]}]}]}]},{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":-30},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":420},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":570},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"259"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.5,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":570},"$type":"TransformData"},"CurveParent":{"$ref":"259"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":570},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"271"},"customOut":{"$id":"272"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":570},"$type":"TransformData"},"CurvePointTangent":{"$ref":"271"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":668.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"272"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":668.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"283"},"customOut":{"$id":"284"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":570},"$type":"TransformData"},"CurvePointTangent":{"$ref":"283"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":668.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"284"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":600},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":780},"$type":"TransformData"}},"children":[]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":37,"z":165},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":37,"z":165},"$type":"TransformData"}},"children":[]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":390},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":29,"z":405},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"357"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":405},"$type":"TransformData"},"CurveParent":{"$ref":"357"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":405},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"369"},"customOut":{"$id":"370"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":405},"$type":"TransformData"},"CurvePointTangent":{"$ref":"369"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":109,"z":503.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"370"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":503.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"381"},"customOut":{"$id":"382"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":109,"z":405},"$type":"TransformData"},"CurvePointTangent":{"$ref":"381"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":503.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"382"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":690},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":-20,"y":7,"z":855},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":855},"$type":"TransformData"}},"children":[]}]}]},{"name":"trains_sides2mid","components":{"Transform":{"position":{"x":0,"y":0,"z":-30},"$type":"TransformData"}},"children":[{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":-30},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":150},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":195},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"462"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":195},"$type":"TransformData"},"CurveParent":{"$ref":"462"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":195},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"474"},"customOut":{"$id":"475"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"474"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"475"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":196},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"486"},"customOut":{"$id":"487"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"486"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"487"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":225},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"500"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":225},"$type":"TransformData"},"CurveParent":{"$ref":"500"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":225},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"512"},"customOut":{"$id":"513"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"512"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"513"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":226},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"524"},"customOut":{"$id":"525"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"524"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"525"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"538"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"538"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"550"},"customOut":{"$id":"551"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"550"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"551"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"562"},"customOut":{"$id":"563"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"562"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"563"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"576"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"576"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"588"},"customOut":{"$id":"589"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"588"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"589"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"600"},"customOut":{"$id":"601"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"600"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"601"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"614"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"614"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"626"},"customOut":{"$id":"627"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"626"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"627"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"638"},"customOut":{"$id":"639"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"638"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"639"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"652"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"652"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"664"},"customOut":{"$id":"665"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"664"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"665"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":346},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"676"},"customOut":{"$id":"677"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"676"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"677"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":420},"$type":"TransformData"}},"children":[]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":420},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":450},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":-20,"y":37,"z":450},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":37,"z":450},"$type":"TransformData"}},"children":[]}]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":600},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":29,"z":660},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"748"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.5,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":660},"$type":"TransformData"},"CurveParent":{"$ref":"748"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":660},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"760"},"customOut":{"$id":"761"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":660},"$type":"TransformData"},"CurvePointTangent":{"$ref":"760"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":109,"z":758.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"761"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":758.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"772"},"customOut":{"$id":"773"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":109,"z":660},"$type":"TransformData"},"CurvePointTangent":{"$ref":"772"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":758.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"773"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":690},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":780},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":0,"y":55,"z":870},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":55,"z":870},"$type":"TransformData"}},"children":[]}]}]}]}]},"routeChunk_default_tunnel_notrain":{"name":"routeChunk_default_tunnel_notrain","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":4,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Gates,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"7"},{"$id":"8"},{"$id":"9"},{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_tunnel_notrain","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"random_tunnel","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"7"}},"children":[{"name":"mid","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"gates_mid_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]}]},{"name":"left","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"gates_left_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":30},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":-20,"y":64.60001,"z":210},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":64.60001,"z":210},"$type":"TransformData"}},"children":[]}]}]},{"name":"sides","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"gates_sides_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":0,"z":75},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"86"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":75},"$type":"TransformData"},"CurveParent":{"$ref":"86"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":75},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"98"},"customOut":{"$id":"99"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":75},"$type":"TransformData"},"CurvePointTangent":{"$ref":"98"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":75},"$type":"TransformData"},"CurvePointTangent":{"$ref":"99"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":176},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"110"},"customOut":{"$id":"111"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"110"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"111"}},"children":[]}]}]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":-20,"y":7,"z":195},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":195},"$type":"TransformData"}},"children":[]}]}]}]},{"name":"right","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"gates_right_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":30},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":0,"y":64.60001,"z":210},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":64.60001,"z":210},"$type":"TransformData"}},"children":[]}]}]}]}]},"Short2Tracks":{"name":"Short2Tracks","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"routeChunk_default_short_2_tracks_end","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":2,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_short_2_tracks_end","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"environment_base","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"EnvironmentBase":{"_type":"Tracks","_numTracks":2,"_blockCount":2,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":135},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":135},"$type":"TransformData"}},"children":[]}]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[]}]},{"name":"routeChunk_default_short_2_tracks_mid_var_1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":10,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"45"},{"$id":"46"},{"$id":"47"},{"$id":"48"},{"$id":"49"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_short_2_tracks_mid_var_1","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"pillars_short","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":38},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"70"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"70"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"82"},"customOut":{"$id":"83"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"82"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"83"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"94"},"customOut":{"$id":"95"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"94"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"95"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"108"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"108"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"120"},"customOut":{"$id":"121"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"120"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"121"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"132"},"customOut":{"$id":"133"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"132"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"133"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"146"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"146"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"158"},"customOut":{"$id":"159"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"158"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"159"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"170"},"customOut":{"$id":"171"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"170"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"171"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"184"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"184"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"196"},"customOut":{"$id":"197"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"196"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"197"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"208"},"customOut":{"$id":"209"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"208"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"209"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"222"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurveParent":{"$ref":"222"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"234"},"customOut":{"$id":"235"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"234"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"235"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":376},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"246"},"customOut":{"$id":"247"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":376},"$type":"TransformData"},"CurvePointTangent":{"$ref":"246"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":376},"$type":"TransformData"},"CurvePointTangent":{"$ref":"247"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":397},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":410},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"279"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"279"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"291"},"customOut":{"$id":"292"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"291"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"292"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"303"},"customOut":{"$id":"304"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"303"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"304"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":615},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"317"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":615},"$type":"TransformData"},"CurveParent":{"$ref":"317"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":615},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"329"},"customOut":{"$id":"330"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":615},"$type":"TransformData"},"CurvePointTangent":{"$ref":"329"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":615},"$type":"TransformData"},"CurvePointTangent":{"$ref":"330"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":616},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"341"},"customOut":{"$id":"342"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":616},"$type":"TransformData"},"CurvePointTangent":{"$ref":"341"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":616},"$type":"TransformData"},"CurvePointTangent":{"$ref":"342"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":645},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"355"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":645},"$type":"TransformData"},"CurveParent":{"$ref":"355"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":645},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"367"},"customOut":{"$id":"368"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":645},"$type":"TransformData"},"CurvePointTangent":{"$ref":"367"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":645},"$type":"TransformData"},"CurvePointTangent":{"$ref":"368"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":646},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"379"},"customOut":{"$id":"380"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":646},"$type":"TransformData"},"CurvePointTangent":{"$ref":"379"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":646},"$type":"TransformData"},"CurvePointTangent":{"$ref":"380"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"393"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurveParent":{"$ref":"393"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"405"},"customOut":{"$id":"406"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePointTangent":{"$ref":"405"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePointTangent":{"$ref":"406"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"417"},"customOut":{"$id":"418"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePointTangent":{"$ref":"417"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePointTangent":{"$ref":"418"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"431"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurveParent":{"$ref":"431"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"443"},"customOut":{"$id":"444"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePointTangent":{"$ref":"443"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePointTangent":{"$ref":"444"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"455"},"customOut":{"$id":"456"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePointTangent":{"$ref":"455"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePointTangent":{"$ref":"456"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"469"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurveParent":{"$ref":"469"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"481"},"customOut":{"$id":"482"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"481"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"482"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"493"},"customOut":{"$id":"494"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"493"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"494"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":756},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":770},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"525"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurveParent":{"$ref":"525"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"537"},"customOut":{"$id":"538"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"537"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"538"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"549"},"customOut":{"$id":"550"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"549"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"550"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"563"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurveParent":{"$ref":"563"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"575"},"customOut":{"$id":"576"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"575"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"576"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"587"},"customOut":{"$id":"588"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePointTangent":{"$ref":"587"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePointTangent":{"$ref":"588"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"601"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurveParent":{"$ref":"601"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"613"},"customOut":{"$id":"614"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"613"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"614"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"625"},"customOut":{"$id":"626"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePointTangent":{"$ref":"625"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePointTangent":{"$ref":"626"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"639"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"CurveParent":{"$ref":"639"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"651"},"customOut":{"$id":"652"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"CurvePointTangent":{"$ref":"651"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"CurvePointTangent":{"$ref":"652"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":976},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"663"},"customOut":{"$id":"664"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":976},"$type":"TransformData"},"CurvePointTangent":{"$ref":"663"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":976},"$type":"TransformData"},"CurvePointTangent":{"$ref":"664"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1005},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"677"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1005},"$type":"TransformData"},"CurveParent":{"$ref":"677"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1005},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"689"},"customOut":{"$id":"690"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1005},"$type":"TransformData"},"CurvePointTangent":{"$ref":"689"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1005},"$type":"TransformData"},"CurvePointTangent":{"$ref":"690"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1006},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"701"},"customOut":{"$id":"702"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1006},"$type":"TransformData"},"CurvePointTangent":{"$ref":"701"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1006},"$type":"TransformData"},"CurvePointTangent":{"$ref":"702"}},"children":[]}]}]}]}]},{"name":"environments","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"pillars_environment","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Pillars,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"}},"children":[]},{"name":"pillars_environment (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Pillars,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"}},"children":[]},{"name":"pillars_environment (2)","components":{"Transform":{"position":{"x":0,"y":0,"z":720},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Pillars,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"}},"children":[]}]},{"name":"environment_base","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"EnvironmentBase":{"_type":"Tracks","_numTracks":2,"_blockCount":10,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]}]},{"name":"routeChunk_default_short_2_tracks_mid_var_2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":10,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"741"},{"$id":"742"},{"$id":"743"},{"$id":"744"},{"$id":"745"},{"$id":"746"},{"$id":"747"},{"$id":"748"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_short_2_tracks_mid_var_2","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"pillars_long","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"roof_setup","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[{"name":"subway","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[]},{"name":"roof","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":210},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"772"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":210},"$type":"TransformData"},"CurveParent":{"$ref":"772"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":210},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"784"},"customOut":{"$id":"785"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"784"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"785"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":361},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"796"},"customOut":{"$id":"797"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"796"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"797"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":390},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"810"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":390},"$type":"TransformData"},"CurveParent":{"$ref":"810"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":390},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"822"},"customOut":{"$id":"823"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"822"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"823"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":541},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"834"},"customOut":{"$id":"835"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":541},"$type":"TransformData"},"CurvePointTangent":{"$ref":"834"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":541},"$type":"TransformData"},"CurvePointTangent":{"$ref":"835"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":570},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"848"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":570},"$type":"TransformData"},"CurveParent":{"$ref":"848"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":570},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"860"},"customOut":{"$id":"861"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":570},"$type":"TransformData"},"CurvePointTangent":{"$ref":"860"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":570},"$type":"TransformData"},"CurvePointTangent":{"$ref":"861"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":721},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"872"},"customOut":{"$id":"873"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":721},"$type":"TransformData"},"CurvePointTangent":{"$ref":"872"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":721},"$type":"TransformData"},"CurvePointTangent":{"$ref":"873"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":750},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"886"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":750},"$type":"TransformData"},"CurveParent":{"$ref":"886"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":750},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"898"},"customOut":{"$id":"899"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":750},"$type":"TransformData"},"CurvePointTangent":{"$ref":"898"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":750},"$type":"TransformData"},"CurvePointTangent":{"$ref":"899"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":901},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"910"},"customOut":{"$id":"911"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":901},"$type":"TransformData"},"CurvePointTangent":{"$ref":"910"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":901},"$type":"TransformData"},"CurvePointTangent":{"$ref":"911"}},"children":[]}]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":251},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"942"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"942"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"954"},"customOut":{"$id":"955"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"954"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"955"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"966"},"customOut":{"$id":"967"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"966"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"967"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"980"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"980"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"992"},"customOut":{"$id":"993"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"992"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"993"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1004"},"customOut":{"$id":"1005"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1004"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1005"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1018"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurveParent":{"$ref":"1018"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1030"},"customOut":{"$id":"1031"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1030"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1031"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":376},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1042"},"customOut":{"$id":"1043"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":376},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1042"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":376},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1043"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":405},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1056"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":405},"$type":"TransformData"},"CurveParent":{"$ref":"1056"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":405},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1068"},"customOut":{"$id":"1069"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":405},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1068"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":405},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1069"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":406},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1080"},"customOut":{"$id":"1081"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":406},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1080"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":406},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1081"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":431},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":450},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1112"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurveParent":{"$ref":"1112"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1124"},"customOut":{"$id":"1125"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1124"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1125"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":496},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1136"},"customOut":{"$id":"1137"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":496},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1136"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":496},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1137"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1150"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurveParent":{"$ref":"1150"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1162"},"customOut":{"$id":"1163"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1162"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1163"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":526},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1174"},"customOut":{"$id":"1175"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":526},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1174"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":526},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1175"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1188"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurveParent":{"$ref":"1188"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1200"},"customOut":{"$id":"1201"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1200"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1201"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":556},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1212"},"customOut":{"$id":"1213"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":556},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1212"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":556},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1213"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1226"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"1226"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1238"},"customOut":{"$id":"1239"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1238"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1239"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1250"},"customOut":{"$id":"1251"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1250"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1251"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":611},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":630},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1282"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurveParent":{"$ref":"1282"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1294"},"customOut":{"$id":"1295"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1294"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1295"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1306"},"customOut":{"$id":"1307"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1306"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1307"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1320"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurveParent":{"$ref":"1320"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1332"},"customOut":{"$id":"1333"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1332"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1333"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1344"},"customOut":{"$id":"1345"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1344"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1345"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1358"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurveParent":{"$ref":"1358"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1370"},"customOut":{"$id":"1371"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1370"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1371"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1382"},"customOut":{"$id":"1383"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1382"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1383"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":765},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1396"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":765},"$type":"TransformData"},"CurveParent":{"$ref":"1396"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":765},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1408"},"customOut":{"$id":"1409"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":765},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1408"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":765},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1409"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":766},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1420"},"customOut":{"$id":"1421"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":766},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1420"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":766},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1421"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":791},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":810},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":855},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1452"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":855},"$type":"TransformData"},"CurveParent":{"$ref":"1452"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":855},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1464"},"customOut":{"$id":"1465"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":855},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1464"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":855},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1465"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":856},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1476"},"customOut":{"$id":"1477"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":856},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1476"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":856},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1477"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1490"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurveParent":{"$ref":"1490"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1502"},"customOut":{"$id":"1503"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1502"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1503"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1514"},"customOut":{"$id":"1515"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1514"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1515"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1528"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurveParent":{"$ref":"1528"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1540"},"customOut":{"$id":"1541"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1540"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1541"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1552"},"customOut":{"$id":"1553"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1552"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1553"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1566"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurveParent":{"$ref":"1566"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1578"},"customOut":{"$id":"1579"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1578"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1579"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1590"},"customOut":{"$id":"1591"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1590"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1591"}},"children":[]}]}]}]}]},{"name":"environments","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"station_environment","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Pillars,All","_density":""},"_blockCount":8,"$type":"SYBO.Subway.Level.Environment"}},"children":[]}]},{"name":"environment_base","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"EnvironmentBase":{"_type":"Tracks","_numTracks":2,"_blockCount":10,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]}]},{"name":"routeChunk_default_short_2_tracks_start","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":2,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"1618"},{"$id":"1619"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_short_2_tracks_start","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":0,"y":7,"z":165},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":165},"$type":"TransformData"}},"children":[]}]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_ramp_2":{"name":"routeChunk_default_ramp_2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":2,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_ramp_2","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":30},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":35.8,"z":120},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":35.8,"z":120},"$type":"TransformData"}},"children":[]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":36,"z":165},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":36,"z":165},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_short_1_track":{"name":"routeChunk_default_short_1_track","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":14,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"7"},{"$id":"8"},{"$id":"9"},{"$id":"10"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_short_1_track","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"random_coins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"11"}},"children":[{"name":"3","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":275},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"35"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"35"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"47"},"customOut":{"$id":"48"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"47"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"48"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"59"},"customOut":{"$id":"60"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"59"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"60"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":275},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"73"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"73"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"85"},"customOut":{"$id":"86"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"85"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"86"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":860},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"97"},"customOut":{"$id":"98"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"97"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"98"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":8.8,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":275},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"111"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":8.8,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"111"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"123"},"customOut":{"$id":"124"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"123"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"124"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"135"},"customOut":{"$id":"136"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"135"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"136"}},"children":[]}]}]}]}]},{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":275},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"152"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"152"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"164"},"customOut":{"$id":"165"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"164"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"165"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":860},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"176"},"customOut":{"$id":"177"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"176"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"177"}},"children":[]}]}]}]}]},{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":275},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"193"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"193"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"205"},"customOut":{"$id":"206"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"205"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"206"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"217"},"customOut":{"$id":"218"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"217"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"218"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":8.8,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":275},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"231"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":8.8,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"231"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"243"},"customOut":{"$id":"244"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"243"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":8.8,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"244"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"255"},"customOut":{"$id":"256"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"255"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":8.8,"z":860},"$type":"TransformData"},"CurvePointTangent":{"$ref":"256"}},"children":[]}]}]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":323},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"station_platforms_extended_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":540},"$type":"TransformData"}},"children":[]},{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":958},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"end_coins","components":{"Transform":{"position":{"x":0,"y":0,"z":990},"$type":"TransformData"}},"children":[{"name":"obstacle_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1080},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":0,"z":1080},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"311"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.5,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":1080},"$type":"TransformData"},"CurveParent":{"$ref":"311"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":1080},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"323"},"customOut":{"$id":"324"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":1080},"$type":"TransformData"},"CurvePointTangent":{"$ref":"323"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":80,"z":1178.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"324"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":1178.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"335"},"customOut":{"$id":"336"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":80,"z":1080},"$type":"TransformData"},"CurvePointTangent":{"$ref":"335"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":1178.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"336"}},"children":[]}]}]}]},{"name":"obstacle_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1110},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":0,"z":1110},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"356"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.5,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":1110},"$type":"TransformData"},"CurveParent":{"$ref":"356"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":1110},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"368"},"customOut":{"$id":"369"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":1110},"$type":"TransformData"},"CurvePointTangent":{"$ref":"368"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":80,"z":1208.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"369"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":1208.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"380"},"customOut":{"$id":"381"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":80,"z":1110},"$type":"TransformData"},"CurvePointTangent":{"$ref":"380"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":1208.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"381"}},"children":[]}]}]}]}]}]},{"name":"environments","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"station_environment","components":{"Transform":{"position":{"x":0,"y":0,"z":540},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Station,All","_density":""},"_blockCount":4,"$type":"SYBO.Subway.Level.Environment"}},"children":[]}]},{"name":"start","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":0,"y":0,"z":-180.6776},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":29.32239},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"410"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":29.32239},"$type":"TransformData"},"CurveParent":{"$ref":"410"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":29.32239},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"422"},"customOut":{"$id":"423"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":29.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"422"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":29.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"423"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":30.32239},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"434"},"customOut":{"$id":"435"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":30.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"434"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":30.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"435"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":59.32239},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"448"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":59.32239},"$type":"TransformData"},"CurveParent":{"$ref":"448"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":59.32239},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"460"},"customOut":{"$id":"461"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":59.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"460"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":59.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"461"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":60.32239},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"472"},"customOut":{"$id":"473"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":60.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"472"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":60.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"473"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":89.32239},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"486"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":89.32239},"$type":"TransformData"},"CurveParent":{"$ref":"486"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":89.32239},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"498"},"customOut":{"$id":"499"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":89.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"498"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":89.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"499"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":90.32239},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"510"},"customOut":{"$id":"511"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":90.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"510"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":90.32239},"$type":"TransformData"},"CurvePointTangent":{"$ref":"511"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":119.3224},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":119.3224},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"533"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":119.3224},"$type":"TransformData"},"CurveParent":{"$ref":"533"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":119.3224},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"545"},"customOut":{"$id":"546"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":119.3224},"$type":"TransformData"},"CurvePointTangent":{"$ref":"545"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":119.3224},"$type":"TransformData"},"CurvePointTangent":{"$ref":"546"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":120.3224},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"557"},"customOut":{"$id":"558"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":120.3224},"$type":"TransformData"},"CurvePointTangent":{"$ref":"557"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":120.3224},"$type":"TransformData"},"CurvePointTangent":{"$ref":"558"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":149.3224},"$type":"TransformData"}},"children":[]},{"name":"obstacle_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":329.3224},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":0,"z":329.3224},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"586"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.5,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":329.3224},"$type":"TransformData"},"CurveParent":{"$ref":"586"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":329.3224},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"598"},"customOut":{"$id":"599"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":329.3224},"$type":"TransformData"},"CurvePointTangent":{"$ref":"598"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":80,"z":427.7094},"$type":"TransformData"},"CurvePointTangent":{"$ref":"599"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":427.7094},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"610"},"customOut":{"$id":"611"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":80,"z":329.3224},"$type":"TransformData"},"CurvePointTangent":{"$ref":"610"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":427.7094},"$type":"TransformData"},"CurvePointTangent":{"$ref":"611"}},"children":[]}]}]}]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":60},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":60},"$type":"TransformData"}},"children":[]}]}]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"}},"children":[]},{"name":"environment_base","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"EnvironmentBase":{"_type":"Tracks","_numTracks":1,"_blockCount":12,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":-20,"y":26.2,"z":495},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":26.2,"z":495},"$type":"TransformData"}},"children":[]}]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1260},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1260},"$type":"TransformData"}},"children":[]}]},"routeChunk_default_short_train_tops_moving":{"name":"routeChunk_default_short_train_tops_moving","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":12,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Epic,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"7"},{"$id":"8"},{"$id":"9"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$id":"11"},{"$id":"12"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"},{"$id":"23"},{"$id":"24"},{"$id":"25"},{"$id":"26"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_short_train_tops_moving","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":46},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_side","components":{"Transform":{"position":{"x":20,"y":0,"z":75.28589},"$type":"TransformData"}},"children":[{"name":"randomizer","components":{"Transform":{"position":{"x":20,"y":0,"z":-59.71411},"$type":"TransformData"},"Randomizer":{"$ref":"10"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":20,"y":0,"z":75.28589},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":135.2859},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":180.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"62"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":180.2859},"$type":"TransformData"},"CurveParent":{"$ref":"62"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":180.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"74"},"customOut":{"$id":"75"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":180.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"74"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":278.6729},"$type":"TransformData"},"CurvePointTangent":{"$ref":"75"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":278.6729},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"86"},"customOut":{"$id":"87"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":180.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"86"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":278.6729},"$type":"TransformData"},"CurvePointTangent":{"$ref":"87"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":255.2859},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"group","components":{"Transform":{"position":{"x":20,"y":0,"z":75.28589},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":135.2859},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":375.2859},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":375.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"132"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.8,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":375.2859},"$type":"TransformData"},"CurveParent":{"$ref":"132"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":375.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"144"},"customOut":{"$id":"145"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":375.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"144"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":473.6729},"$type":"TransformData"},"CurvePointTangent":{"$ref":"145"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":473.6729},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"156"},"customOut":{"$id":"157"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":375.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"156"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":473.6729},"$type":"TransformData"},"CurvePointTangent":{"$ref":"157"}},"children":[]}]}]}]}]},{"name":"group","components":{"Transform":{"position":{"x":20,"y":0,"z":75.28589},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":20,"y":29,"z":75.28589},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":150.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"176"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":150.2859},"$type":"TransformData"},"CurveParent":{"$ref":"176"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":150.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"188"},"customOut":{"$id":"189"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":150.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"188"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":150.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"189"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":151.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"200"},"customOut":{"$id":"201"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":151.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"200"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":151.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"201"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":180.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"214"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":180.2859},"$type":"TransformData"},"CurveParent":{"$ref":"214"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":180.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"226"},"customOut":{"$id":"227"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":180.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"226"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":180.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"227"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":181.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"238"},"customOut":{"$id":"239"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":181.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"238"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":181.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"239"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":210.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"252"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":210.2859},"$type":"TransformData"},"CurveParent":{"$ref":"252"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":210.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"264"},"customOut":{"$id":"265"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":210.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"264"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":210.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"265"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":211.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"276"},"customOut":{"$id":"277"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":211.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"276"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":211.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"277"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":240.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"290"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":240.2859},"$type":"TransformData"},"CurveParent":{"$ref":"290"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":240.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"302"},"customOut":{"$id":"303"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":240.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"302"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":240.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"303"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":241.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"314"},"customOut":{"$id":"315"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":241.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"314"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":241.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"315"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":270.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"328"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":270.2859},"$type":"TransformData"},"CurveParent":{"$ref":"328"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":270.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"340"},"customOut":{"$id":"341"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":270.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"340"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":270.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"341"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":271.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"352"},"customOut":{"$id":"353"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":271.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"352"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":271.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"353"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":300.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"366"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":300.2859},"$type":"TransformData"},"CurveParent":{"$ref":"366"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":300.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"378"},"customOut":{"$id":"379"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":300.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"378"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":300.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"379"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":301.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"390"},"customOut":{"$id":"391"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":301.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"390"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":301.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"391"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":330.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"404"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":330.2859},"$type":"TransformData"},"CurveParent":{"$ref":"404"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":330.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"416"},"customOut":{"$id":"417"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":330.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"416"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":330.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"417"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":331.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"428"},"customOut":{"$id":"429"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":331.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"428"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":331.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"429"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":360.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"442"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":360.2859},"$type":"TransformData"},"CurveParent":{"$ref":"442"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":360.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"454"},"customOut":{"$id":"455"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":360.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"454"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":360.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"455"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":361.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"466"},"customOut":{"$id":"467"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":361.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"466"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":361.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"467"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":390.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"480"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":390.2859},"$type":"TransformData"},"CurveParent":{"$ref":"480"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":390.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"492"},"customOut":{"$id":"493"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":390.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"492"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":390.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"493"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":391.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"504"},"customOut":{"$id":"505"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":391.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"504"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":391.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"505"}},"children":[]}]}]}]}]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":135.2859},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":105.2859},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":225.2859},"$type":"TransformData"}},"children":[]}]},{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":401},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_side","components":{"Transform":{"position":{"x":-20,"y":0,"z":495.2859},"$type":"TransformData"}},"children":[{"name":"randomizer","components":{"Transform":{"position":{"x":-20,"y":0,"z":360.2859},"$type":"TransformData"},"Randomizer":{"$ref":"13"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":495.2859},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":555.2859},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":600.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"574"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":600.2859},"$type":"TransformData"},"CurveParent":{"$ref":"574"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":600.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"586"},"customOut":{"$id":"587"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":600.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"586"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":698.6729},"$type":"TransformData"},"CurvePointTangent":{"$ref":"587"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":698.6729},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"598"},"customOut":{"$id":"599"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":600.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"598"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":698.6729},"$type":"TransformData"},"CurvePointTangent":{"$ref":"599"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":675.2859},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":495.2859},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":555.2859},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":795.2859},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":795.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"643"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.8,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":795.2859},"$type":"TransformData"},"CurveParent":{"$ref":"643"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":795.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"655"},"customOut":{"$id":"656"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":795.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"655"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":893.6729},"$type":"TransformData"},"CurvePointTangent":{"$ref":"656"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":893.6729},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"667"},"customOut":{"$id":"668"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":795.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"667"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":893.6729},"$type":"TransformData"},"CurvePointTangent":{"$ref":"668"}},"children":[]}]}]}]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":495.2859},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":-20,"y":29,"z":495.2859},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":570.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"687"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":570.2859},"$type":"TransformData"},"CurveParent":{"$ref":"687"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":570.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"699"},"customOut":{"$id":"700"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":570.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"699"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":570.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"700"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":571.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"711"},"customOut":{"$id":"712"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":571.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"711"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":571.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"712"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":600.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"725"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":600.2859},"$type":"TransformData"},"CurveParent":{"$ref":"725"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":600.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"737"},"customOut":{"$id":"738"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":600.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"737"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":600.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"738"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":601.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"749"},"customOut":{"$id":"750"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":601.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"749"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":601.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"750"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":630.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"763"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":630.2859},"$type":"TransformData"},"CurveParent":{"$ref":"763"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":630.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"775"},"customOut":{"$id":"776"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":630.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"775"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":630.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"776"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":631.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"787"},"customOut":{"$id":"788"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":631.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"787"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":631.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"788"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":660.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"801"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":660.2859},"$type":"TransformData"},"CurveParent":{"$ref":"801"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":660.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"813"},"customOut":{"$id":"814"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":660.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"813"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":660.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"814"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":661.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"825"},"customOut":{"$id":"826"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":661.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"825"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":661.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"826"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":690.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"839"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":690.2859},"$type":"TransformData"},"CurveParent":{"$ref":"839"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":690.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"851"},"customOut":{"$id":"852"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":690.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"851"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":690.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"852"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":691.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"863"},"customOut":{"$id":"864"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":691.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"863"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":691.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"864"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":720.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"877"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":720.2859},"$type":"TransformData"},"CurveParent":{"$ref":"877"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":720.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"889"},"customOut":{"$id":"890"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":720.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"889"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":720.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"890"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":721.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"901"},"customOut":{"$id":"902"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":721.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"901"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":721.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"902"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":750.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"915"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":750.2859},"$type":"TransformData"},"CurveParent":{"$ref":"915"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":750.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"927"},"customOut":{"$id":"928"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":750.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"927"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":750.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"928"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":751.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"939"},"customOut":{"$id":"940"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":751.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"939"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":751.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"940"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":780.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"953"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":780.2859},"$type":"TransformData"},"CurveParent":{"$ref":"953"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":780.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"965"},"customOut":{"$id":"966"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":780.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"965"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":780.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"966"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":781.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"977"},"customOut":{"$id":"978"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":781.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"977"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":781.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"978"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":810.2859},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"991"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":810.2859},"$type":"TransformData"},"CurveParent":{"$ref":"991"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":810.2859},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1003"},"customOut":{"$id":"1004"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":810.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1003"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":810.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1004"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":811.2859},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1015"},"customOut":{"$id":"1016"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":811.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1015"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":811.2859},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1016"}},"children":[]}]}]}]}]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":555.2859},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":525.2859},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":615.2859},"$type":"TransformData"}},"children":[]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":7,"z":570},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":7,"z":570},"$type":"TransformData"}},"children":[]}]},{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":820},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_side","components":{"Transform":{"position":{"x":20,"y":0,"z":915.2859},"$type":"TransformData"}},"children":[{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":975.2859},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_short_train_tops_moving_combined":{"name":"routeChunk_default_short_train_tops_moving_combined","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":12,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"11"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"23"},{"$id":"24"},{"$id":"25"},{"$id":"26"},{"$id":"27"},{"$id":"28"},{"$id":"29"},{"$id":"30"},{"$id":"31"},{"$id":"32"},{"$id":"33"},{"$id":"34"},{"$id":"35"},{"$id":"36"},{"$id":"37"},{"$id":"38"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_short_train_tops_moving_combined","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_start_end","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":150},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":900},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":29,"z":915},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"101"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":915},"$type":"TransformData"},"CurveParent":{"$ref":"101"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":915},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"113"},"customOut":{"$id":"114"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"113"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"114"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1066},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"125"},"customOut":{"$id":"126"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1066},"$type":"TransformData"},"CurvePointTangent":{"$ref":"125"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1066},"$type":"TransformData"},"CurvePointTangent":{"$ref":"126"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":960},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":55,"z":210},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":55,"z":210},"$type":"TransformData"}},"children":[]}]},{"name":"side","components":{"Transform":{"position":{"x":0,"y":0,"z":395.3984},"$type":"TransformData"},"Randomizer":{"$ref":"10"}},"children":[{"name":"trains_side_ground","components":{"Transform":{"position":{"x":0,"y":0,"z":395.3984},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":515.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":515.3984},"$type":"TransformData"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":665.3984},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":695.3984},"$type":"TransformData"}},"children":[]}]},{"name":"trains_side","components":{"Transform":{"position":{"x":0,"y":0,"z":395.3984},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"randomizer","components":{"Transform":{"position":{"x":-20,"y":0,"z":260.3984},"$type":"TransformData"},"Randomizer":{"$ref":"23"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":395.3984},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":455.3984},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":500.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"225"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":500.3984},"$type":"TransformData"},"CurveParent":{"$ref":"225"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":500.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"237"},"customOut":{"$id":"238"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":500.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"237"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":598.7854},"$type":"TransformData"},"CurvePointTangent":{"$ref":"238"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":598.7854},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"249"},"customOut":{"$id":"250"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":500.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"249"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":598.7854},"$type":"TransformData"},"CurvePointTangent":{"$ref":"250"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":575.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":395.3984},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":455.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":695.3984},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":695.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"294"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.8,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":695.3984},"$type":"TransformData"},"CurveParent":{"$ref":"294"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":695.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"306"},"customOut":{"$id":"307"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":695.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"306"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":793.7854},"$type":"TransformData"},"CurvePointTangent":{"$ref":"307"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":793.7854},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"318"},"customOut":{"$id":"319"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":695.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"318"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":793.7854},"$type":"TransformData"},"CurvePointTangent":{"$ref":"319"}},"children":[]}]}]}]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":395.3984},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":-20,"y":29,"z":395.3984},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":470.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"338"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":470.3984},"$type":"TransformData"},"CurveParent":{"$ref":"338"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":470.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"350"},"customOut":{"$id":"351"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":470.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"350"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":470.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"351"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":471.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"362"},"customOut":{"$id":"363"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":471.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"362"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":471.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"363"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":500.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"376"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":500.3984},"$type":"TransformData"},"CurveParent":{"$ref":"376"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":500.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"388"},"customOut":{"$id":"389"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":500.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"388"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":500.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"389"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":501.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"400"},"customOut":{"$id":"401"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":501.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"400"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":501.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"401"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":530.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"414"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":530.3984},"$type":"TransformData"},"CurveParent":{"$ref":"414"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":530.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"426"},"customOut":{"$id":"427"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":530.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"426"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":530.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"427"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":531.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"438"},"customOut":{"$id":"439"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":531.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"438"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":531.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"439"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":560.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"452"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":560.3984},"$type":"TransformData"},"CurveParent":{"$ref":"452"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":560.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"464"},"customOut":{"$id":"465"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":560.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"464"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":560.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"465"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":561.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"476"},"customOut":{"$id":"477"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":561.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"476"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":561.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"477"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":590.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"490"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":590.3984},"$type":"TransformData"},"CurveParent":{"$ref":"490"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":590.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"502"},"customOut":{"$id":"503"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":590.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"502"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":590.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"503"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":591.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"514"},"customOut":{"$id":"515"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":591.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"514"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":591.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"515"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":620.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"528"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":620.3984},"$type":"TransformData"},"CurveParent":{"$ref":"528"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":620.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"540"},"customOut":{"$id":"541"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":620.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"540"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":620.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"541"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":621.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"552"},"customOut":{"$id":"553"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":621.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"552"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":621.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"553"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":650.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"566"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":650.3984},"$type":"TransformData"},"CurveParent":{"$ref":"566"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":650.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"578"},"customOut":{"$id":"579"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":650.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"578"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":650.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"579"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":651.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"590"},"customOut":{"$id":"591"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":651.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"590"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":651.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"591"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":680.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"604"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":680.3984},"$type":"TransformData"},"CurveParent":{"$ref":"604"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":680.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"616"},"customOut":{"$id":"617"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":680.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"616"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":680.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"617"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":681.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"628"},"customOut":{"$id":"629"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":681.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"628"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":681.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"629"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":710.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"642"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":710.3984},"$type":"TransformData"},"CurveParent":{"$ref":"642"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":710.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"654"},"customOut":{"$id":"655"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":710.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"654"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":710.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"655"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":711.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"666"},"customOut":{"$id":"667"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":711.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"666"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":711.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"667"}},"children":[]}]}]}]}]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":455.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":425.3984},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":425.3984},"$type":"TransformData"}},"children":[]}]},{"name":"3 moving sides","components":{"Transform":{"position":{"x":0,"y":0,"z":395.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":454.3984},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":662.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]},{"name":"middle","components":{"Transform":{"position":{"x":0,"y":0,"z":448.5102},"$type":"TransformData"},"Randomizer":{"$ref":"11"}},"children":[{"name":"1 moving","components":{"Transform":{"position":{"x":0,"y":0,"z":13.31934},"$type":"TransformData"}},"children":[{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":283.3193},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"3 moving coins","components":{"Transform":{"position":{"x":0,"y":0,"z":608.8612},"$type":"TransformData"}},"children":[{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":270.8612},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":418.8612},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]},{"name":"middle","components":{"Transform":{"position":{"x":0,"y":0,"z":895.1921},"$type":"TransformData"},"Randomizer":{"$ref":"12"}},"children":[{"name":"1 moving","components":{"Transform":{"position":{"x":0,"y":0,"z":460.0012},"$type":"TransformData"}},"children":[{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":730.0012},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"3 moving coins","components":{"Transform":{"position":{"x":0,"y":0,"z":1055.543},"$type":"TransformData"}},"children":[{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":717.543},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":865.543},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]}]},"routeChunk_default_short_train_tops_moving_multiple":{"name":"routeChunk_default_short_train_tops_moving_multiple","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":12,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_short_train_tops_moving_multiple","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_start","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":-20,"y":37,"z":165},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":37,"z":165},"$type":"TransformData"}},"children":[]}]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":210},"$type":"TransformData"}},"children":[]},{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":270},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":480},"$type":"TransformData"}},"children":[]}]},{"name":"trains_moving_sides","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":717},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":870},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"trains_moving_mid","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"}},"children":[{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":382},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":632},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":829},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":0,"y":55,"z":690},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":55,"z":690},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_4_units_3_tracks_b-s-b":{"name":"routeChunk_default_4_units_3_tracks_b-s-b","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":6,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_4_units_3_tracks_b-s-b","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"coins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"40"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"CurveParent":{"$ref":"40"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"52"},"customOut":{"$id":"53"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"52"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"53"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":181},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"64"},"customOut":{"$id":"65"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"64"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"65"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":210},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"78"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":210},"$type":"TransformData"},"CurveParent":{"$ref":"78"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":210},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"90"},"customOut":{"$id":"91"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"90"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"91"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":211},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"102"},"customOut":{"$id":"103"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":211},"$type":"TransformData"},"CurvePointTangent":{"$ref":"102"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":211},"$type":"TransformData"},"CurvePointTangent":{"$ref":"103"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"116"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"CurveParent":{"$ref":"116"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"128"},"customOut":{"$id":"129"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"128"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"129"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":241},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"140"},"customOut":{"$id":"141"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"140"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"141"}},"children":[]}]}]}]}]},{"name":"coins_mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-10,"y":0,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"157"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-10,"y":0,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"157"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-10,"y":0,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"169"},"customOut":{"$id":"170"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"169"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"170"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-10,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"181"},"customOut":{"$id":"182"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"181"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"182"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":270},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"195"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":270},"$type":"TransformData"},"CurveParent":{"$ref":"195"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":270},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"207"},"customOut":{"$id":"208"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"207"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"208"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":271},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"219"},"customOut":{"$id":"220"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"219"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"220"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"233"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"},"CurveParent":{"$ref":"233"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"245"},"customOut":{"$id":"246"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"245"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"246"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":301},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"257"},"customOut":{"$id":"258"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"257"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"258"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":330},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"271"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":330},"$type":"TransformData"},"CurveParent":{"$ref":"271"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":330},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"283"},"customOut":{"$id":"284"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"283"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"284"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":331},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"295"},"customOut":{"$id":"296"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"295"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"296"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"309"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurveParent":{"$ref":"309"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"321"},"customOut":{"$id":"322"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePointTangent":{"$ref":"321"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"CurvePointTangent":{"$ref":"322"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":361},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"333"},"customOut":{"$id":"334"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"333"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"334"}},"children":[]}]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":30},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":300},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"}},"children":[]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":-20,"y":55,"z":150},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":55,"z":150},"$type":"TransformData"}},"children":[]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":495},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":495},"$type":"TransformData"}},"children":[]}]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":-10,"y":0,"z":510},"$type":"TransformData"}},"children":[]}]},"routeChunk_default_4_units_3_tracks_choice":{"name":"routeChunk_default_4_units_3_tracks_choice","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":6,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_4_units_3_tracks_choice","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":0,"z":30},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"25"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":30},"$type":"TransformData"},"CurveParent":{"$ref":"25"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":30},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"37"},"customOut":{"$id":"38"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":30},"$type":"TransformData"},"CurvePointTangent":{"$ref":"37"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":30},"$type":"TransformData"},"CurvePointTangent":{"$ref":"38"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":131},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"49"},"customOut":{"$id":"50"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":131},"$type":"TransformData"},"CurvePointTangent":{"$ref":"49"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":131},"$type":"TransformData"},"CurvePointTangent":{"$ref":"50"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":135},"$type":"TransformData"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"92"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"CurveParent":{"$ref":"92"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"104"},"customOut":{"$id":"105"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"104"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"105"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":331},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"116"},"customOut":{"$id":"117"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"116"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"117"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":210},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":0,"y":7,"z":330},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":330},"$type":"TransformData"}},"children":[]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":390},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":420},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":450},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":450},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":465},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"187"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.9,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":465},"$type":"TransformData"},"CurveParent":{"$ref":"187"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":465},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"199"},"customOut":{"$id":"200"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":465},"$type":"TransformData"},"CurvePointTangent":{"$ref":"199"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":563.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"200"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":563.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"211"},"customOut":{"$id":"212"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":465},"$type":"TransformData"},"CurvePointTangent":{"$ref":"211"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":563.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"212"}},"children":[]}]}]}]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":-10,"y":0,"z":510},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":20,"y":57,"z":555},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":57,"z":555},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_4_units_3_tracks_s-b-s-b":{"name":"routeChunk_default_4_units_3_tracks_s-b-s-b","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":6,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_4_units_3_tracks_s-b-s-b","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":15},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":76},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"43"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":15},"$type":"TransformData"},"CurveParent":{"$ref":"43"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":15},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"55"},"customOut":{"$id":"56"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":15},"$type":"TransformData"},"CurvePointTangent":{"$ref":"55"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":15},"$type":"TransformData"},"CurvePointTangent":{"$ref":"56"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":91},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"67"},"customOut":{"$id":"68"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":91},"$type":"TransformData"},"CurvePointTangent":{"$ref":"67"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":91},"$type":"TransformData"},"CurvePointTangent":{"$ref":"68"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":29,"z":105},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"81"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":105},"$type":"TransformData"},"CurveParent":{"$ref":"81"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":105},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"93"},"customOut":{"$id":"94"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"93"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"94"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"105"},"customOut":{"$id":"106"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"105"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"106"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":210},"$type":"TransformData"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":75},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"139"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"139"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"151"},"customOut":{"$id":"152"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"151"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"152"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":330},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"163"},"customOut":{"$id":"164"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"163"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"164"}},"children":[]}]}]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":345},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":345},"$type":"TransformData"}},"children":[]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":360},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":450},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":-20,"y":55,"z":540},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":55,"z":540},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_4_units_3_tracks_s-s-s-s":{"name":"routeChunk_default_4_units_3_tracks_s-s-s-s","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":6,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_4_units_3_tracks_s-s-s-s","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":30},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"33"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":30},"$type":"TransformData"},"CurveParent":{"$ref":"33"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":30},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"45"},"customOut":{"$id":"46"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":30},"$type":"TransformData"},"CurvePointTangent":{"$ref":"45"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":30},"$type":"TransformData"},"CurvePointTangent":{"$ref":"46"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":131},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"57"},"customOut":{"$id":"58"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":131},"$type":"TransformData"},"CurvePointTangent":{"$ref":"57"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":131},"$type":"TransformData"},"CurvePointTangent":{"$ref":"58"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":29,"z":90},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"71"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":90},"$type":"TransformData"},"CurveParent":{"$ref":"71"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":90},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"83"},"customOut":{"$id":"84"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"83"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"84"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":241},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"95"},"customOut":{"$id":"96"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"95"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"96"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":150},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"127"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurveParent":{"$ref":"127"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"139"},"customOut":{"$id":"140"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"139"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"140"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":371},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"151"},"customOut":{"$id":"152"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":371},"$type":"TransformData"},"CurvePointTangent":{"$ref":"151"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":371},"$type":"TransformData"},"CurvePointTangent":{"$ref":"152"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":300},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":420},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":35.8,"z":420},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":35.8,"z":420},"$type":"TransformData"}},"children":[]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":495},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":495},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_4_units_3_tracks_s-s":{"name":"routeChunk_default_4_units_3_tracks_s-s","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":4,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_4_units_3_tracks_s-s","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":7,"z":150},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":7,"z":150},"$type":"TransformData"}},"children":[]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":51},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"62"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"62"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"74"},"customOut":{"$id":"75"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"74"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"75"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":216},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"86"},"customOut":{"$id":"87"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":216},"$type":"TransformData"},"CurvePointTangent":{"$ref":"86"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":216},"$type":"TransformData"},"CurvePointTangent":{"$ref":"87"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":315},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":315},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_epic_various":{"name":"routeChunk_default_epic_various","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":16,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"23"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"24"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"25"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"26"},{"$id":"27"},{"$id":"28"},{"$id":"29"},{"$id":"30"},{"$id":"31"},{"$id":"32"},{"$id":"33"},{"$id":"34"},{"$id":"35"},{"$id":"36"},{"$id":"37"},{"$id":"38"},{"$id":"39"},{"$id":"40"},{"$id":"41"},{"$id":"42"},{"$id":"43"},{"$id":"44"},{"$id":"45"},{"$id":"46"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_epic_various","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"Randomizer","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"10"}},"children":[{"name":"roofRun","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":240},"$type":"TransformData"}},"children":[]},{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":270},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":451},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":605},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":832},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":990},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"groundRunDoubleTrains","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"23"}},"children":[{"name":"train double","components":{"Transform":{"position":{"x":0,"y":0,"z":145.1655},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.667267},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.667267},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"157"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.667267},"$type":"TransformData"},"CurveParent":{"$ref":"157"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.667267},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"169"},"customOut":{"$id":"170"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.667267},"$type":"TransformData"},"CurvePointTangent":{"$ref":"169"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.667267},"$type":"TransformData"},"CurvePointTangent":{"$ref":"170"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.667267},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"181"},"customOut":{"$id":"182"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.667267},"$type":"TransformData"},"CurvePointTangent":{"$ref":"181"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.667267},"$type":"TransformData"},"CurvePointTangent":{"$ref":"182"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":25.33273},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"195"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":25.33273},"$type":"TransformData"},"CurveParent":{"$ref":"195"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":25.33273},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"207"},"customOut":{"$id":"208"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":25.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"207"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":25.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"208"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":26.33273},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"219"},"customOut":{"$id":"220"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":26.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"219"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":26.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"220"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":55.33273},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"233"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":55.33273},"$type":"TransformData"},"CurveParent":{"$ref":"233"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":55.33273},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"245"},"customOut":{"$id":"246"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":55.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"245"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":55.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"246"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":56.33273},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"257"},"customOut":{"$id":"258"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":56.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"257"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":56.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"258"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":85.33273},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"271"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":85.33273},"$type":"TransformData"},"CurveParent":{"$ref":"271"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":85.33273},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"283"},"customOut":{"$id":"284"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":85.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"283"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":85.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"284"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":86.33273},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"295"},"customOut":{"$id":"296"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":86.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"295"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":86.33273},"$type":"TransformData"},"CurvePointTangent":{"$ref":"296"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":115.3327},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"309"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":115.3327},"$type":"TransformData"},"CurveParent":{"$ref":"309"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":115.3327},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"321"},"customOut":{"$id":"322"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":115.3327},"$type":"TransformData"},"CurvePointTangent":{"$ref":"321"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":115.3327},"$type":"TransformData"},"CurvePointTangent":{"$ref":"322"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":116.3327},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"333"},"customOut":{"$id":"334"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":116.3327},"$type":"TransformData"},"CurvePointTangent":{"$ref":"333"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":116.3327},"$type":"TransformData"},"CurvePointTangent":{"$ref":"334"}},"children":[]}]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":137.1655},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":137.1655},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"train double close","components":{"Transform":{"position":{"x":0,"y":0,"z":145.1655},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"371"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurveParent":{"$ref":"371"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"383"},"customOut":{"$id":"384"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"383"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"384"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.834534},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"395"},"customOut":{"$id":"396"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"395"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"396"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"409"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurveParent":{"$ref":"409"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"421"},"customOut":{"$id":"422"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"421"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"422"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":26.16547},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"433"},"customOut":{"$id":"434"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":26.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"433"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":26.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"434"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"447"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurveParent":{"$ref":"447"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"459"},"customOut":{"$id":"460"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"459"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"460"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":56.16547},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"471"},"customOut":{"$id":"472"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":56.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"471"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":56.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"472"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"485"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurveParent":{"$ref":"485"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"497"},"customOut":{"$id":"498"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"497"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"498"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":86.16547},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"509"},"customOut":{"$id":"510"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":86.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"509"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":86.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"510"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"523"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurveParent":{"$ref":"523"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"535"},"customOut":{"$id":"536"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"535"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"536"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":116.1655},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"547"},"customOut":{"$id":"548"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":116.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"547"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":116.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"548"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":118.1655},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":2,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":137.1655},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"train 1","components":{"Transform":{"position":{"x":0,"y":0,"z":145.1655},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"586"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurveParent":{"$ref":"586"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"598"},"customOut":{"$id":"599"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"598"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"599"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.834534},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"610"},"customOut":{"$id":"611"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"610"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"611"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"624"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurveParent":{"$ref":"624"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"636"},"customOut":{"$id":"637"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"636"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"637"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":26.16547},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"648"},"customOut":{"$id":"649"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":26.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"648"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":26.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"649"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"662"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurveParent":{"$ref":"662"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"674"},"customOut":{"$id":"675"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"674"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"675"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":56.16547},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"686"},"customOut":{"$id":"687"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":56.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"686"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":56.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"687"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"700"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurveParent":{"$ref":"700"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"712"},"customOut":{"$id":"713"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"712"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"713"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":86.16547},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"724"},"customOut":{"$id":"725"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":86.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"724"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":86.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"725"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"738"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurveParent":{"$ref":"738"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"750"},"customOut":{"$id":"751"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"750"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"751"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":116.1655},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"762"},"customOut":{"$id":"763"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":116.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"762"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":116.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"763"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":137.1655},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]},{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":285.5849},"$type":"TransformData"},"Randomizer":{"$ref":"24"}},"children":[{"name":"train double","components":{"Transform":{"position":{"x":0,"y":0,"z":430.7503},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":0,"y":0,"z":280.9176},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":280.9176},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"797"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":280.9176},"$type":"TransformData"},"CurveParent":{"$ref":"797"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":280.9176},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"809"},"customOut":{"$id":"810"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":280.9176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"809"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":280.9176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"810"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":2819176},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"821"},"customOut":{"$id":"822"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":2819176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"821"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":2819176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"822"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":310.9176},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"835"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":310.9176},"$type":"TransformData"},"CurveParent":{"$ref":"835"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":310.9176},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"847"},"customOut":{"$id":"848"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":310.9176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"847"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":310.9176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"848"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":3119176},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"859"},"customOut":{"$id":"860"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":3119176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"859"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":3119176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"860"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":340.9176},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"873"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":340.9176},"$type":"TransformData"},"CurveParent":{"$ref":"873"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":340.9176},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"885"},"customOut":{"$id":"886"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":340.9176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"885"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":340.9176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"886"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":3419176},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"897"},"customOut":{"$id":"898"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":3419176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"897"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":3419176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"898"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":370.9176},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"911"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":370.9176},"$type":"TransformData"},"CurveParent":{"$ref":"911"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":370.9176},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"923"},"customOut":{"$id":"924"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":370.9176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"923"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":370.9176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"924"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":3719176},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"935"},"customOut":{"$id":"936"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":3719176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"935"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":3719176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"936"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":400.9176},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"949"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":400.9176},"$type":"TransformData"},"CurveParent":{"$ref":"949"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":400.9176},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"961"},"customOut":{"$id":"962"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":400.9176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"961"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":400.9176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"962"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":4019176},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"973"},"customOut":{"$id":"974"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":4019176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"973"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":4019176},"$type":"TransformData"},"CurvePointTangent":{"$ref":"974"}},"children":[]}]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":422.7503},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":422.7503},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"train double close","components":{"Transform":{"position":{"x":0,"y":0,"z":430.7503},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":280.7503},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1010"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":280.7503},"$type":"TransformData"},"CurveParent":{"$ref":"1010"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":280.7503},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1022"},"customOut":{"$id":"1023"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":280.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1022"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":280.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1023"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":281.7503},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1034"},"customOut":{"$id":"1035"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":281.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1034"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":281.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1035"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":310.7503},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1048"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":310.7503},"$type":"TransformData"},"CurveParent":{"$ref":"1048"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":310.7503},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1060"},"customOut":{"$id":"1061"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":310.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1060"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":310.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1061"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":311.7503},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1072"},"customOut":{"$id":"1073"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":311.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1072"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":311.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1073"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":340.7503},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1086"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":340.7503},"$type":"TransformData"},"CurveParent":{"$ref":"1086"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":340.7503},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1098"},"customOut":{"$id":"1099"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":340.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1098"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":340.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1099"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":341.7503},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1110"},"customOut":{"$id":"1111"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":341.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1110"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":341.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1111"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":370.7503},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1124"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":370.7503},"$type":"TransformData"},"CurveParent":{"$ref":"1124"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":370.7503},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1136"},"customOut":{"$id":"1137"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":370.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1136"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":370.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1137"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":371.7503},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1148"},"customOut":{"$id":"1149"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":371.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1148"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":371.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1149"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":400.7503},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1162"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":400.7503},"$type":"TransformData"},"CurveParent":{"$ref":"1162"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":400.7503},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1174"},"customOut":{"$id":"1175"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":400.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1174"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":400.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1175"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":401.7503},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1186"},"customOut":{"$id":"1187"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":401.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1186"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":401.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1187"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":403.7503},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":2,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":422.7503},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"train 1","components":{"Transform":{"position":{"x":0,"y":0,"z":430.7503},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":280.7503},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1225"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":280.7503},"$type":"TransformData"},"CurveParent":{"$ref":"1225"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":280.7503},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1237"},"customOut":{"$id":"1238"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":280.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1237"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":280.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1238"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":281.7503},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1249"},"customOut":{"$id":"1250"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":281.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1249"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":281.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1250"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":310.7503},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1263"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":310.7503},"$type":"TransformData"},"CurveParent":{"$ref":"1263"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":310.7503},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1275"},"customOut":{"$id":"1276"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":310.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1275"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":310.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1276"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":311.7503},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1287"},"customOut":{"$id":"1288"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":311.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1287"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":311.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1288"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":340.7503},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1301"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":340.7503},"$type":"TransformData"},"CurveParent":{"$ref":"1301"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":340.7503},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1313"},"customOut":{"$id":"1314"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":340.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1313"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":340.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1314"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":341.7503},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1325"},"customOut":{"$id":"1326"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":341.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1325"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":341.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1326"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":370.7503},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1339"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":370.7503},"$type":"TransformData"},"CurveParent":{"$ref":"1339"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":370.7503},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1351"},"customOut":{"$id":"1352"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":370.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1351"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":370.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1352"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":371.7503},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1363"},"customOut":{"$id":"1364"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":371.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1363"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":371.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1364"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":400.7503},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1377"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":400.7503},"$type":"TransformData"},"CurveParent":{"$ref":"1377"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":400.7503},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1389"},"customOut":{"$id":"1390"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":400.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1389"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":400.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1390"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":401.7503},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1401"},"customOut":{"$id":"1402"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":401.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1401"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":401.7503},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1402"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":422.7503},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]},{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":576.1245},"$type":"TransformData"},"Randomizer":{"$ref":"25"}},"children":[{"name":"train double","components":{"Transform":{"position":{"x":0,"y":0,"z":721.29},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":0,"y":0,"z":571.4573},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":571.4573},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1436"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":571.4573},"$type":"TransformData"},"CurveParent":{"$ref":"1436"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":571.4573},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1448"},"customOut":{"$id":"1449"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":571.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1448"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":571.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1449"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":572.4573},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1460"},"customOut":{"$id":"1461"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":572.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1460"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":572.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1461"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":601.4573},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1474"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":601.4573},"$type":"TransformData"},"CurveParent":{"$ref":"1474"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":601.4573},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1486"},"customOut":{"$id":"1487"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":601.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1486"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":601.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1487"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":602.4573},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1498"},"customOut":{"$id":"1499"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":602.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1498"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":602.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1499"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":631.4573},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1512"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":631.4573},"$type":"TransformData"},"CurveParent":{"$ref":"1512"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":631.4573},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1524"},"customOut":{"$id":"1525"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":631.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1524"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":631.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1525"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":632.4573},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1536"},"customOut":{"$id":"1537"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":632.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1536"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":632.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1537"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":661.4573},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1550"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":661.4573},"$type":"TransformData"},"CurveParent":{"$ref":"1550"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":661.4573},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1562"},"customOut":{"$id":"1563"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":661.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1562"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":661.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1563"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":662.4573},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1574"},"customOut":{"$id":"1575"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":662.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1574"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":662.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1575"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":691.4573},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1588"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":691.4573},"$type":"TransformData"},"CurveParent":{"$ref":"1588"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":691.4573},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1600"},"customOut":{"$id":"1601"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":691.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1600"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":691.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1601"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":692.4573},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1612"},"customOut":{"$id":"1613"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":692.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1612"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":692.4573},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1613"}},"children":[]}]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":713.29},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":713.29},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"train double close","components":{"Transform":{"position":{"x":0,"y":0,"z":721.29},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":571.29},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1649"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":571.29},"$type":"TransformData"},"CurveParent":{"$ref":"1649"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":571.29},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1661"},"customOut":{"$id":"1662"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":571.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1661"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":571.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1662"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":572.29},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1673"},"customOut":{"$id":"1674"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":572.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1673"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":572.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1674"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":601.29},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1687"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":601.29},"$type":"TransformData"},"CurveParent":{"$ref":"1687"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":601.29},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1699"},"customOut":{"$id":"1700"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":601.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1699"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":601.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1700"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":602.29},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1711"},"customOut":{"$id":"1712"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":602.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1711"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":602.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1712"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":631.29},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1725"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":631.29},"$type":"TransformData"},"CurveParent":{"$ref":"1725"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":631.29},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1737"},"customOut":{"$id":"1738"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":631.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1737"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":631.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1738"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":632.29},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1749"},"customOut":{"$id":"1750"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":632.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1749"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":632.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1750"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":661.29},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1763"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":661.29},"$type":"TransformData"},"CurveParent":{"$ref":"1763"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":661.29},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1775"},"customOut":{"$id":"1776"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":661.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1775"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":661.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1776"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":662.29},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1787"},"customOut":{"$id":"1788"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":662.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1787"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":662.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1788"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":691.29},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1801"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":691.29},"$type":"TransformData"},"CurveParent":{"$ref":"1801"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":691.29},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1813"},"customOut":{"$id":"1814"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":691.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1813"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":691.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1814"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":692.29},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1825"},"customOut":{"$id":"1826"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":692.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1825"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":692.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1826"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":694.29},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":2,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":713.29},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"train 1","components":{"Transform":{"position":{"x":0,"y":0,"z":721.29},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":571.29},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1864"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":571.29},"$type":"TransformData"},"CurveParent":{"$ref":"1864"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":571.29},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1876"},"customOut":{"$id":"1877"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":571.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1876"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":571.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1877"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":572.29},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1888"},"customOut":{"$id":"1889"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":572.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1888"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":572.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1889"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":601.29},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1902"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":601.29},"$type":"TransformData"},"CurveParent":{"$ref":"1902"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":601.29},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1914"},"customOut":{"$id":"1915"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":601.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1914"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":601.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1915"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":602.29},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1926"},"customOut":{"$id":"1927"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":602.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1926"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":602.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1927"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":631.29},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1940"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":631.29},"$type":"TransformData"},"CurveParent":{"$ref":"1940"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":631.29},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1952"},"customOut":{"$id":"1953"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":631.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1952"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":631.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1953"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":632.29},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1964"},"customOut":{"$id":"1965"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":632.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1964"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":632.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1965"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":661.29},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1978"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":661.29},"$type":"TransformData"},"CurveParent":{"$ref":"1978"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":661.29},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1990"},"customOut":{"$id":"1991"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":661.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1990"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":661.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1991"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":662.29},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2002"},"customOut":{"$id":"2003"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":662.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2002"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":662.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2003"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":691.29},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2016"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":691.29},"$type":"TransformData"},"CurveParent":{"$ref":"2016"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":691.29},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2028"},"customOut":{"$id":"2029"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":691.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2028"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":691.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2029"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":692.29},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2040"},"customOut":{"$id":"2041"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":692.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2040"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":692.29},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2041"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":713.29},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]},{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":861.6984},"$type":"TransformData"},"Randomizer":{"$ref":"26"}},"children":[{"name":"train double","components":{"Transform":{"position":{"x":0,"y":0,"z":1006.864},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":0,"y":0,"z":857.0311},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":857.0311},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2075"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":857.0311},"$type":"TransformData"},"CurveParent":{"$ref":"2075"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":857.0311},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2087"},"customOut":{"$id":"2088"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":857.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2087"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":857.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2088"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":858.0311},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2099"},"customOut":{"$id":"2100"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":858.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2099"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":858.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2100"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":887.0311},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2113"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":887.0311},"$type":"TransformData"},"CurveParent":{"$ref":"2113"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":887.0311},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2125"},"customOut":{"$id":"2126"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":887.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2125"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":887.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2126"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":888.0311},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2137"},"customOut":{"$id":"2138"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":888.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2137"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":888.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2138"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":917.0311},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2151"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":917.0311},"$type":"TransformData"},"CurveParent":{"$ref":"2151"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":917.0311},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2163"},"customOut":{"$id":"2164"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":917.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2163"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":917.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2164"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":918.0311},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2175"},"customOut":{"$id":"2176"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":918.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2175"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":918.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2176"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":947.0311},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2189"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":947.0311},"$type":"TransformData"},"CurveParent":{"$ref":"2189"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":947.0311},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2201"},"customOut":{"$id":"2202"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":947.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2201"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":947.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2202"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":948.0311},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2213"},"customOut":{"$id":"2214"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":948.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2213"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":948.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2214"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":977.0311},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2227"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":977.0311},"$type":"TransformData"},"CurveParent":{"$ref":"2227"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":977.0311},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2239"},"customOut":{"$id":"2240"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":977.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2239"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":977.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2240"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":978.0311},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2251"},"customOut":{"$id":"2252"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":978.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2251"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":978.0311},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2252"}},"children":[]}]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":998.8638},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":998.8638},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"train double close","components":{"Transform":{"position":{"x":0,"y":0,"z":1006.864},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":856.8638},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2288"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":856.8638},"$type":"TransformData"},"CurveParent":{"$ref":"2288"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":856.8638},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2300"},"customOut":{"$id":"2301"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":856.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2300"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":856.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2301"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":857.8638},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2312"},"customOut":{"$id":"2313"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":857.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2312"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":857.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2313"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":886.8638},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2326"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":886.8638},"$type":"TransformData"},"CurveParent":{"$ref":"2326"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":886.8638},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2338"},"customOut":{"$id":"2339"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":886.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2338"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":886.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2339"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":887.8638},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2350"},"customOut":{"$id":"2351"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":887.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2350"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":887.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2351"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":916.8638},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2364"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":916.8638},"$type":"TransformData"},"CurveParent":{"$ref":"2364"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":916.8638},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2376"},"customOut":{"$id":"2377"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":916.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2376"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":916.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2377"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":917.8638},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2388"},"customOut":{"$id":"2389"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":917.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2388"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":917.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2389"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":946.8638},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2402"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":946.8638},"$type":"TransformData"},"CurveParent":{"$ref":"2402"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":946.8638},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2414"},"customOut":{"$id":"2415"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":946.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2414"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":946.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2415"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":947.8638},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2426"},"customOut":{"$id":"2427"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":947.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2426"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":947.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2427"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":976.8638},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2440"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":976.8638},"$type":"TransformData"},"CurveParent":{"$ref":"2440"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":976.8638},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2452"},"customOut":{"$id":"2453"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":976.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2452"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":976.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2453"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":977.8638},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2464"},"customOut":{"$id":"2465"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":977.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2464"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":977.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2465"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":979.8638},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":2,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":998.8638},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"train 1","components":{"Transform":{"position":{"x":0,"y":0,"z":1006.864},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":856.8638},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2503"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":856.8638},"$type":"TransformData"},"CurveParent":{"$ref":"2503"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":856.8638},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2515"},"customOut":{"$id":"2516"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":856.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2515"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":856.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2516"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":857.8638},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2527"},"customOut":{"$id":"2528"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":857.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2527"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":857.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2528"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":886.8638},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2541"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":886.8638},"$type":"TransformData"},"CurveParent":{"$ref":"2541"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":886.8638},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2553"},"customOut":{"$id":"2554"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":886.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2553"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":886.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2554"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":887.8638},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2565"},"customOut":{"$id":"2566"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":887.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2565"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":887.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2566"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":916.8638},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2579"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":916.8638},"$type":"TransformData"},"CurveParent":{"$ref":"2579"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":916.8638},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2591"},"customOut":{"$id":"2592"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":916.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2591"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":916.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2592"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":917.8638},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2603"},"customOut":{"$id":"2604"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":917.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2603"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":917.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2604"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":946.8638},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2617"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":946.8638},"$type":"TransformData"},"CurveParent":{"$ref":"2617"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":946.8638},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2629"},"customOut":{"$id":"2630"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":946.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2629"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":946.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2630"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":947.8638},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2641"},"customOut":{"$id":"2642"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":947.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2641"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":947.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2642"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":976.8638},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2655"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":976.8638},"$type":"TransformData"},"CurveParent":{"$ref":"2655"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":976.8638},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2667"},"customOut":{"$id":"2668"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":976.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2667"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":976.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2668"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":977.8638},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2679"},"customOut":{"$id":"2680"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":977.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2679"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":977.8638},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2680"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":998.8638},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]}]}]},{"name":"endCoins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"11"}},"children":[{"name":"endCoins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2709"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurveParent":{"$ref":"2709"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2721"},"customOut":{"$id":"2722"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2721"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2722"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1271},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2733"},"customOut":{"$id":"2734"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2733"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2734"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":1290},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2747"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1290},"$type":"TransformData"},"CurveParent":{"$ref":"2747"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1290},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2759"},"customOut":{"$id":"2760"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2759"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2760"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1391},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2771"},"customOut":{"$id":"2772"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1391},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2771"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1391},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2772"}},"children":[]}]}]}]}]},{"name":"endCoins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":10,"y":0,"z":1245},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2792"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":10,"y":0,"z":1245},"$type":"TransformData"},"CurveParent":{"$ref":"2792"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":10,"y":0,"z":1245},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2804"},"customOut":{"$id":"2805"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":1245},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2804"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":1245},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2805"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":10,"y":0,"z":1246},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2816"},"customOut":{"$id":"2817"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":1246},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2816"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":1246},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2817"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":1260},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2830"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":1260},"$type":"TransformData"},"CurveParent":{"$ref":"2830"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":1260},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2842"},"customOut":{"$id":"2843"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":1260},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2842"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":1260},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2843"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":1261},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2854"},"customOut":{"$id":"2855"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":1261},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2854"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":1261},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2855"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":1290},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2868"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":1290},"$type":"TransformData"},"CurveParent":{"$ref":"2868"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":1290},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2880"},"customOut":{"$id":"2881"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2880"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2881"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":1291},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2892"},"customOut":{"$id":"2893"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":1291},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2892"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":1291},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2893"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":10,"y":0,"z":1305},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2906"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":10,"y":0,"z":1305},"$type":"TransformData"},"CurveParent":{"$ref":"2906"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":10,"y":0,"z":1305},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2918"},"customOut":{"$id":"2919"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":1305},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2918"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":1305},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2919"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":10,"y":0,"z":1306},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2930"},"customOut":{"$id":"2931"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":1306},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2930"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":1306},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2931"}},"children":[]}]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1140},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2944"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1140},"$type":"TransformData"},"CurveParent":{"$ref":"2944"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1140},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2956"},"customOut":{"$id":"2957"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1140},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2956"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1140},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2957"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1141},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2968"},"customOut":{"$id":"2969"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1141},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2968"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1141},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2969"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2982"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurveParent":{"$ref":"2982"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2994"},"customOut":{"$id":"2995"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2994"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2995"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1171},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"3006"},"customOut":{"$id":"3007"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1171},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3006"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1171},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3007"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1200},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"3020"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1200},"$type":"TransformData"},"CurveParent":{"$ref":"3020"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1200},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"3032"},"customOut":{"$id":"3033"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1200},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3032"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1200},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3033"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1201},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"3044"},"customOut":{"$id":"3045"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1201},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3044"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1201},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3045"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1230},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"3058"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1230},"$type":"TransformData"},"CurveParent":{"$ref":"3058"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1230},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"3070"},"customOut":{"$id":"3071"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1230},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3070"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1230},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3071"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1231},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"3082"},"customOut":{"$id":"3083"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1231},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3082"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1231},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3083"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1320},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"3096"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1320},"$type":"TransformData"},"CurveParent":{"$ref":"3096"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1320},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"3108"},"customOut":{"$id":"3109"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1320},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3108"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1320},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3109"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1321},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"3120"},"customOut":{"$id":"3121"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1321},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3120"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1321},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3121"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1350},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"3134"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1350},"$type":"TransformData"},"CurveParent":{"$ref":"3134"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1350},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"3146"},"customOut":{"$id":"3147"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1350},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3146"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1350},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3147"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1351},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"3158"},"customOut":{"$id":"3159"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1351},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3158"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1351},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3159"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1380},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"3172"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1380},"$type":"TransformData"},"CurveParent":{"$ref":"3172"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1380},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"3184"},"customOut":{"$id":"3185"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1380},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3184"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1380},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3185"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1381},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"3196"},"customOut":{"$id":"3197"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1381},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3196"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1381},"$type":"TransformData"},"CurvePointTangent":{"$ref":"3197"}},"children":[]}]}]}]}]}]},{"name":"environments","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"epic_environment","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Epic,All","_density":""},"_blockCount":12,"$type":"SYBO.Subway.Level.Environment"}},"children":[]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":7,"z":45},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":7,"z":45},"$type":"TransformData"}},"children":[]}]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":-10,"y":0,"z":1260},"$type":"TransformData"}},"children":[]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":10,"y":0,"z":1350},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":-20,"y":7,"z":1410},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":1410},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_fallback":{"name":"routeChunk_default_fallback","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":2,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_fallback","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[]},"routeChunk_default_jetpack_landing":{"name":"routeChunk_default_jetpack_landing","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":4,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_jetpack_landing","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[]},"routeChunk_default_no_gameplay_1":{"name":"routeChunk_default_no_gameplay_1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":8,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"9"},{"$id":"10"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_no_gameplay_1","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_5_gen_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":390},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[]}]},"routeChunk_default_no_gameplay_2":{"name":"routeChunk_default_no_gameplay_2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":12,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"9"},{"$id":"10"},{"$id":"11"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_no_gameplay_2","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_5_gen_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":390},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":810},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[]}]},"routeChunk_default_no_gameplay_epic":{"name":"routeChunk_default_no_gameplay_epic","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":12,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Epic,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"7"},{"$id":"8"},{"$id":"9"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_no_gameplay_epic","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_5_gen_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":390},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":810},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[]}]},"routeChunk_default_start1":{"name":"routeChunk_default_start1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":4,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"9"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$id":"11"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_start1","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"random_coins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"10"}},"children":[{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":10,"y":0,"z":240},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"39"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":10,"y":0,"z":240},"$type":"TransformData"},"CurveParent":{"$ref":"39"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":10,"y":0,"z":240},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"51"},"customOut":{"$id":"52"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"51"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"52"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":10,"y":0,"z":241},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"63"},"customOut":{"$id":"64"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"63"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"64"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"77"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"77"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"89"},"customOut":{"$id":"90"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"89"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"90"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"101"},"customOut":{"$id":"102"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"101"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"102"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"115"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"115"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"127"},"customOut":{"$id":"128"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"127"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"128"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"139"},"customOut":{"$id":"140"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"139"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"140"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":10,"y":0,"z":300},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"153"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":10,"y":0,"z":300},"$type":"TransformData"},"CurveParent":{"$ref":"153"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":10,"y":0,"z":300},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"165"},"customOut":{"$id":"166"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"165"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"166"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":10,"y":0,"z":301},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"177"},"customOut":{"$id":"178"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"177"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"178"}},"children":[]}]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"191"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurveParent":{"$ref":"191"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"203"},"customOut":{"$id":"204"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"203"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"204"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"215"},"customOut":{"$id":"216"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"215"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"216"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"229"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"229"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"241"},"customOut":{"$id":"242"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"241"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"242"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"253"},"customOut":{"$id":"254"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"253"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"254"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"267"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"267"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"279"},"customOut":{"$id":"280"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"279"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"280"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"291"},"customOut":{"$id":"292"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"291"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"292"}},"children":[]}]}]}]}]},{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"308"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurveParent":{"$ref":"308"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"320"},"customOut":{"$id":"321"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"320"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"321"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":326},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"332"},"customOut":{"$id":"333"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":326},"$type":"TransformData"},"CurvePointTangent":{"$ref":"332"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":326},"$type":"TransformData"},"CurvePointTangent":{"$ref":"333"}},"children":[]}]}]}]}]},{"name":"3","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"349"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurveParent":{"$ref":"349"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"361"},"customOut":{"$id":"362"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"361"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"CurvePointTangent":{"$ref":"362"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":191},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"373"},"customOut":{"$id":"374"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":191},"$type":"TransformData"},"CurvePointTangent":{"$ref":"373"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":191},"$type":"TransformData"},"CurvePointTangent":{"$ref":"374"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"387"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"387"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"399"},"customOut":{"$id":"400"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"399"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"400"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":356},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"411"},"customOut":{"$id":"412"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":356},"$type":"TransformData"},"CurvePointTangent":{"$ref":"411"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":356},"$type":"TransformData"},"CurvePointTangent":{"$ref":"412"}},"children":[]}]}]}]}]}]},{"name":"environment_constraints","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Empty,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"},"EnvironmentBase":{"_type":"Empty","_numTracks":3,"_blockCount":2,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]},{"name":"train_sub_2_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":60},"$type":"TransformData"}},"children":[]}]},"routeChunk_default_start2":{"name":"routeChunk_default_start2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":4,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"9"},{"$id":"10"},{"$id":"11"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"12"},{"$id":"13"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"14"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_start2","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"9"}},"children":[{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"12"}},"children":[{"name":"coins_2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":135},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"42"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":135},"$type":"TransformData"},"CurveParent":{"$ref":"42"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":135},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"54"},"customOut":{"$id":"55"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"54"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"55"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":136},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"66"},"customOut":{"$id":"67"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"66"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"67"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"80"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"80"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"92"},"customOut":{"$id":"93"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"92"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"93"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":166},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"104"},"customOut":{"$id":"105"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"104"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"105"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":10,"y":0,"z":180},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"118"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":10,"y":0,"z":180},"$type":"TransformData"},"CurveParent":{"$ref":"118"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":10,"y":0,"z":180},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"130"},"customOut":{"$id":"131"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"130"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":180},"$type":"TransformData"},"CurvePointTangent":{"$ref":"131"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":10,"y":0,"z":181},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"142"},"customOut":{"$id":"143"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"142"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"143"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"156"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurveParent":{"$ref":"156"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"168"},"customOut":{"$id":"169"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"168"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"169"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"180"},"customOut":{"$id":"181"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"180"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"181"}},"children":[]}]}]}]}]},{"name":"coins_1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"197"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurveParent":{"$ref":"197"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"209"},"customOut":{"$id":"210"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"209"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"210"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":136},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"221"},"customOut":{"$id":"222"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"221"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"222"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"235"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"235"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"247"},"customOut":{"$id":"248"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"247"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"248"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":166},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"259"},"customOut":{"$id":"260"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"259"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"260"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"273"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurveParent":{"$ref":"273"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"285"},"customOut":{"$id":"286"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"285"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"286"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"297"},"customOut":{"$id":"298"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"297"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"298"}},"children":[]}]}]}]}]}]},{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"315"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurveParent":{"$ref":"315"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"327"},"customOut":{"$id":"328"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"327"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"328"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"339"},"customOut":{"$id":"340"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"339"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"340"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":10,"y":0,"z":240},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"353"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":10,"y":0,"z":240},"$type":"TransformData"},"CurveParent":{"$ref":"353"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":10,"y":0,"z":240},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"365"},"customOut":{"$id":"366"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"365"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"366"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":10,"y":0,"z":241},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"377"},"customOut":{"$id":"378"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"377"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"378"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"391"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"391"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"403"},"customOut":{"$id":"404"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"403"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"404"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"415"},"customOut":{"$id":"416"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"415"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"416"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"429"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"429"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"441"},"customOut":{"$id":"442"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"441"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"442"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"453"},"customOut":{"$id":"454"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"453"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"454"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":10,"y":0,"z":300},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"467"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":10,"y":0,"z":300},"$type":"TransformData"},"CurveParent":{"$ref":"467"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":10,"y":0,"z":300},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"479"},"customOut":{"$id":"480"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"479"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"480"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":10,"y":0,"z":301},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"491"},"customOut":{"$id":"492"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"491"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"492"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"505"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"505"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"517"},"customOut":{"$id":"518"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"517"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"518"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"529"},"customOut":{"$id":"530"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"529"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"530"}},"children":[]}]}]}]}]}]},{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"random","components":{"Transform":{"position":{"x":-0.04516602,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"14"}},"children":[{"name":"coins_2","components":{"Transform":{"position":{"x":-0.04516602,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20.04517,"y":0,"z":225},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"563"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20.04517,"y":0,"z":225},"$type":"TransformData"},"CurveParent":{"$ref":"563"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20.04517,"y":0,"z":225},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"575"},"customOut":{"$id":"576"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20.04517,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"575"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20.04517,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"576"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20.04517,"y":0,"z":226},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"587"},"customOut":{"$id":"588"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20.04517,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"587"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20.04517,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"588"}},"children":[]}]}]}]}]},{"name":"coins_1","components":{"Transform":{"position":{"x":-0.04516602,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-0.04516602,"y":0,"z":225},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"604"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-0.04516602,"y":0,"z":225},"$type":"TransformData"},"CurveParent":{"$ref":"604"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-0.04516602,"y":0,"z":225},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"616"},"customOut":{"$id":"617"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-0.04516602,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"616"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-0.04516602,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"617"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-0.04516602,"y":0,"z":226},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"628"},"customOut":{"$id":"629"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-0.04516602,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"628"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-0.04516602,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"629"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-10.04517,"y":0,"z":240},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"642"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-10.04517,"y":0,"z":240},"$type":"TransformData"},"CurveParent":{"$ref":"642"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-10.04517,"y":0,"z":240},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"654"},"customOut":{"$id":"655"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10.04517,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"654"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10.04517,"y":0,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"655"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-10.04517,"y":0,"z":241},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"666"},"customOut":{"$id":"667"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10.04517,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"666"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10.04517,"y":0,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"667"}},"children":[]}]}]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"680"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"680"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"692"},"customOut":{"$id":"693"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"692"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"693"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"704"},"customOut":{"$id":"705"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"704"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"705"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"718"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"718"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"730"},"customOut":{"$id":"731"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"730"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"731"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"742"},"customOut":{"$id":"743"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"742"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"743"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-10,"y":0,"z":300},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"756"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-10,"y":0,"z":300},"$type":"TransformData"},"CurveParent":{"$ref":"756"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-10,"y":0,"z":300},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"768"},"customOut":{"$id":"769"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"768"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"769"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-10,"y":0,"z":301},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"780"},"customOut":{"$id":"781"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-10,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"780"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-10,"y":0,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"781"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"794"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"794"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"806"},"customOut":{"$id":"807"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"806"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"807"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"818"},"customOut":{"$id":"819"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"818"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"819"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"832"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"832"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"844"},"customOut":{"$id":"845"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"844"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"845"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"856"},"customOut":{"$id":"857"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"856"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"857"}},"children":[]}]}]}]}]}]},{"name":"environment_constraints","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Empty,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"},"EnvironmentBase":{"_type":"Empty","_numTracks":3,"_blockCount":2,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]},{"name":"train_sub_2_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":60},"$type":"TransformData"}},"children":[]}]},"Default1Track":{"name":"Default1Track","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"routeChunk_default_1_track_end","components":{"Transform":{"position":{"x":0,"y":0,"z":1620},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":2,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_1_track_end","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"end","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"}},"children":[{"name":"endtrain","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1620},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"blocker_jump_standard_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1620},"$type":"TransformData"}},"children":[]},{"name":"blocker_jump_standard_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1620},"$type":"TransformData"}},"children":[]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":10,"y":0,"z":1710},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":1725},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":1725},"$type":"TransformData"}},"children":[]}]}]}]},{"name":"routeChunk_default_1_track_mid_var_1","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":14,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"83"},{"$id":"84"},{"$id":"85"},{"$id":"86"},{"$id":"87"},{"$id":"88"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_1_track_mid_var_1","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"environment_base","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"},"EnvironmentBase":{"_type":"Tracks","_numTracks":1,"_blockCount":14,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":492},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":719},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"station_platforms_extended_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":720},"$type":"TransformData"}},"children":[]},{"name":"random_coins","components":{"Transform":{"position":{"x":0,"y":0,"z":720},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":720},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"138"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":720},"$type":"TransformData"},"CurveParent":{"$ref":"138"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":720},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"150"},"customOut":{"$id":"151"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":720},"$type":"TransformData"},"CurvePointTangent":{"$ref":"150"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":720},"$type":"TransformData"},"CurvePointTangent":{"$ref":"151"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":721},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"162"},"customOut":{"$id":"163"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":721},"$type":"TransformData"},"CurvePointTangent":{"$ref":"162"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":721},"$type":"TransformData"},"CurvePointTangent":{"$ref":"163"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":750},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"176"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":750},"$type":"TransformData"},"CurveParent":{"$ref":"176"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":750},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"188"},"customOut":{"$id":"189"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":750},"$type":"TransformData"},"CurvePointTangent":{"$ref":"188"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":750},"$type":"TransformData"},"CurvePointTangent":{"$ref":"189"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":751},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"200"},"customOut":{"$id":"201"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":751},"$type":"TransformData"},"CurvePointTangent":{"$ref":"200"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":751},"$type":"TransformData"},"CurvePointTangent":{"$ref":"201"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":780},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"214"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":780},"$type":"TransformData"},"CurveParent":{"$ref":"214"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":780},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"226"},"customOut":{"$id":"227"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":780},"$type":"TransformData"},"CurvePointTangent":{"$ref":"226"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":780},"$type":"TransformData"},"CurvePointTangent":{"$ref":"227"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":781},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"238"},"customOut":{"$id":"239"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":781},"$type":"TransformData"},"CurvePointTangent":{"$ref":"238"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":781},"$type":"TransformData"},"CurvePointTangent":{"$ref":"239"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":810},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"252"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":810},"$type":"TransformData"},"CurveParent":{"$ref":"252"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":810},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"264"},"customOut":{"$id":"265"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":810},"$type":"TransformData"},"CurvePointTangent":{"$ref":"264"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":810},"$type":"TransformData"},"CurvePointTangent":{"$ref":"265"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":811},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"276"},"customOut":{"$id":"277"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":811},"$type":"TransformData"},"CurvePointTangent":{"$ref":"276"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":811},"$type":"TransformData"},"CurvePointTangent":{"$ref":"277"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":840},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"290"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":840},"$type":"TransformData"},"CurveParent":{"$ref":"290"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":840},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"302"},"customOut":{"$id":"303"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":840},"$type":"TransformData"},"CurvePointTangent":{"$ref":"302"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":840},"$type":"TransformData"},"CurvePointTangent":{"$ref":"303"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":841},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"314"},"customOut":{"$id":"315"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":841},"$type":"TransformData"},"CurvePointTangent":{"$ref":"314"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":841},"$type":"TransformData"},"CurvePointTangent":{"$ref":"315"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":870},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"328"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":870},"$type":"TransformData"},"CurveParent":{"$ref":"328"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":870},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"340"},"customOut":{"$id":"341"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":870},"$type":"TransformData"},"CurvePointTangent":{"$ref":"340"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":870},"$type":"TransformData"},"CurvePointTangent":{"$ref":"341"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":871},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"352"},"customOut":{"$id":"353"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":871},"$type":"TransformData"},"CurvePointTangent":{"$ref":"352"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":871},"$type":"TransformData"},"CurvePointTangent":{"$ref":"353"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":900},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"366"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":900},"$type":"TransformData"},"CurveParent":{"$ref":"366"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":900},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"378"},"customOut":{"$id":"379"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":900},"$type":"TransformData"},"CurvePointTangent":{"$ref":"378"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":900},"$type":"TransformData"},"CurvePointTangent":{"$ref":"379"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":901},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"390"},"customOut":{"$id":"391"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":901},"$type":"TransformData"},"CurvePointTangent":{"$ref":"390"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":901},"$type":"TransformData"},"CurvePointTangent":{"$ref":"391"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":930},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"404"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":930},"$type":"TransformData"},"CurveParent":{"$ref":"404"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":930},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"416"},"customOut":{"$id":"417"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":930},"$type":"TransformData"},"CurvePointTangent":{"$ref":"416"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":930},"$type":"TransformData"},"CurvePointTangent":{"$ref":"417"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":931},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"428"},"customOut":{"$id":"429"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":931},"$type":"TransformData"},"CurvePointTangent":{"$ref":"428"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":931},"$type":"TransformData"},"CurvePointTangent":{"$ref":"429"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":960},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"442"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":960},"$type":"TransformData"},"CurveParent":{"$ref":"442"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":960},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"454"},"customOut":{"$id":"455"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":960},"$type":"TransformData"},"CurvePointTangent":{"$ref":"454"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":960},"$type":"TransformData"},"CurvePointTangent":{"$ref":"455"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":961},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"466"},"customOut":{"$id":"467"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":961},"$type":"TransformData"},"CurvePointTangent":{"$ref":"466"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":961},"$type":"TransformData"},"CurvePointTangent":{"$ref":"467"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":990},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"480"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":990},"$type":"TransformData"},"CurveParent":{"$ref":"480"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":990},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"492"},"customOut":{"$id":"493"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":990},"$type":"TransformData"},"CurvePointTangent":{"$ref":"492"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":990},"$type":"TransformData"},"CurvePointTangent":{"$ref":"493"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":991},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"504"},"customOut":{"$id":"505"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":991},"$type":"TransformData"},"CurvePointTangent":{"$ref":"504"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":991},"$type":"TransformData"},"CurvePointTangent":{"$ref":"505"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":1020},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"518"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":1020},"$type":"TransformData"},"CurveParent":{"$ref":"518"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":1020},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"530"},"customOut":{"$id":"531"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":1020},"$type":"TransformData"},"CurvePointTangent":{"$ref":"530"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":1020},"$type":"TransformData"},"CurvePointTangent":{"$ref":"531"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":1021},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"542"},"customOut":{"$id":"543"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":1021},"$type":"TransformData"},"CurvePointTangent":{"$ref":"542"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":1021},"$type":"TransformData"},"CurvePointTangent":{"$ref":"543"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":10,"z":1050},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"556"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":10,"z":1050},"$type":"TransformData"},"CurveParent":{"$ref":"556"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":10,"z":1050},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"568"},"customOut":{"$id":"569"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":1050},"$type":"TransformData"},"CurvePointTangent":{"$ref":"568"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":1050},"$type":"TransformData"},"CurvePointTangent":{"$ref":"569"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":10,"z":1051},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"580"},"customOut":{"$id":"581"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":10,"z":1051},"$type":"TransformData"},"CurvePointTangent":{"$ref":"580"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":10,"z":1051},"$type":"TransformData"},"CurvePointTangent":{"$ref":"581"}},"children":[]}]}]}]}]},{"name":"random_coins","components":{"Transform":{"position":{"x":0,"y":0,"z":1175.177},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"obstacle_group_group","components":{"Transform":{"position":{"x":0,"y":0,"z":1265.177},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":0,"z":1265.177},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"607"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.5,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1265.177},"$type":"TransformData"},"CurveParent":{"$ref":"607"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1265.177},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"619"},"customOut":{"$id":"620"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1265.177},"$type":"TransformData"},"CurvePointTangent":{"$ref":"619"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":80,"z":1363.564},"$type":"TransformData"},"CurvePointTangent":{"$ref":"620"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1363.564},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"631"},"customOut":{"$id":"632"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":80,"z":1265.177},"$type":"TransformData"},"CurvePointTangent":{"$ref":"631"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1363.564},"$type":"TransformData"},"CurvePointTangent":{"$ref":"632"}},"children":[]}]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1261},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"random_coins","components":{"Transform":{"position":{"x":0,"y":0,"z":1407.424},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"obstacle_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1467.424},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":0,"z":1467.424},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"667"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.5,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1467.424},"$type":"TransformData"},"CurveParent":{"$ref":"667"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1467.424},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"679"},"customOut":{"$id":"680"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1467.424},"$type":"TransformData"},"CurvePointTangent":{"$ref":"679"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":80,"z":1565.811},"$type":"TransformData"},"CurvePointTangent":{"$ref":"680"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1565.811},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"691"},"customOut":{"$id":"692"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":80,"z":1467.424},"$type":"TransformData"},"CurvePointTangent":{"$ref":"691"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1565.811},"$type":"TransformData"},"CurvePointTangent":{"$ref":"692"}},"children":[]}]}]}]}]}]},{"name":"environments","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"}},"children":[{"name":"high_filler","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Fillers,All","_density":"High,All"},"_blockCount":4,"$type":"SYBO.Subway.Level.Environment"}},"children":[]},{"name":"station_environment","components":{"Transform":{"position":{"x":0,"y":0,"z":720},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Station,All","_density":""},"_blockCount":4,"$type":"SYBO.Subway.Level.Environment"}},"children":[]},{"name":"high_filler","components":{"Transform":{"position":{"x":0,"y":0,"z":1260},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Fillers,All","_density":"High,All"},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"}},"children":[]}]}]},{"name":"routeChunk_default_1_track_mid_var_2","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":14,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"726"},{"$id":"727"},{"$id":"728"},{"$id":"729"},{"$id":"730"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_1_track_mid_var_2","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"environment_base","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"},"EnvironmentBase":{"_type":"Tracks","_numTracks":1,"_blockCount":14,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]},{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":461},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"station_platforms_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":720},"$type":"TransformData"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"763"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurveParent":{"$ref":"763"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"775"},"customOut":{"$id":"776"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"775"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"776"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"787"},"customOut":{"$id":"788"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"787"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"788"}},"children":[]}]}]}]},{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":967},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1080},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[]},{"name":"station_platforms_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1260},"$type":"TransformData"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":1275},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"830"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1275},"$type":"TransformData"},"CurveParent":{"$ref":"830"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1275},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"842"},"customOut":{"$id":"843"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1275},"$type":"TransformData"},"CurvePointTangent":{"$ref":"842"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1275},"$type":"TransformData"},"CurvePointTangent":{"$ref":"843"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1426},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"854"},"customOut":{"$id":"855"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1426},"$type":"TransformData"},"CurvePointTangent":{"$ref":"854"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1426},"$type":"TransformData"},"CurvePointTangent":{"$ref":"855"}},"children":[]}]}]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":-20,"y":7,"z":1530},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":1530},"$type":"TransformData"}},"children":[]}]}]},{"name":"environments","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"}},"children":[{"name":"high_filler","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Fillers,All","_density":"High,All"},"_blockCount":4,"$type":"SYBO.Subway.Level.Environment"}},"children":[]},{"name":"station","components":{"Transform":{"position":{"x":0,"y":0,"z":720},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Station,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"}},"children":[]},{"name":"high_filler","components":{"Transform":{"position":{"x":0,"y":0,"z":900},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Fillers,All","_density":"High,All"},"_blockCount":4,"$type":"SYBO.Subway.Level.Environment"}},"children":[]},{"name":"station","components":{"Transform":{"position":{"x":0,"y":0,"z":1260},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Station,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"}},"children":[]}]}]},{"name":"routeChunk_default_1_track_start","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":4,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"912"},{"$id":"913"},{"$id":"914"},{"$id":"915"},{"$id":"916"},{"$id":"917"},{"$id":"918"},{"$id":"919"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_1_track_start","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"start","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"912"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":60},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":195},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"946"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":195},"$type":"TransformData"},"CurveParent":{"$ref":"946"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":195},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"958"},"customOut":{"$id":"959"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"958"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"959"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":196},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"970"},"customOut":{"$id":"971"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"970"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"971"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":225},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"984"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":225},"$type":"TransformData"},"CurveParent":{"$ref":"984"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":225},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"996"},"customOut":{"$id":"997"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"996"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"997"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":226},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1008"},"customOut":{"$id":"1009"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1008"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1009"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1022"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"1022"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1034"},"customOut":{"$id":"1035"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1034"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1035"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1046"},"customOut":{"$id":"1047"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1046"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1047"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1060"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"1060"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1072"},"customOut":{"$id":"1073"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1072"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1073"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1084"},"customOut":{"$id":"1085"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1084"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1085"}},"children":[]}]}]}]},{"name":"obstacle_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":510},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":0,"z":510},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1105"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.5,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":510},"$type":"TransformData"},"CurveParent":{"$ref":"1105"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":510},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1117"},"customOut":{"$id":"1118"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":510},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1117"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":80,"z":608.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1118"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":608.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1129"},"customOut":{"$id":"1130"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":80,"z":510},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1129"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":608.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1130"}},"children":[]}]}]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":7,"z":510},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":7,"z":510},"$type":"TransformData"}},"children":[]}]}]},{"name":"group","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":60},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":195},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1170"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":195},"$type":"TransformData"},"CurveParent":{"$ref":"1170"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":195},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1182"},"customOut":{"$id":"1183"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1182"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1183"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":196},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1194"},"customOut":{"$id":"1195"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1194"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1195"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":225},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1208"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":225},"$type":"TransformData"},"CurveParent":{"$ref":"1208"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":225},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1220"},"customOut":{"$id":"1221"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1220"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1221"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":226},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1232"},"customOut":{"$id":"1233"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1232"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1233"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1246"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"1246"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1258"},"customOut":{"$id":"1259"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1258"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1259"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1270"},"customOut":{"$id":"1271"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1270"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1271"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1284"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"1284"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1296"},"customOut":{"$id":"1297"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1296"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1297"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1308"},"customOut":{"$id":"1309"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1308"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1309"}},"children":[]}]}]}]},{"name":"obstacle_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":510},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":0,"z":510},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1329"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.5,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":510},"$type":"TransformData"},"CurveParent":{"$ref":"1329"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":510},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1341"},"customOut":{"$id":"1342"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":510},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1341"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":80,"z":608.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1342"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":608.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1353"},"customOut":{"$id":"1354"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":80,"z":510},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1353"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":608.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1354"}},"children":[]}]}]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":-20,"y":7,"z":510},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":510},"$type":"TransformData"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":210},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"blockers","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":360},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"}},"children":[]}]}]}]},"Default2Tracks":{"name":"Default2Tracks","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"routeChunk_default_2_tracks_end","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":2,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_2_tracks_end","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"blocker_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":-10,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":105},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":105},"$type":"TransformData"}},"children":[]}]}]},{"name":"routeChunk_default_2_tracks_mid_var_1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":16,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"50"},{"$id":"51"},{"$id":"52"},{"$id":"53"},{"$id":"54"},{"$id":"55"},{"$id":"56"},{"$id":"57"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_2_tracks_mid_var_1","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"environments","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"pillar_environment","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Pillars,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"}},"children":[]},{"name":"pillar_environment (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Pillars,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"}},"children":[]},{"name":"pillar_environment (2)","components":{"Transform":{"position":{"x":0,"y":0,"z":720},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Pillars,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"}},"children":[]},{"name":"pillar_environment (3)","components":{"Transform":{"position":{"x":0,"y":0,"z":1080},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Pillars,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"}},"children":[]}]},{"name":"environment_base","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"EnvironmentBase":{"_type":"Tracks","_numTracks":2,"_blockCount":16,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]},{"name":"pillars_short","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":-135},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"98"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":-135},"$type":"TransformData"},"CurveParent":{"$ref":"98"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":-135},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"110"},"customOut":{"$id":"111"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"110"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"111"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":-134},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"122"},"customOut":{"$id":"123"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-134},"$type":"TransformData"},"CurvePointTangent":{"$ref":"122"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-134},"$type":"TransformData"},"CurvePointTangent":{"$ref":"123"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":-105},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"136"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":-105},"$type":"TransformData"},"CurveParent":{"$ref":"136"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":-105},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"148"},"customOut":{"$id":"149"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"148"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"149"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":-104},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"160"},"customOut":{"$id":"161"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-104},"$type":"TransformData"},"CurvePointTangent":{"$ref":"160"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-104},"$type":"TransformData"},"CurvePointTangent":{"$ref":"161"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":-75},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"174"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":-75},"$type":"TransformData"},"CurveParent":{"$ref":"174"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":-75},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"186"},"customOut":{"$id":"187"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-75},"$type":"TransformData"},"CurvePointTangent":{"$ref":"186"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-75},"$type":"TransformData"},"CurvePointTangent":{"$ref":"187"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":-74},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"198"},"customOut":{"$id":"199"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-74},"$type":"TransformData"},"CurvePointTangent":{"$ref":"198"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-74},"$type":"TransformData"},"CurvePointTangent":{"$ref":"199"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":-45},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"212"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":-45},"$type":"TransformData"},"CurveParent":{"$ref":"212"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":-45},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"224"},"customOut":{"$id":"225"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-45},"$type":"TransformData"},"CurvePointTangent":{"$ref":"224"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-45},"$type":"TransformData"},"CurvePointTangent":{"$ref":"225"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":-44},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"236"},"customOut":{"$id":"237"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-44},"$type":"TransformData"},"CurvePointTangent":{"$ref":"236"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-44},"$type":"TransformData"},"CurvePointTangent":{"$ref":"237"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":-15},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"250"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":-15},"$type":"TransformData"},"CurveParent":{"$ref":"250"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":-15},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"262"},"customOut":{"$id":"263"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-15},"$type":"TransformData"},"CurvePointTangent":{"$ref":"262"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-15},"$type":"TransformData"},"CurvePointTangent":{"$ref":"263"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":-14},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"274"},"customOut":{"$id":"275"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-14},"$type":"TransformData"},"CurvePointTangent":{"$ref":"274"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-14},"$type":"TransformData"},"CurvePointTangent":{"$ref":"275"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":39},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place (3)","components":{"Transform":{"position":{"x":0,"y":0,"z":50},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"308"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurveParent":{"$ref":"308"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"320"},"customOut":{"$id":"321"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"320"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"321"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":136},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"332"},"customOut":{"$id":"333"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"332"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"333"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"346"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"346"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"358"},"customOut":{"$id":"359"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"358"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"359"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":166},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"370"},"customOut":{"$id":"371"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"370"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"371"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"384"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurveParent":{"$ref":"384"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"396"},"customOut":{"$id":"397"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"396"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"397"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"408"},"customOut":{"$id":"409"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"408"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"409"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"422"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurveParent":{"$ref":"422"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"434"},"customOut":{"$id":"435"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"434"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"435"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"446"},"customOut":{"$id":"447"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"446"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"447"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"460"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"460"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"472"},"customOut":{"$id":"473"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"472"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"473"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"484"},"customOut":{"$id":"485"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"484"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"485"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"498"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"498"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"510"},"customOut":{"$id":"511"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"510"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"511"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"522"},"customOut":{"$id":"523"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"522"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"523"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"536"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"536"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"548"},"customOut":{"$id":"549"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"548"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"549"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"560"},"customOut":{"$id":"561"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"560"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"561"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"574"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"574"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"586"},"customOut":{"$id":"587"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"586"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"587"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"598"},"customOut":{"$id":"599"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"598"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"599"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":398},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":410},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"630"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurveParent":{"$ref":"630"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"642"},"customOut":{"$id":"643"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurvePointTangent":{"$ref":"642"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurvePointTangent":{"$ref":"643"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":496},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"654"},"customOut":{"$id":"655"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":496},"$type":"TransformData"},"CurvePointTangent":{"$ref":"654"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":496},"$type":"TransformData"},"CurvePointTangent":{"$ref":"655"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"668"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurveParent":{"$ref":"668"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"680"},"customOut":{"$id":"681"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurvePointTangent":{"$ref":"680"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurvePointTangent":{"$ref":"681"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":526},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"692"},"customOut":{"$id":"693"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":526},"$type":"TransformData"},"CurvePointTangent":{"$ref":"692"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":526},"$type":"TransformData"},"CurvePointTangent":{"$ref":"693"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"706"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurveParent":{"$ref":"706"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"718"},"customOut":{"$id":"719"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurvePointTangent":{"$ref":"718"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurvePointTangent":{"$ref":"719"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":556},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"730"},"customOut":{"$id":"731"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":556},"$type":"TransformData"},"CurvePointTangent":{"$ref":"730"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":556},"$type":"TransformData"},"CurvePointTangent":{"$ref":"731"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"744"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"744"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"756"},"customOut":{"$id":"757"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"756"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"757"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"768"},"customOut":{"$id":"769"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"768"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"769"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":615},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"782"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":615},"$type":"TransformData"},"CurveParent":{"$ref":"782"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":615},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"794"},"customOut":{"$id":"795"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":615},"$type":"TransformData"},"CurvePointTangent":{"$ref":"794"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":615},"$type":"TransformData"},"CurvePointTangent":{"$ref":"795"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":616},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"806"},"customOut":{"$id":"807"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":616},"$type":"TransformData"},"CurvePointTangent":{"$ref":"806"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":616},"$type":"TransformData"},"CurvePointTangent":{"$ref":"807"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":645},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"820"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":645},"$type":"TransformData"},"CurveParent":{"$ref":"820"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":645},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"832"},"customOut":{"$id":"833"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":645},"$type":"TransformData"},"CurvePointTangent":{"$ref":"832"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":645},"$type":"TransformData"},"CurvePointTangent":{"$ref":"833"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":646},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"844"},"customOut":{"$id":"845"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":646},"$type":"TransformData"},"CurvePointTangent":{"$ref":"844"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":646},"$type":"TransformData"},"CurvePointTangent":{"$ref":"845"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"858"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurveParent":{"$ref":"858"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"870"},"customOut":{"$id":"871"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePointTangent":{"$ref":"870"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePointTangent":{"$ref":"871"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"882"},"customOut":{"$id":"883"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePointTangent":{"$ref":"882"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePointTangent":{"$ref":"883"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"896"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurveParent":{"$ref":"896"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"908"},"customOut":{"$id":"909"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePointTangent":{"$ref":"908"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePointTangent":{"$ref":"909"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"920"},"customOut":{"$id":"921"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePointTangent":{"$ref":"920"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePointTangent":{"$ref":"921"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":758},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":770},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"952"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurveParent":{"$ref":"952"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"964"},"customOut":{"$id":"965"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"964"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"965"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"976"},"customOut":{"$id":"977"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"976"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"977"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"990"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurveParent":{"$ref":"990"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1002"},"customOut":{"$id":"1003"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1002"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1003"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1014"},"customOut":{"$id":"1015"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1014"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1015"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1028"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurveParent":{"$ref":"1028"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1040"},"customOut":{"$id":"1041"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1040"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1041"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1052"},"customOut":{"$id":"1053"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1052"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1053"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1066"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"CurveParent":{"$ref":"1066"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1078"},"customOut":{"$id":"1079"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1078"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1079"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":976},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1090"},"customOut":{"$id":"1091"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":976},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1090"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":976},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1091"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1005},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1104"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1005},"$type":"TransformData"},"CurveParent":{"$ref":"1104"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1005},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1116"},"customOut":{"$id":"1117"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1005},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1116"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1005},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1117"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1006},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1128"},"customOut":{"$id":"1129"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1006},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1128"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1006},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1129"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1035},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1142"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1035},"$type":"TransformData"},"CurveParent":{"$ref":"1142"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1035},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1154"},"customOut":{"$id":"1155"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1035},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1154"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1035},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1155"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1166"},"customOut":{"$id":"1167"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1166"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1167"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1065},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1180"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1065},"$type":"TransformData"},"CurveParent":{"$ref":"1180"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1065},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1192"},"customOut":{"$id":"1193"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1065},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1192"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1065},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1193"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1066},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1204"},"customOut":{"$id":"1205"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1066},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1204"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1066},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1205"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1118},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place (2)","components":{"Transform":{"position":{"x":0,"y":0,"z":1130},"$type":"TransformData"}},"children":[]}]}]},{"name":"routeChunk_default_2_tracks_mid_var_2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":16,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"1237"},{"$id":"1238"},{"$id":"1239"},{"$id":"1240"},{"$id":"1241"},{"$id":"1242"},{"$id":"1243"},{"$id":"1244"},{"$id":"1245"},{"$id":"1246"},{"$id":"1247"},{"$id":"1248"},{"$id":"1249"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_2_tracks_mid_var_2","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"pillars_long","components":{"Transform":{"position":{"x":0,"y":0,"z":-180},"$type":"TransformData"}},"children":[{"name":"roof_setup","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":30},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1263"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":30},"$type":"TransformData"},"CurveParent":{"$ref":"1263"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":30},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1275"},"customOut":{"$id":"1276"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":30},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1275"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":30},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1276"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":181},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1287"},"customOut":{"$id":"1288"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1287"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":181},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1288"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":210},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1301"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":210},"$type":"TransformData"},"CurveParent":{"$ref":"1301"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":210},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1313"},"customOut":{"$id":"1314"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1313"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1314"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":361},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1325"},"customOut":{"$id":"1326"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1325"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1326"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":390},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1339"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":390},"$type":"TransformData"},"CurveParent":{"$ref":"1339"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":390},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1351"},"customOut":{"$id":"1352"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1351"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1352"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":541},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1363"},"customOut":{"$id":"1364"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":541},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1363"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":541},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1364"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":570},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1377"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":570},"$type":"TransformData"},"CurveParent":{"$ref":"1377"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":570},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1389"},"customOut":{"$id":"1390"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":570},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1389"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":570},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1390"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":721},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1401"},"customOut":{"$id":"1402"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":721},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1401"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":721},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1402"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":750},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1415"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":750},"$type":"TransformData"},"CurveParent":{"$ref":"1415"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":750},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1427"},"customOut":{"$id":"1428"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":750},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1427"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":750},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1428"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":901},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1439"},"customOut":{"$id":"1440"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":901},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1439"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":901},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1440"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":930},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1453"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":930},"$type":"TransformData"},"CurveParent":{"$ref":"1453"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":930},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1465"},"customOut":{"$id":"1466"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":930},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1465"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":930},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1466"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":1081},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1477"},"customOut":{"$id":"1478"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":1081},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1477"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":1081},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1478"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":1110},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1491"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":1110},"$type":"TransformData"},"CurveParent":{"$ref":"1491"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":1110},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1503"},"customOut":{"$id":"1504"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":1110},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1503"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":1110},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1504"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":1261},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1515"},"customOut":{"$id":"1516"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":1261},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1515"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":1261},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1516"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":91,"z":1290},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1529"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":91,"z":1290},"$type":"TransformData"},"CurveParent":{"$ref":"1529"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":91,"z":1290},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1541"},"customOut":{"$id":"1542"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1541"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1542"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":91,"z":1441},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1553"},"customOut":{"$id":"1554"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":91,"z":1441},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1553"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":91,"z":1441},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1554"}},"children":[]}]}]}]}]},{"name":"pillar_group_place (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1575"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurveParent":{"$ref":"1575"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1587"},"customOut":{"$id":"1588"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1587"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1588"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":136},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1599"},"customOut":{"$id":"1600"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1599"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":136},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1600"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1613"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"1613"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1625"},"customOut":{"$id":"1626"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1625"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1626"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":166},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1637"},"customOut":{"$id":"1638"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1637"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":166},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1638"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1651"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurveParent":{"$ref":"1651"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1663"},"customOut":{"$id":"1664"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1663"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1664"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1675"},"customOut":{"$id":"1676"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1675"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":196},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1676"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1689"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurveParent":{"$ref":"1689"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1701"},"customOut":{"$id":"1702"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1701"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":225},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1702"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1713"},"customOut":{"$id":"1714"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1713"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":226},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1714"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":251},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place (4)","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1745"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"1745"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1757"},"customOut":{"$id":"1758"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1757"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1758"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1769"},"customOut":{"$id":"1770"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1769"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1770"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1783"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"1783"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1795"},"customOut":{"$id":"1796"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1795"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1796"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1807"},"customOut":{"$id":"1808"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1807"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":346},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1808"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1821"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurveParent":{"$ref":"1821"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1833"},"customOut":{"$id":"1834"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1833"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1834"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":376},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1845"},"customOut":{"$id":"1846"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":376},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1845"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":376},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1846"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":405},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1859"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":405},"$type":"TransformData"},"CurveParent":{"$ref":"1859"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":405},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1871"},"customOut":{"$id":"1872"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":405},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1871"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":405},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1872"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":406},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1883"},"customOut":{"$id":"1884"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":406},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1883"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":406},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1884"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":431},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":450},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1915"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurveParent":{"$ref":"1915"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1927"},"customOut":{"$id":"1928"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1927"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":495},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1928"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":496},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1939"},"customOut":{"$id":"1940"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":496},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1939"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":496},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1940"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1953"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurveParent":{"$ref":"1953"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1965"},"customOut":{"$id":"1966"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1965"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":525},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1966"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":526},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1977"},"customOut":{"$id":"1978"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":526},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1977"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":526},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1978"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1991"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurveParent":{"$ref":"1991"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2003"},"customOut":{"$id":"2004"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2003"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2004"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":556},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2015"},"customOut":{"$id":"2016"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":556},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2015"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":556},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2016"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2029"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"2029"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2041"},"customOut":{"$id":"2042"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2041"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2042"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2053"},"customOut":{"$id":"2054"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2053"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2054"}},"children":[]}]}]}]},{"name":"pillar_group_place (3)","components":{"Transform":{"position":{"x":0,"y":0,"z":630},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2075"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurveParent":{"$ref":"2075"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2087"},"customOut":{"$id":"2088"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2087"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":675},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2088"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2099"},"customOut":{"$id":"2100"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2099"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":676},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2100"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2113"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurveParent":{"$ref":"2113"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2125"},"customOut":{"$id":"2126"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2125"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":705},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2126"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2137"},"customOut":{"$id":"2138"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2137"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":706},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2138"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2151"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurveParent":{"$ref":"2151"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2163"},"customOut":{"$id":"2164"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2163"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2164"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2175"},"customOut":{"$id":"2176"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2175"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2176"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":765},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2189"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":765},"$type":"TransformData"},"CurveParent":{"$ref":"2189"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":765},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2201"},"customOut":{"$id":"2202"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":765},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2201"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":765},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2202"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":766},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2213"},"customOut":{"$id":"2214"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":766},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2213"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":766},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2214"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":791},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place (5)","components":{"Transform":{"position":{"x":0,"y":0,"z":810},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":855},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2245"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":855},"$type":"TransformData"},"CurveParent":{"$ref":"2245"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":855},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2257"},"customOut":{"$id":"2258"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":855},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2257"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":855},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2258"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":856},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2269"},"customOut":{"$id":"2270"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":856},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2269"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":856},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2270"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2283"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurveParent":{"$ref":"2283"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2295"},"customOut":{"$id":"2296"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2295"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2296"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2307"},"customOut":{"$id":"2308"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2307"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2308"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2321"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurveParent":{"$ref":"2321"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2333"},"customOut":{"$id":"2334"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2333"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2334"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2345"},"customOut":{"$id":"2346"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2345"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":916},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2346"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2359"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurveParent":{"$ref":"2359"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2371"},"customOut":{"$id":"2372"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2371"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2372"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2383"},"customOut":{"$id":"2384"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2383"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":946},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2384"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":971},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place (7)","components":{"Transform":{"position":{"x":0,"y":0,"z":990},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1035},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2415"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1035},"$type":"TransformData"},"CurveParent":{"$ref":"2415"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1035},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2427"},"customOut":{"$id":"2428"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1035},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2427"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1035},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2428"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2439"},"customOut":{"$id":"2440"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2439"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2440"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1065},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2453"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1065},"$type":"TransformData"},"CurveParent":{"$ref":"2453"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1065},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2465"},"customOut":{"$id":"2466"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1065},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2465"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1065},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2466"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1066},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2477"},"customOut":{"$id":"2478"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1066},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2477"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1066},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2478"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1095},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2491"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1095},"$type":"TransformData"},"CurveParent":{"$ref":"2491"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1095},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2503"},"customOut":{"$id":"2504"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1095},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2503"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1095},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2504"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1096},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2515"},"customOut":{"$id":"2516"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1096},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2515"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1096},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2516"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1125},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2529"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1125},"$type":"TransformData"},"CurveParent":{"$ref":"2529"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1125},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2541"},"customOut":{"$id":"2542"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1125},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2541"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1125},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2542"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1126},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2553"},"customOut":{"$id":"2554"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1126},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2553"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1126},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2554"}},"children":[]}]}]}]},{"name":"pillar_group_place (6)","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"}},"children":[]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1215},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2575"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1215},"$type":"TransformData"},"CurveParent":{"$ref":"2575"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1215},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2587"},"customOut":{"$id":"2588"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1215},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2587"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1215},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2588"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1216},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2599"},"customOut":{"$id":"2600"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1216},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2599"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1216},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2600"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1245},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2613"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1245},"$type":"TransformData"},"CurveParent":{"$ref":"2613"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1245},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2625"},"customOut":{"$id":"2626"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1245},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2625"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1245},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2626"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1246},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2637"},"customOut":{"$id":"2638"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1246},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2637"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1246},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2638"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1275},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2651"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1275},"$type":"TransformData"},"CurveParent":{"$ref":"2651"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1275},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2663"},"customOut":{"$id":"2664"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1275},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2663"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1275},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2664"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1276},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2675"},"customOut":{"$id":"2676"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1276},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2675"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1276},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2676"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1305},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2689"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1305},"$type":"TransformData"},"CurveParent":{"$ref":"2689"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1305},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2701"},"customOut":{"$id":"2702"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1305},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2701"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1305},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2702"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1306},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2713"},"customOut":{"$id":"2714"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1306},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2713"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1306},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2714"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1331},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"pillar_group_place (2)","components":{"Transform":{"position":{"x":0,"y":0,"z":1350},"$type":"TransformData"}},"children":[]}]},{"name":"environment_base","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"EnvironmentBase":{"_type":"Tracks","_numTracks":2,"_blockCount":16,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]},{"name":"environments","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"pillars_environment","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Pillars,All","_density":""},"_blockCount":16,"$type":"SYBO.Subway.Level.Environment"}},"children":[]}]}]},{"name":"routeChunk_default_2_tracks_start","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":2,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"2758"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_2_tracks_start","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"blocker_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"environment_base","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"EnvironmentBase":{"_type":"Tracks","_numTracks":2,"_blockCount":2,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":0,"y":26.2,"z":120},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":26.2,"z":120},"$type":"TransformData"}},"children":[]}]}]}]},"routeChunk_default_epic":{"name":"routeChunk_default_epic","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":false,"_blockCount":16,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"9"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"},{"$id":"23"},{"$id":"24"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_epic","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"endCoins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"9"}},"children":[{"name":"endCoins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"37"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurveParent":{"$ref":"37"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"49"},"customOut":{"$id":"50"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePointTangent":{"$ref":"49"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePointTangent":{"$ref":"50"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1271},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"61"},"customOut":{"$id":"62"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"61"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"62"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":1290},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"75"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1290},"$type":"TransformData"},"CurveParent":{"$ref":"75"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1290},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"87"},"customOut":{"$id":"88"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"87"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"88"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1391},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"99"},"customOut":{"$id":"100"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1391},"$type":"TransformData"},"CurvePointTangent":{"$ref":"99"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1391},"$type":"TransformData"},"CurvePointTangent":{"$ref":"100"}},"children":[]}]}]}]}]},{"name":"endCoins","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":10,"y":0,"z":1245},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"120"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":10,"y":0,"z":1245},"$type":"TransformData"},"CurveParent":{"$ref":"120"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":10,"y":0,"z":1245},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"132"},"customOut":{"$id":"133"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":1245},"$type":"TransformData"},"CurvePointTangent":{"$ref":"132"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":1245},"$type":"TransformData"},"CurvePointTangent":{"$ref":"133"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":10,"y":0,"z":1246},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"144"},"customOut":{"$id":"145"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":1246},"$type":"TransformData"},"CurvePointTangent":{"$ref":"144"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":1246},"$type":"TransformData"},"CurvePointTangent":{"$ref":"145"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":1260},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"158"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":1260},"$type":"TransformData"},"CurveParent":{"$ref":"158"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":1260},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"170"},"customOut":{"$id":"171"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":1260},"$type":"TransformData"},"CurvePointTangent":{"$ref":"170"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":1260},"$type":"TransformData"},"CurvePointTangent":{"$ref":"171"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":1261},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"182"},"customOut":{"$id":"183"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":1261},"$type":"TransformData"},"CurvePointTangent":{"$ref":"182"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":1261},"$type":"TransformData"},"CurvePointTangent":{"$ref":"183"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":0,"z":1290},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"196"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":1290},"$type":"TransformData"},"CurveParent":{"$ref":"196"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":1290},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"208"},"customOut":{"$id":"209"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"208"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"209"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":1291},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"220"},"customOut":{"$id":"221"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":1291},"$type":"TransformData"},"CurvePointTangent":{"$ref":"220"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":1291},"$type":"TransformData"},"CurvePointTangent":{"$ref":"221"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":10,"y":0,"z":1305},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"234"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":10,"y":0,"z":1305},"$type":"TransformData"},"CurveParent":{"$ref":"234"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":10,"y":0,"z":1305},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"246"},"customOut":{"$id":"247"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":1305},"$type":"TransformData"},"CurvePointTangent":{"$ref":"246"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":1305},"$type":"TransformData"},"CurvePointTangent":{"$ref":"247"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":10,"y":0,"z":1306},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"258"},"customOut":{"$id":"259"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":10,"y":0,"z":1306},"$type":"TransformData"},"CurvePointTangent":{"$ref":"258"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":10,"y":0,"z":1306},"$type":"TransformData"},"CurvePointTangent":{"$ref":"259"}},"children":[]}]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1140},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"272"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1140},"$type":"TransformData"},"CurveParent":{"$ref":"272"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1140},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"284"},"customOut":{"$id":"285"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1140},"$type":"TransformData"},"CurvePointTangent":{"$ref":"284"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1140},"$type":"TransformData"},"CurvePointTangent":{"$ref":"285"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1141},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"296"},"customOut":{"$id":"297"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1141},"$type":"TransformData"},"CurvePointTangent":{"$ref":"296"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1141},"$type":"TransformData"},"CurvePointTangent":{"$ref":"297"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"310"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurveParent":{"$ref":"310"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"322"},"customOut":{"$id":"323"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePointTangent":{"$ref":"322"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1170},"$type":"TransformData"},"CurvePointTangent":{"$ref":"323"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1171},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"334"},"customOut":{"$id":"335"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1171},"$type":"TransformData"},"CurvePointTangent":{"$ref":"334"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1171},"$type":"TransformData"},"CurvePointTangent":{"$ref":"335"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1200},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"348"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1200},"$type":"TransformData"},"CurveParent":{"$ref":"348"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1200},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"360"},"customOut":{"$id":"361"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1200},"$type":"TransformData"},"CurvePointTangent":{"$ref":"360"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1200},"$type":"TransformData"},"CurvePointTangent":{"$ref":"361"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1201},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"372"},"customOut":{"$id":"373"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1201},"$type":"TransformData"},"CurvePointTangent":{"$ref":"372"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1201},"$type":"TransformData"},"CurvePointTangent":{"$ref":"373"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1230},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"386"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1230},"$type":"TransformData"},"CurveParent":{"$ref":"386"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1230},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"398"},"customOut":{"$id":"399"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1230},"$type":"TransformData"},"CurvePointTangent":{"$ref":"398"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1230},"$type":"TransformData"},"CurvePointTangent":{"$ref":"399"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1231},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"410"},"customOut":{"$id":"411"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1231},"$type":"TransformData"},"CurvePointTangent":{"$ref":"410"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1231},"$type":"TransformData"},"CurvePointTangent":{"$ref":"411"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1320},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"424"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1320},"$type":"TransformData"},"CurveParent":{"$ref":"424"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1320},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"436"},"customOut":{"$id":"437"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1320},"$type":"TransformData"},"CurvePointTangent":{"$ref":"436"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1320},"$type":"TransformData"},"CurvePointTangent":{"$ref":"437"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1321},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"448"},"customOut":{"$id":"449"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1321},"$type":"TransformData"},"CurvePointTangent":{"$ref":"448"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1321},"$type":"TransformData"},"CurvePointTangent":{"$ref":"449"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1350},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"462"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1350},"$type":"TransformData"},"CurveParent":{"$ref":"462"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1350},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"474"},"customOut":{"$id":"475"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1350},"$type":"TransformData"},"CurvePointTangent":{"$ref":"474"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1350},"$type":"TransformData"},"CurvePointTangent":{"$ref":"475"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1351},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"486"},"customOut":{"$id":"487"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1351},"$type":"TransformData"},"CurvePointTangent":{"$ref":"486"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1351},"$type":"TransformData"},"CurvePointTangent":{"$ref":"487"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":1380},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"500"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":1380},"$type":"TransformData"},"CurveParent":{"$ref":"500"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":1380},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"512"},"customOut":{"$id":"513"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1380},"$type":"TransformData"},"CurvePointTangent":{"$ref":"512"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1380},"$type":"TransformData"},"CurvePointTangent":{"$ref":"513"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1381},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"524"},"customOut":{"$id":"525"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1381},"$type":"TransformData"},"CurvePointTangent":{"$ref":"524"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1381},"$type":"TransformData"},"CurvePointTangent":{"$ref":"525"}},"children":[]}]}]}]}]}]},{"name":"Randomizer","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"10"}},"children":[{"name":"roofRun","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":240},"$type":"TransformData"}},"children":[]},{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":270},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":451},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":605},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":832},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":990},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"groundRun","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"train 1","components":{"Transform":{"position":{"x":0,"y":0,"z":145.1655},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"636"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurveParent":{"$ref":"636"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"648"},"customOut":{"$id":"649"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"648"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-4.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"649"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.834534},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"660"},"customOut":{"$id":"661"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"660"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":-3.834534},"$type":"TransformData"},"CurvePointTangent":{"$ref":"661"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"674"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurveParent":{"$ref":"674"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"686"},"customOut":{"$id":"687"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"686"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":25.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"687"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":26.16547},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"698"},"customOut":{"$id":"699"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":26.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"698"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":26.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"699"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"712"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurveParent":{"$ref":"712"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"724"},"customOut":{"$id":"725"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"724"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":55.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"725"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":56.16547},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"736"},"customOut":{"$id":"737"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":56.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"736"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":56.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"737"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"750"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurveParent":{"$ref":"750"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"762"},"customOut":{"$id":"763"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"762"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":85.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"763"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":86.16547},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"774"},"customOut":{"$id":"775"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":86.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"774"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":86.16547},"$type":"TransformData"},"CurvePointTangent":{"$ref":"775"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"788"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurveParent":{"$ref":"788"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"800"},"customOut":{"$id":"801"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"800"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":115.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"801"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":116.1655},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"812"},"customOut":{"$id":"813"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":116.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"812"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":116.1655},"$type":"TransformData"},"CurvePointTangent":{"$ref":"813"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":137.1655},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"train 1","components":{"Transform":{"position":{"x":0,"y":0,"z":432.2206},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":282.2206},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"842"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":282.2206},"$type":"TransformData"},"CurveParent":{"$ref":"842"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":282.2206},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"854"},"customOut":{"$id":"855"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":282.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"854"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":282.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"855"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":283.2206},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"866"},"customOut":{"$id":"867"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":283.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"866"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":283.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"867"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":312.2206},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"880"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":312.2206},"$type":"TransformData"},"CurveParent":{"$ref":"880"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":312.2206},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"892"},"customOut":{"$id":"893"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":312.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"892"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":312.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"893"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":313.2206},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"904"},"customOut":{"$id":"905"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":313.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"904"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":313.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"905"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":342.2206},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"918"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":342.2206},"$type":"TransformData"},"CurveParent":{"$ref":"918"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":342.2206},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"930"},"customOut":{"$id":"931"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":342.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"930"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":342.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"931"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":343.2206},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"942"},"customOut":{"$id":"943"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":343.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"942"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":343.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"943"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":372.2206},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"956"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":372.2206},"$type":"TransformData"},"CurveParent":{"$ref":"956"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":372.2206},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"968"},"customOut":{"$id":"969"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":372.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"968"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":372.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"969"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":373.2206},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"980"},"customOut":{"$id":"981"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":373.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"980"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":373.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"981"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":402.2206},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"994"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":402.2206},"$type":"TransformData"},"CurveParent":{"$ref":"994"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":402.2206},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1006"},"customOut":{"$id":"1007"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":402.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1006"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":402.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1007"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":403.2206},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1018"},"customOut":{"$id":"1019"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":403.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1018"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":403.2206},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1019"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":423.2206},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"train 1","components":{"Transform":{"position":{"x":0,"y":0,"z":719.3317},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":569.3317},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1047"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":569.3317},"$type":"TransformData"},"CurveParent":{"$ref":"1047"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":569.3317},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1059"},"customOut":{"$id":"1060"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":569.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1059"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":569.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1060"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":570.3317},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1071"},"customOut":{"$id":"1072"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":570.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1071"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":570.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1072"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":599.3317},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1085"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":599.3317},"$type":"TransformData"},"CurveParent":{"$ref":"1085"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":599.3317},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1097"},"customOut":{"$id":"1098"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":599.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1097"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":599.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1098"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":600.3317},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1109"},"customOut":{"$id":"1110"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":600.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1109"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":600.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1110"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":629.3317},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1123"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":629.3317},"$type":"TransformData"},"CurveParent":{"$ref":"1123"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":629.3317},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1135"},"customOut":{"$id":"1136"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":629.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1135"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":629.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1136"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":630.3317},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1147"},"customOut":{"$id":"1148"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":630.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1147"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":630.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1148"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":659.3317},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1161"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":659.3317},"$type":"TransformData"},"CurveParent":{"$ref":"1161"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":659.3317},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1173"},"customOut":{"$id":"1174"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":659.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1173"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":659.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1174"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":660.3317},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1185"},"customOut":{"$id":"1186"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":660.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1185"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":660.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1186"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":689.3317},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1199"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":689.3317},"$type":"TransformData"},"CurveParent":{"$ref":"1199"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":689.3317},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1211"},"customOut":{"$id":"1212"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":689.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1211"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":689.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1212"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":690.3317},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1223"},"customOut":{"$id":"1224"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":690.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1223"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":690.3317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1224"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":712.3317},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"train 1","components":{"Transform":{"position":{"x":0,"y":0,"z":1007.032},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":857.0317},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1252"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":857.0317},"$type":"TransformData"},"CurveParent":{"$ref":"1252"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":857.0317},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1264"},"customOut":{"$id":"1265"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":857.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1264"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":857.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1265"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":858.0317},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1276"},"customOut":{"$id":"1277"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":858.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1276"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":858.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1277"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":887.0317},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1290"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":887.0317},"$type":"TransformData"},"CurveParent":{"$ref":"1290"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":887.0317},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1302"},"customOut":{"$id":"1303"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":887.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1302"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":887.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1303"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":888.0317},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1314"},"customOut":{"$id":"1315"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":888.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1314"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":888.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1315"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":917.0317},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1328"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":917.0317},"$type":"TransformData"},"CurveParent":{"$ref":"1328"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":917.0317},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1340"},"customOut":{"$id":"1341"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":917.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1340"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":917.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1341"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":918.0317},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1352"},"customOut":{"$id":"1353"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":918.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1352"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":918.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1353"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":947.0317},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1366"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":947.0317},"$type":"TransformData"},"CurveParent":{"$ref":"1366"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":947.0317},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1378"},"customOut":{"$id":"1379"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":947.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1378"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":947.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1379"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":948.0317},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1390"},"customOut":{"$id":"1391"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":948.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1390"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":948.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1391"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":0,"y":0,"z":977.0317},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1404"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":977.0317},"$type":"TransformData"},"CurveParent":{"$ref":"1404"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":977.0317},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1416"},"customOut":{"$id":"1417"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":977.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1416"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":977.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1417"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":978.0317},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1428"},"customOut":{"$id":"1429"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":978.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1428"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":978.0317},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1429"}},"children":[]}]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":999.0317},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":2,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]}]},{"name":"environments","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"epic_environment","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Epic,All","_density":""},"_blockCount":12,"$type":"SYBO.Subway.Level.Environment"}},"children":[]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":-20,"y":7,"z":30},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":30},"$type":"TransformData"}},"children":[]}]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":-10,"y":0,"z":1260},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":20,"y":7,"z":1410},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":7,"z":1410},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_ramp_1":{"name":"routeChunk_default_ramp_1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":2,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_ramp_1","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"random_trains","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":56,"z":195},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":56,"z":195},"$type":"TransformData"}},"children":[]}]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":-20,"y":7,"z":30},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":30},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_train_tops_moving":{"name":"routeChunk_default_train_tops_moving","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":20,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"15"},{"$id":"16"},{"$id":"17"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"18"},{"$id":"19"},{"$id":"20"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"21"},{"$id":"22"},{"$id":"23"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"24"},{"$id":"25"},{"$id":"26"},{"$id":"27"},{"$id":"28"},{"$id":"29"},{"$id":"30"},{"$id":"31"},{"$id":"32"},{"$id":"33"},{"$id":"34"},{"$id":"35"},{"$id":"36"},{"$id":"37"},{"$id":"38"},{"$id":"39"},{"$id":"40"},{"$id":"41"},{"$id":"42"},{"$id":"43"},{"$id":"44"},{"$id":"45"},{"$id":"46"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_train_tops_moving","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":106},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_side","components":{"Transform":{"position":{"x":0,"y":0,"z":135},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"randomizer","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"15"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":20,"y":0,"z":135},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":195},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":240},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"83"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":240},"$type":"TransformData"},"CurveParent":{"$ref":"83"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":240},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"95"},"customOut":{"$id":"96"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"95"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":338.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"96"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":338.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"107"},"customOut":{"$id":"108"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"107"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":338.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"108"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":315},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"group","components":{"Transform":{"position":{"x":20,"y":0,"z":135},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":195},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":435},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"153"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.8,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CurveParent":{"$ref":"153"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"165"},"customOut":{"$id":"166"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"165"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":533.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"166"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":533.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"177"},"customOut":{"$id":"178"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"177"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":533.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"178"}},"children":[]}]}]}]}]},{"name":"group","components":{"Transform":{"position":{"x":20,"y":0,"z":135},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":20,"y":29,"z":135},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":210},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"197"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":210},"$type":"TransformData"},"CurveParent":{"$ref":"197"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":210},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"209"},"customOut":{"$id":"210"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"209"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":210},"$type":"TransformData"},"CurvePointTangent":{"$ref":"210"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":211},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"221"},"customOut":{"$id":"222"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":211},"$type":"TransformData"},"CurvePointTangent":{"$ref":"221"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":211},"$type":"TransformData"},"CurvePointTangent":{"$ref":"222"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":240},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"235"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":240},"$type":"TransformData"},"CurveParent":{"$ref":"235"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":240},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"247"},"customOut":{"$id":"248"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"247"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":240},"$type":"TransformData"},"CurvePointTangent":{"$ref":"248"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":241},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"259"},"customOut":{"$id":"260"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"259"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":241},"$type":"TransformData"},"CurvePointTangent":{"$ref":"260"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":270},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"273"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":270},"$type":"TransformData"},"CurveParent":{"$ref":"273"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":270},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"285"},"customOut":{"$id":"286"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"285"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":270},"$type":"TransformData"},"CurvePointTangent":{"$ref":"286"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":271},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"297"},"customOut":{"$id":"298"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"297"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":271},"$type":"TransformData"},"CurvePointTangent":{"$ref":"298"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":300},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"311"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":300},"$type":"TransformData"},"CurveParent":{"$ref":"311"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":300},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"323"},"customOut":{"$id":"324"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"323"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":300},"$type":"TransformData"},"CurvePointTangent":{"$ref":"324"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":301},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"335"},"customOut":{"$id":"336"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"335"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":301},"$type":"TransformData"},"CurvePointTangent":{"$ref":"336"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":330},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"349"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":330},"$type":"TransformData"},"CurveParent":{"$ref":"349"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":330},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"361"},"customOut":{"$id":"362"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"361"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":330},"$type":"TransformData"},"CurvePointTangent":{"$ref":"362"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":331},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"373"},"customOut":{"$id":"374"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"373"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":331},"$type":"TransformData"},"CurvePointTangent":{"$ref":"374"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":360},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"387"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":360},"$type":"TransformData"},"CurveParent":{"$ref":"387"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":360},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"399"},"customOut":{"$id":"400"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":360},"$type":"TransformData"},"CurvePointTangent":{"$ref":"399"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":360},"$type":"TransformData"},"CurvePointTangent":{"$ref":"400"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":361},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"411"},"customOut":{"$id":"412"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"411"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":361},"$type":"TransformData"},"CurvePointTangent":{"$ref":"412"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":390},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"425"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":390},"$type":"TransformData"},"CurveParent":{"$ref":"425"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":390},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"437"},"customOut":{"$id":"438"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"437"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":390},"$type":"TransformData"},"CurvePointTangent":{"$ref":"438"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":391},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"449"},"customOut":{"$id":"450"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":391},"$type":"TransformData"},"CurvePointTangent":{"$ref":"449"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":391},"$type":"TransformData"},"CurvePointTangent":{"$ref":"450"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":420},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"463"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":420},"$type":"TransformData"},"CurveParent":{"$ref":"463"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":420},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"475"},"customOut":{"$id":"476"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":420},"$type":"TransformData"},"CurvePointTangent":{"$ref":"475"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":420},"$type":"TransformData"},"CurvePointTangent":{"$ref":"476"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":421},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"487"},"customOut":{"$id":"488"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":421},"$type":"TransformData"},"CurvePointTangent":{"$ref":"487"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":421},"$type":"TransformData"},"CurvePointTangent":{"$ref":"488"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":450},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"501"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":450},"$type":"TransformData"},"CurveParent":{"$ref":"501"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":450},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"513"},"customOut":{"$id":"514"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":450},"$type":"TransformData"},"CurvePointTangent":{"$ref":"513"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":450},"$type":"TransformData"},"CurvePointTangent":{"$ref":"514"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":451},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"525"},"customOut":{"$id":"526"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":451},"$type":"TransformData"},"CurvePointTangent":{"$ref":"525"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":451},"$type":"TransformData"},"CurvePointTangent":{"$ref":"526"}},"children":[]}]}]}]}]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":195},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":165},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":-20,"y":7,"z":210},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":210},"$type":"TransformData"}},"children":[]}]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"}},"children":[]}]},{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":461},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_side","components":{"Transform":{"position":{"x":0,"y":0,"z":555},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"randomizer","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"Randomizer":{"$ref":"18"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":555},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":615},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":660},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"610"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":660},"$type":"TransformData"},"CurveParent":{"$ref":"610"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":660},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"622"},"customOut":{"$id":"623"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":660},"$type":"TransformData"},"CurvePointTangent":{"$ref":"622"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":758.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"623"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":758.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"634"},"customOut":{"$id":"635"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":660},"$type":"TransformData"},"CurvePointTangent":{"$ref":"634"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":758.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"635"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":735},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":555},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":615},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":855},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":855},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"679"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.8,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":855},"$type":"TransformData"},"CurveParent":{"$ref":"679"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":855},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"691"},"customOut":{"$id":"692"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":855},"$type":"TransformData"},"CurvePointTangent":{"$ref":"691"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":953.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"692"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":953.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"703"},"customOut":{"$id":"704"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":855},"$type":"TransformData"},"CurvePointTangent":{"$ref":"703"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":953.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"704"}},"children":[]}]}]}]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":555},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":-20,"y":29,"z":555},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":630},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"723"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":630},"$type":"TransformData"},"CurveParent":{"$ref":"723"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":630},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"735"},"customOut":{"$id":"736"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":630},"$type":"TransformData"},"CurvePointTangent":{"$ref":"735"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":630},"$type":"TransformData"},"CurvePointTangent":{"$ref":"736"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":631},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"747"},"customOut":{"$id":"748"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":631},"$type":"TransformData"},"CurvePointTangent":{"$ref":"747"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":631},"$type":"TransformData"},"CurvePointTangent":{"$ref":"748"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":660},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"761"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":660},"$type":"TransformData"},"CurveParent":{"$ref":"761"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":660},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"773"},"customOut":{"$id":"774"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":660},"$type":"TransformData"},"CurvePointTangent":{"$ref":"773"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":660},"$type":"TransformData"},"CurvePointTangent":{"$ref":"774"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":661},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"785"},"customOut":{"$id":"786"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":661},"$type":"TransformData"},"CurvePointTangent":{"$ref":"785"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":661},"$type":"TransformData"},"CurvePointTangent":{"$ref":"786"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":690},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"799"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":690},"$type":"TransformData"},"CurveParent":{"$ref":"799"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":690},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"811"},"customOut":{"$id":"812"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":690},"$type":"TransformData"},"CurvePointTangent":{"$ref":"811"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":690},"$type":"TransformData"},"CurvePointTangent":{"$ref":"812"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":691},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"823"},"customOut":{"$id":"824"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":691},"$type":"TransformData"},"CurvePointTangent":{"$ref":"823"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":691},"$type":"TransformData"},"CurvePointTangent":{"$ref":"824"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":720},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"837"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":720},"$type":"TransformData"},"CurveParent":{"$ref":"837"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":720},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"849"},"customOut":{"$id":"850"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":720},"$type":"TransformData"},"CurvePointTangent":{"$ref":"849"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":720},"$type":"TransformData"},"CurvePointTangent":{"$ref":"850"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":721},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"861"},"customOut":{"$id":"862"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":721},"$type":"TransformData"},"CurvePointTangent":{"$ref":"861"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":721},"$type":"TransformData"},"CurvePointTangent":{"$ref":"862"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":750},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"875"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":750},"$type":"TransformData"},"CurveParent":{"$ref":"875"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":750},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"887"},"customOut":{"$id":"888"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":750},"$type":"TransformData"},"CurvePointTangent":{"$ref":"887"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":750},"$type":"TransformData"},"CurvePointTangent":{"$ref":"888"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":751},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"899"},"customOut":{"$id":"900"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":751},"$type":"TransformData"},"CurvePointTangent":{"$ref":"899"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":751},"$type":"TransformData"},"CurvePointTangent":{"$ref":"900"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":780},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"913"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":780},"$type":"TransformData"},"CurveParent":{"$ref":"913"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":780},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"925"},"customOut":{"$id":"926"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":780},"$type":"TransformData"},"CurvePointTangent":{"$ref":"925"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":780},"$type":"TransformData"},"CurvePointTangent":{"$ref":"926"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":781},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"937"},"customOut":{"$id":"938"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":781},"$type":"TransformData"},"CurvePointTangent":{"$ref":"937"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":781},"$type":"TransformData"},"CurvePointTangent":{"$ref":"938"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":810},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"951"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":810},"$type":"TransformData"},"CurveParent":{"$ref":"951"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":810},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"963"},"customOut":{"$id":"964"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":810},"$type":"TransformData"},"CurvePointTangent":{"$ref":"963"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":810},"$type":"TransformData"},"CurvePointTangent":{"$ref":"964"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":811},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"975"},"customOut":{"$id":"976"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":811},"$type":"TransformData"},"CurvePointTangent":{"$ref":"975"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":811},"$type":"TransformData"},"CurvePointTangent":{"$ref":"976"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":840},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"989"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":840},"$type":"TransformData"},"CurveParent":{"$ref":"989"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":840},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1001"},"customOut":{"$id":"1002"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":840},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1001"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":840},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1002"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":841},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1013"},"customOut":{"$id":"1014"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":841},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1013"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":841},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1014"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":870},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1027"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":870},"$type":"TransformData"},"CurveParent":{"$ref":"1027"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":870},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1039"},"customOut":{"$id":"1040"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":870},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1039"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":870},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1040"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":871},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1051"},"customOut":{"$id":"1052"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":871},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1051"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":871},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1052"}},"children":[]}]}]}]}]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":615},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":585},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":675},"$type":"TransformData"}},"children":[]}]},{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":879},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_side","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"randomizer","components":{"Transform":{"position":{"x":20,"y":0,"z":840},"$type":"TransformData"},"Randomizer":{"$ref":"21"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":20,"y":0,"z":975},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1035},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":1080},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1119"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1080},"$type":"TransformData"},"CurveParent":{"$ref":"1119"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1080},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1131"},"customOut":{"$id":"1132"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1080},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1131"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":1178.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1132"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1178.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1143"},"customOut":{"$id":"1144"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":1080},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1143"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1178.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1144"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1155},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"group","components":{"Transform":{"position":{"x":20,"y":0,"z":975},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1035},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1275},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":1275},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1188"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.8,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1275},"$type":"TransformData"},"CurveParent":{"$ref":"1188"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1275},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1200"},"customOut":{"$id":"1201"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1275},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1200"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":1373.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1201"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1373.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1212"},"customOut":{"$id":"1213"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":1275},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1212"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1373.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1213"}},"children":[]}]}]}]}]},{"name":"group","components":{"Transform":{"position":{"x":20,"y":0,"z":975},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":20,"y":29,"z":975},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":1050},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1232"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1050},"$type":"TransformData"},"CurveParent":{"$ref":"1232"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1050},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1244"},"customOut":{"$id":"1245"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1050},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1244"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1050},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1245"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1051},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1256"},"customOut":{"$id":"1257"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1051},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1256"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1051},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1257"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":1080},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1270"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1080},"$type":"TransformData"},"CurveParent":{"$ref":"1270"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1080},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1282"},"customOut":{"$id":"1283"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1080},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1282"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1080},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1283"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1081},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1294"},"customOut":{"$id":"1295"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1081},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1294"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1081},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1295"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":1110},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1308"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1110},"$type":"TransformData"},"CurveParent":{"$ref":"1308"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1110},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1320"},"customOut":{"$id":"1321"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1110},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1320"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1110},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1321"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1111},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1332"},"customOut":{"$id":"1333"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1111},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1332"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1111},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1333"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":1140},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1346"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1140},"$type":"TransformData"},"CurveParent":{"$ref":"1346"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1140},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1358"},"customOut":{"$id":"1359"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1140},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1358"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1140},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1359"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1141},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1370"},"customOut":{"$id":"1371"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1141},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1370"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1141},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1371"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":1170},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1384"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1170},"$type":"TransformData"},"CurveParent":{"$ref":"1384"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1170},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1396"},"customOut":{"$id":"1397"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1170},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1396"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1170},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1397"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1171},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1408"},"customOut":{"$id":"1409"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1171},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1408"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1171},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1409"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":1200},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1422"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1200},"$type":"TransformData"},"CurveParent":{"$ref":"1422"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1200},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1434"},"customOut":{"$id":"1435"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1200},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1434"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1200},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1435"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1201},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1446"},"customOut":{"$id":"1447"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1201},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1446"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1201},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1447"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":1230},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1460"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1230},"$type":"TransformData"},"CurveParent":{"$ref":"1460"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1230},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1472"},"customOut":{"$id":"1473"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1230},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1472"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1230},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1473"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1231},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1484"},"customOut":{"$id":"1485"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1231},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1484"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1231},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1485"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":1260},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1498"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1260},"$type":"TransformData"},"CurveParent":{"$ref":"1498"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1260},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1510"},"customOut":{"$id":"1511"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1260},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1510"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1260},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1511"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1261},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1522"},"customOut":{"$id":"1523"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1261},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1522"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1261},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1523"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":20,"y":29,"z":1290},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1536"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1290},"$type":"TransformData"},"CurveParent":{"$ref":"1536"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1290},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1548"},"customOut":{"$id":"1549"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1548"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1290},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1549"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1291},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1560"},"customOut":{"$id":"1561"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1291},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1560"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1291},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1561"}},"children":[]}]}]}]}]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1035},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":-20,"y":7,"z":990},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":990},"$type":"TransformData"}},"children":[]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1005},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1035},"$type":"TransformData"}},"children":[]}]},{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1301},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_side","components":{"Transform":{"position":{"x":0,"y":0,"z":1395},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"randomizer","components":{"Transform":{"position":{"x":-20,"y":0,"z":1260},"$type":"TransformData"},"Randomizer":{"$ref":"24"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":1395},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1455},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1500},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1642"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1500},"$type":"TransformData"},"CurveParent":{"$ref":"1642"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1500},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1654"},"customOut":{"$id":"1655"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1500},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1654"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":1598.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1655"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1598.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1666"},"customOut":{"$id":"1667"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":1500},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1666"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1598.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1667"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1575},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":1395},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1455},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1695},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1695},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1711"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.8,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1695},"$type":"TransformData"},"CurveParent":{"$ref":"1711"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1695},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1723"},"customOut":{"$id":"1724"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1695},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1723"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":1793.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1724"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1793.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1735"},"customOut":{"$id":"1736"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":1695},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1735"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1793.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1736"}},"children":[]}]}]}]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":0,"z":1395},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":-20,"y":29,"z":1395},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1470},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1755"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1470},"$type":"TransformData"},"CurveParent":{"$ref":"1755"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1470},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1767"},"customOut":{"$id":"1768"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1470},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1767"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1470},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1768"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1471},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1779"},"customOut":{"$id":"1780"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1471},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1779"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1471},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1780"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1500},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1793"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1500},"$type":"TransformData"},"CurveParent":{"$ref":"1793"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1500},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1805"},"customOut":{"$id":"1806"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1500},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1805"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1500},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1806"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1501},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1817"},"customOut":{"$id":"1818"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1501},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1817"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1501},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1818"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1530},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1831"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1530},"$type":"TransformData"},"CurveParent":{"$ref":"1831"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1530},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1843"},"customOut":{"$id":"1844"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1530},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1843"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1530},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1844"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1531},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1855"},"customOut":{"$id":"1856"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1531},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1855"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1531},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1856"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1560},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1869"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1560},"$type":"TransformData"},"CurveParent":{"$ref":"1869"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1560},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1881"},"customOut":{"$id":"1882"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1560},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1881"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1560},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1882"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1561},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1893"},"customOut":{"$id":"1894"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1561},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1893"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1561},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1894"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1590},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1907"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1590},"$type":"TransformData"},"CurveParent":{"$ref":"1907"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1590},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1919"},"customOut":{"$id":"1920"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1590},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1919"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1590},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1920"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1591},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1931"},"customOut":{"$id":"1932"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1591},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1931"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1591},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1932"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1620},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1945"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1620},"$type":"TransformData"},"CurveParent":{"$ref":"1945"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1620},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1957"},"customOut":{"$id":"1958"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1620},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1957"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1620},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1958"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1621},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1969"},"customOut":{"$id":"1970"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1621},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1969"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1621},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1970"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1650},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1983"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1650},"$type":"TransformData"},"CurveParent":{"$ref":"1983"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1650},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1995"},"customOut":{"$id":"1996"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1650},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1995"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1650},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1996"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1651},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2007"},"customOut":{"$id":"2008"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1651},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2007"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1651},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2008"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1680},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2021"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1680},"$type":"TransformData"},"CurveParent":{"$ref":"2021"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1680},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2033"},"customOut":{"$id":"2034"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1680},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2033"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1680},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2034"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1681},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2045"},"customOut":{"$id":"2046"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1681},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2045"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1681},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2046"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1710},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2059"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1710},"$type":"TransformData"},"CurveParent":{"$ref":"2059"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1710},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2071"},"customOut":{"$id":"2072"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1710},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2071"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1710},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2072"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1711},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2083"},"customOut":{"$id":"2084"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1711},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2083"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1711},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2084"}},"children":[]}]}]}]}]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1455},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1425},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1425},"$type":"TransformData"}},"children":[]}]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":10,"y":0,"z":1530},"$type":"TransformData"}},"children":[]}]},"routeChunk_default_train_tops_moving_combined":{"name":"routeChunk_default_train_tops_moving_combined","components":{"Transform":{"position":{"x":0,"y":413.3,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":20,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"11"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"12"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"13"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"14"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"},{"$id":"23"},{"$id":"24"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"25"},{"$id":"26"},{"$id":"27"},{"$id":"28"},{"$id":"29"},{"$id":"30"},{"$id":"31"},{"$id":"32"},{"$id":"33"},{"$id":"34"},{"$id":"35"},{"$id":"36"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"37"},{"$id":"38"},{"$id":"39"},{"$id":"40"},{"$id":"41"},{"$id":"42"},{"$id":"43"},{"$id":"44"},{"$id":"45"},{"$id":"46"},{"$id":"47"},{"$id":"48"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"49"},{"$id":"50"},{"$id":"51"},{"$id":"52"},{"$id":"53"},{"$id":"54"},{"$id":"55"},{"$id":"56"},{"$id":"57"},{"$id":"58"},{"$id":"59"},{"$id":"60"},{"$id":"61"},{"$id":"62"},{"$id":"63"},{"$id":"64"},{"$id":"65"},{"$id":"66"},{"$id":"67"},{"$id":"68"},{"$id":"69"},{"$id":"70"},{"$id":"71"},{"$id":"72"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_train_tops_moving_combined","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_start","components":{"Transform":{"position":{"x":0,"y":413.3,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":60},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":439.5,"z":105},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":439.5,"z":105},"$type":"TransformData"}},"children":[]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":120},"$type":"TransformData"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":120},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":150},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":150},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":442.3,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"146"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":442.3,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"146"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":442.3,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"158"},"customOut":{"$id":"159"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":442.3,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"158"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":442.3,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"159"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":442.3,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"170"},"customOut":{"$id":"171"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":442.3,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"170"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":442.3,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"171"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":195},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"184"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":195},"$type":"TransformData"},"CurveParent":{"$ref":"184"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":195},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"196"},"customOut":{"$id":"197"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"196"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":195},"$type":"TransformData"},"CurvePointTangent":{"$ref":"197"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":296},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"208"},"customOut":{"$id":"209"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":296},"$type":"TransformData"},"CurvePointTangent":{"$ref":"208"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":296},"$type":"TransformData"},"CurvePointTangent":{"$ref":"209"}},"children":[]}]}]}]}]},{"name":"side","components":{"Transform":{"position":{"x":0,"y":413.3,"z":395.3984},"$type":"TransformData"},"Randomizer":{"$ref":"10"}},"children":[{"name":"trains_side_ground","components":{"Transform":{"position":{"x":0,"y":413.3,"z":395.3984},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":515.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":515.3984},"$type":"TransformData"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":665.3984},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":695.3984},"$type":"TransformData"}},"children":[]}]},{"name":"trains_side","components":{"Transform":{"position":{"x":0,"y":413.3,"z":395.3984},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"randomizer","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":260.3984},"$type":"TransformData"},"Randomizer":{"$ref":"25"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":395.3984},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":455.3984},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":500.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"284"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":500.3984},"$type":"TransformData"},"CurveParent":{"$ref":"284"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":500.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"296"},"customOut":{"$id":"297"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":500.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"296"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":598.7854},"$type":"TransformData"},"CurvePointTangent":{"$ref":"297"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":598.7854},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"308"},"customOut":{"$id":"309"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":500.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"308"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":598.7854},"$type":"TransformData"},"CurvePointTangent":{"$ref":"309"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":575.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":395.3984},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":455.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":695.3984},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":695.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"353"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.8,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":695.3984},"$type":"TransformData"},"CurveParent":{"$ref":"353"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":695.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"365"},"customOut":{"$id":"366"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":695.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"365"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":793.7854},"$type":"TransformData"},"CurvePointTangent":{"$ref":"366"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":793.7854},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"377"},"customOut":{"$id":"378"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":695.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"377"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":793.7854},"$type":"TransformData"},"CurvePointTangent":{"$ref":"378"}},"children":[]}]}]}]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":395.3984},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":395.3984},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":470.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"397"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":470.3984},"$type":"TransformData"},"CurveParent":{"$ref":"397"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":470.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"409"},"customOut":{"$id":"410"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":470.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"409"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":470.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"410"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":471.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"421"},"customOut":{"$id":"422"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":471.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"421"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":471.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"422"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":500.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"435"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":500.3984},"$type":"TransformData"},"CurveParent":{"$ref":"435"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":500.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"447"},"customOut":{"$id":"448"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":500.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"447"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":500.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"448"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":501.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"459"},"customOut":{"$id":"460"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":501.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"459"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":501.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"460"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":530.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"473"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":530.3984},"$type":"TransformData"},"CurveParent":{"$ref":"473"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":530.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"485"},"customOut":{"$id":"486"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":530.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"485"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":530.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"486"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":531.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"497"},"customOut":{"$id":"498"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":531.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"497"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":531.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"498"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":560.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"511"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":560.3984},"$type":"TransformData"},"CurveParent":{"$ref":"511"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":560.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"523"},"customOut":{"$id":"524"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":560.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"523"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":560.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"524"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":561.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"535"},"customOut":{"$id":"536"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":561.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"535"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":561.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"536"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":590.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"549"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":590.3984},"$type":"TransformData"},"CurveParent":{"$ref":"549"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":590.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"561"},"customOut":{"$id":"562"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":590.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"561"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":590.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"562"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":591.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"573"},"customOut":{"$id":"574"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":591.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"573"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":591.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"574"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":620.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"587"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":620.3984},"$type":"TransformData"},"CurveParent":{"$ref":"587"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":620.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"599"},"customOut":{"$id":"600"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":620.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"599"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":620.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"600"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":621.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"611"},"customOut":{"$id":"612"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":621.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"611"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":621.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"612"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":650.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"625"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":650.3984},"$type":"TransformData"},"CurveParent":{"$ref":"625"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":650.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"637"},"customOut":{"$id":"638"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":650.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"637"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":650.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"638"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":651.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"649"},"customOut":{"$id":"650"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":651.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"649"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":651.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"650"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":680.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"663"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":680.3984},"$type":"TransformData"},"CurveParent":{"$ref":"663"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":680.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"675"},"customOut":{"$id":"676"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":680.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"675"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":680.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"676"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":681.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"687"},"customOut":{"$id":"688"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":681.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"687"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":681.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"688"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":710.3984},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"701"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":710.3984},"$type":"TransformData"},"CurveParent":{"$ref":"701"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":710.3984},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"713"},"customOut":{"$id":"714"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":710.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"713"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":710.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"714"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":711.3984},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"725"},"customOut":{"$id":"726"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":711.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"725"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":711.3984},"$type":"TransformData"},"CurvePointTangent":{"$ref":"726"}},"children":[]}]}]}]}]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":455.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":425.3984},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":425.3984},"$type":"TransformData"}},"children":[]}]},{"name":"3 moving sides","components":{"Transform":{"position":{"x":0,"y":413.3,"z":395.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":454.3984},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":662.3984},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]},{"name":"middle","components":{"Transform":{"position":{"x":0,"y":413.3,"z":448.5102},"$type":"TransformData"},"Randomizer":{"$ref":"11"}},"children":[{"name":"1 moving","components":{"Transform":{"position":{"x":0,"y":413.3,"z":13.31934},"$type":"TransformData"}},"children":[{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":283.3193},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"3 moving coins","components":{"Transform":{"position":{"x":0,"y":413.3,"z":608.8612},"$type":"TransformData"}},"children":[{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":270.8612},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":418.8612},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]},{"name":"side","components":{"Transform":{"position":{"x":0,"y":413.3,"z":842.0803},"$type":"TransformData"},"Randomizer":{"$ref":"12"}},"children":[{"name":"trains_side_ground","components":{"Transform":{"position":{"x":0,"y":413.3,"z":842.0803},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":962.0803},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":962.0803},"$type":"TransformData"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":1112.08},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":1142.08},"$type":"TransformData"}},"children":[]}]},{"name":"trains_side","components":{"Transform":{"position":{"x":0,"y":413.3,"z":842.0803},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"randomizer","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":707.0803},"$type":"TransformData"},"Randomizer":{"$ref":"37"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":842.0803},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":902.0803},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":947.0803},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"888"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":947.0803},"$type":"TransformData"},"CurveParent":{"$ref":"888"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":947.0803},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"900"},"customOut":{"$id":"901"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":947.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"900"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":1045.467},"$type":"TransformData"},"CurvePointTangent":{"$ref":"901"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1045.467},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"912"},"customOut":{"$id":"913"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":947.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"912"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1045.467},"$type":"TransformData"},"CurvePointTangent":{"$ref":"913"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1022.08},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":842.0803},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":902.0803},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1142.08},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1142.08},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"957"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.8,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1142.08},"$type":"TransformData"},"CurveParent":{"$ref":"957"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1142.08},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"969"},"customOut":{"$id":"970"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1142.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"969"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":1240.467},"$type":"TransformData"},"CurvePointTangent":{"$ref":"970"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1240.467},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"981"},"customOut":{"$id":"982"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":1142.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"981"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1240.467},"$type":"TransformData"},"CurvePointTangent":{"$ref":"982"}},"children":[]}]}]}]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":842.0803},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":842.0803},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":917.0803},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1001"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":917.0803},"$type":"TransformData"},"CurveParent":{"$ref":"1001"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":917.0803},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1013"},"customOut":{"$id":"1014"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":917.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1013"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":917.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1014"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":918.0803},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1025"},"customOut":{"$id":"1026"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":918.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1025"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":918.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1026"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":947.0803},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1039"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":947.0803},"$type":"TransformData"},"CurveParent":{"$ref":"1039"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":947.0803},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1051"},"customOut":{"$id":"1052"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":947.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1051"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":947.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1052"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":948.0803},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1063"},"customOut":{"$id":"1064"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":948.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1063"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":948.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1064"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":977.0803},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1077"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":977.0803},"$type":"TransformData"},"CurveParent":{"$ref":"1077"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":977.0803},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1089"},"customOut":{"$id":"1090"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":977.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1089"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":977.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1090"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":978.0803},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1101"},"customOut":{"$id":"1102"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":978.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1101"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":978.0803},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1102"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1007.08},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1115"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1007.08},"$type":"TransformData"},"CurveParent":{"$ref":"1115"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1007.08},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1127"},"customOut":{"$id":"1128"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1007.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1127"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1007.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1128"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1008.08},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1139"},"customOut":{"$id":"1140"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1008.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1139"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1008.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1140"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1037.08},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1153"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1037.08},"$type":"TransformData"},"CurveParent":{"$ref":"1153"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1037.08},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1165"},"customOut":{"$id":"1166"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1037.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1165"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1037.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1166"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1038.08},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1177"},"customOut":{"$id":"1178"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1038.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1177"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1038.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1178"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1067.08},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1191"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1067.08},"$type":"TransformData"},"CurveParent":{"$ref":"1191"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1067.08},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1203"},"customOut":{"$id":"1204"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1067.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1203"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1067.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1204"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1068.08},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1215"},"customOut":{"$id":"1216"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1068.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1215"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1068.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1216"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1097.08},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1229"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1097.08},"$type":"TransformData"},"CurveParent":{"$ref":"1229"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1097.08},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1241"},"customOut":{"$id":"1242"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1097.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1241"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1097.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1242"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1098.08},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1253"},"customOut":{"$id":"1254"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1098.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1253"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1098.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1254"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1127.08},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1267"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1127.08},"$type":"TransformData"},"CurveParent":{"$ref":"1267"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1127.08},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1279"},"customOut":{"$id":"1280"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1127.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1279"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1127.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1280"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1128.08},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1291"},"customOut":{"$id":"1292"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1128.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1291"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1128.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1292"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1157.08},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1305"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1157.08},"$type":"TransformData"},"CurveParent":{"$ref":"1305"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1157.08},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1317"},"customOut":{"$id":"1318"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1157.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1317"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1157.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1318"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1158.08},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1329"},"customOut":{"$id":"1330"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1158.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1329"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1158.08},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1330"}},"children":[]}]}]}]}]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":902.0803},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":872.0803},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":872.0803},"$type":"TransformData"}},"children":[]}]},{"name":"3 moving sides","components":{"Transform":{"position":{"x":0,"y":413.3,"z":842.0803},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":901.0803},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1109.08},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]},{"name":"middle","components":{"Transform":{"position":{"x":0,"y":413.3,"z":895.1921},"$type":"TransformData"},"Randomizer":{"$ref":"13"}},"children":[{"name":"1 moving","components":{"Transform":{"position":{"x":0,"y":413.3,"z":460.0012},"$type":"TransformData"}},"children":[{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":730.0012},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"3 moving coins","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1055.543},"$type":"TransformData"}},"children":[{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":717.543},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":865.543},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]},{"name":"side","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1290.069},"$type":"TransformData"},"Randomizer":{"$ref":"14"}},"children":[{"name":"trains_side_ground","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1290.069},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":1410.069},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1410.069},"$type":"TransformData"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":1590.069},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":1620.069},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"trains_side","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1290.069},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"randomizer","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1155.069},"$type":"TransformData"},"Randomizer":{"$ref":"49"}},"children":[{"name":"group","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1290.069},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1350.069},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1395.069},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1490"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1395.069},"$type":"TransformData"},"CurveParent":{"$ref":"1490"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1395.069},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1502"},"customOut":{"$id":"1503"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1395.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1502"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":1493.456},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1503"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1493.456},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1514"},"customOut":{"$id":"1515"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":1395.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1514"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1493.456},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1515"}},"children":[]}]}]}]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1470.069},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1290.069},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1350.069},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1590.069},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1590.069},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1559"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.8,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1590.069},"$type":"TransformData"},"CurveParent":{"$ref":"1559"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1590.069},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1571"},"customOut":{"$id":"1572"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1590.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1571"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":1688.456},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1572"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1688.456},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1583"},"customOut":{"$id":"1584"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":522.3,"z":1590.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1583"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1688.456},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1584"}},"children":[]}]}]}]}]},{"name":"group","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1290.069},"$type":"TransformData"}},"children":[{"name":"coins","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1290.069},"$type":"TransformData"}},"children":[{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1365.069},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1603"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1365.069},"$type":"TransformData"},"CurveParent":{"$ref":"1603"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1365.069},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1615"},"customOut":{"$id":"1616"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1365.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1615"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1365.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1616"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1366.069},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1627"},"customOut":{"$id":"1628"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1366.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1627"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1366.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1628"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1395.069},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1641"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1395.069},"$type":"TransformData"},"CurveParent":{"$ref":"1641"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1395.069},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1653"},"customOut":{"$id":"1654"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1395.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1653"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1395.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1654"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1396.069},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1665"},"customOut":{"$id":"1666"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1396.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1665"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1396.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1666"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1425.069},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1679"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1425.069},"$type":"TransformData"},"CurveParent":{"$ref":"1679"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1425.069},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1691"},"customOut":{"$id":"1692"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1425.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1691"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1425.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1692"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1426.069},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1703"},"customOut":{"$id":"1704"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1426.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1703"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1426.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1704"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1455.069},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1717"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1455.069},"$type":"TransformData"},"CurveParent":{"$ref":"1717"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1455.069},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1729"},"customOut":{"$id":"1730"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1455.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1729"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1455.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1730"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1456.069},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1741"},"customOut":{"$id":"1742"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1456.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1741"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1456.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1742"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1485.069},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1755"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1485.069},"$type":"TransformData"},"CurveParent":{"$ref":"1755"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1485.069},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1767"},"customOut":{"$id":"1768"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1485.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1767"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1485.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1768"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1486.069},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1779"},"customOut":{"$id":"1780"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1486.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1779"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1486.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1780"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1515.069},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1793"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1515.069},"$type":"TransformData"},"CurveParent":{"$ref":"1793"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1515.069},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1805"},"customOut":{"$id":"1806"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1515.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1805"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1515.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1806"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1516.069},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1817"},"customOut":{"$id":"1818"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1516.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1817"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1516.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1818"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1545.069},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1831"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1545.069},"$type":"TransformData"},"CurveParent":{"$ref":"1831"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1545.069},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1843"},"customOut":{"$id":"1844"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1545.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1843"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1545.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1844"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1546.069},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1855"},"customOut":{"$id":"1856"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1546.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1855"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1546.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1856"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1575.069},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1869"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1575.069},"$type":"TransformData"},"CurveParent":{"$ref":"1869"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1575.069},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1881"},"customOut":{"$id":"1882"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1575.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1881"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1575.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1882"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1576.069},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1893"},"customOut":{"$id":"1894"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1576.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1893"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1576.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1894"}},"children":[]}]}]}]},{"name":"Coin (Single)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1605.069},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":1},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1907"},"_scaleMode":"NoScale","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1605.069},"$type":"TransformData"},"CurveParent":{"$ref":"1907"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1605.069},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1919"},"customOut":{"$id":"1920"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1605.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1919"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1605.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1920"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1606.069},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1931"},"customOut":{"$id":"1932"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1606.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1931"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":442.3,"z":1606.069},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1932"}},"children":[]}]}]}]}]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1350.069},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1320.069},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":20,"y":413.3,"z":1320.069},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":413.3,"z":1740.069},"$type":"TransformData"}},"children":[]}]},{"name":"3 moving sides","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1290.069},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1349.069},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1557.069},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]},{"name":"middle","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1343.181},"$type":"TransformData"},"Randomizer":{"$ref":"15"}},"children":[{"name":"1 moving","components":{"Transform":{"position":{"x":0,"y":413.3,"z":907.9899},"$type":"TransformData"}},"children":[{"name":"trains_5_moving_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1177.99},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"3 moving coins","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1503.532},"$type":"TransformData"}},"children":[{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1165.532},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":413.3,"z":1313.532},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]}]},"routeChunk_default_train_tops_moving_multiple":{"name":"routeChunk_default_train_tops_moving_multiple","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":20,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"},{"$id":"23"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_train_tops_moving_multiple","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"trains_start","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":0},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":-20,"y":37,"z":165},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":37,"z":165},"$type":"TransformData"}},"children":[]}]},{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":270},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"trains_moving_sides","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"}},"children":[{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":660},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1060},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1460},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"trains_moving_mid","components":{"Transform":{"position":{"x":0,"y":0,"z":120},"$type":"TransformData"}},"children":[{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":382},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":575},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":772},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":975},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1175},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]},{"name":"trains_3_moving_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1375},"$type":"TransformData"},"MovingTrainPlaceholder":{"_speed":0.5,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":0,"y":55,"z":210},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":55,"z":210},"$type":"TransformData"}},"children":[]}]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":10,"y":0,"z":1530},"$type":"TransformData"}},"children":[]}]},"routeChunk_default_tunnel":{"name":"routeChunk_default_tunnel","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":6,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"9"},{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_tunnel","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"random_tunnel","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"9"}},"children":[{"name":"sides","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"gates_sides_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"Mirror","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"46"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"CurveParent":{"$ref":"46"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"58"},"customOut":{"$id":"59"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"CurvePointTangent":{"$ref":"58"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"CurvePointTangent":{"$ref":"59"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":221},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"70"},"customOut":{"$id":"71"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":221},"$type":"TransformData"},"CurvePointTangent":{"$ref":"70"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":221},"$type":"TransformData"},"CurvePointTangent":{"$ref":"71"}},"children":[]}]}]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":-20,"y":7,"z":150},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":-20,"y":7,"z":150},"$type":"TransformData"}},"children":[]}]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":309},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"right","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"gates_right_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":30},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":64.60001,"z":225},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":64.60001,"z":225},"$type":"TransformData"}},"children":[]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":309},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"mid","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"gates_mid_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":309},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]},{"name":"left","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"gates_left_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":30},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Medium)","components":{"Transform":{"position":{"x":20,"y":64.60001,"z":225},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Medium","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":64.60001,"z":225},"$type":"TransformData"}},"children":[]}]},{"name":"trains_3_moving_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":309},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"},"MovingTrainPlaceholder":{"_speed":1,"$type":"SYBO.Subway.Placeholders.MovingTrainPlaceholder"}},"children":[]}]}]},{"name":"environment","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"gates_environment","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Gates,All","_density":""},"_blockCount":4,"$type":"SYBO.Subway.Level.Environment"}},"children":[]}]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":10,"y":0,"z":480},"$type":"TransformData"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":510},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":510},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_bonus_long":{"name":"routeChunk_default_bonus_long","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":14,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"15"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"16"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"17"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"18"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"19"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"20"},{"$id":"21"},{"$id":"22"},{"$id":"23"},{"$id":"24"},{"$id":"25"},{"$id":"26"},{"$id":"27"},{"$id":"28"},{"$id":"29"},{"$id":"30"},{"$id":"31"},{"$id":"32"},{"$id":"33"},{"$id":"34"},{"$id":"35"},{"$id":"36"},{"$id":"37"},{"$id":"38"},{"$id":"39"},{"$id":"40"},{"$id":"41"},{"$id":"42"},{"$id":"43"},{"$id":"44"},{"$id":"45"},{"$id":"46"},{"$id":"47"},{"$id":"48"},{"$id":"49"},{"$id":"50"},{"$id":"51"},{"$id":"52"},{"$id":"53"},{"$id":"54"},{"$id":"55"},{"$id":"56"},{"$id":"57"},{"$id":"58"},{"$id":"59"},{"$id":"60"},{"$id":"61"},{"$id":"62"},{"$id":"63"},{"$id":"64"},{"$id":"65"},{"$id":"66"},{"$id":"67"},{"$id":"68"},{"$id":"69"},{"$id":"70"},{"$id":"71"},{"$id":"72"},{"$id":"73"},{"$id":"74"},{"$id":"75"},{"$id":"76"},{"$id":"77"},{"$id":"78"},{"$id":"79"},{"$id":"80"},{"$id":"81"},{"$id":"82"},{"$id":"83"},{"$id":"84"},{"$id":"85"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_bonus_long","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"random_start","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"Randomizer":{"$ref":"10"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"}},"children":[]},{"name":"blocker_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"Randomizer":{"$ref":"11"}},"children":[{"name":"ground_run","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[{"name":"ground","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"Randomizer":{"$ref":"15"}},"children":[{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"138"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"138"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"150"},"customOut":{"$id":"151"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"150"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"151"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":436},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"162"},"customOut":{"$id":"163"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"162"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"163"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"176"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"176"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"188"},"customOut":{"$id":"189"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"188"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"189"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":436},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"200"},"customOut":{"$id":"201"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"200"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"201"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"214"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"214"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"226"},"customOut":{"$id":"227"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"226"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"227"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":436},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"238"},"customOut":{"$id":"239"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"238"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"239"}},"children":[]}]}]}]}]},{"name":"3","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":360},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":360},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"278"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"278"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"290"},"customOut":{"$id":"291"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"290"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"291"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":436},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"302"},"customOut":{"$id":"303"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"302"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"303"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":360},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"4","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"329"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurveParent":{"$ref":"329"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"341"},"customOut":{"$id":"342"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"341"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":285},"$type":"TransformData"},"CurvePointTangent":{"$ref":"342"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":436},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"353"},"customOut":{"$id":"354"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"353"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":436},"$type":"TransformData"},"CurvePointTangent":{"$ref":"354"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":360},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":20,"y":7,"z":240},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":7,"z":240},"$type":"TransformData"}},"children":[]}]},{"name":"ground","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"},"Randomizer":{"$ref":"16"}},"children":[{"name":"3","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"}},"children":[{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":660},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":660},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"4","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"421"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"421"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"433"},"customOut":{"$id":"434"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"433"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"434"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":736},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"445"},"customOut":{"$id":"446"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"445"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"446"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":660},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"472"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"472"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"484"},"customOut":{"$id":"485"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"484"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"485"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"496"},"customOut":{"$id":"497"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"496"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"497"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":660},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"523"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"523"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"535"},"customOut":{"$id":"536"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"535"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"536"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":736},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"547"},"customOut":{"$id":"548"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"547"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"548"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"561"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"561"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"573"},"customOut":{"$id":"574"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"573"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"574"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":736},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"585"},"customOut":{"$id":"586"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"585"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"586"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"599"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurveParent":{"$ref":"599"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"611"},"customOut":{"$id":"612"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"611"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":585},"$type":"TransformData"},"CurvePointTangent":{"$ref":"612"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"623"},"customOut":{"$id":"624"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"623"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":736},"$type":"TransformData"},"CurvePointTangent":{"$ref":"624"}},"children":[]}]}]}]}]}]},{"name":"ground","components":{"Transform":{"position":{"x":0,"y":0,"z":780},"$type":"TransformData"},"Randomizer":{"$ref":"17"}},"children":[{"name":"3","components":{"Transform":{"position":{"x":0,"y":0,"z":780},"$type":"TransformData"}},"children":[{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":960},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":960},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"4","components":{"Transform":{"position":{"x":0,"y":0,"z":780},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":885},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"667"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":885},"$type":"TransformData"},"CurveParent":{"$ref":"667"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":885},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"679"},"customOut":{"$id":"680"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"679"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"680"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":1036},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"691"},"customOut":{"$id":"692"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"691"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"692"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":960},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":780},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"718"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurveParent":{"$ref":"718"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"730"},"customOut":{"$id":"731"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"730"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"731"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"742"},"customOut":{"$id":"743"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"742"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"743"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":960},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":780},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":0,"z":885},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"769"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":885},"$type":"TransformData"},"CurveParent":{"$ref":"769"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":885},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"781"},"customOut":{"$id":"782"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"781"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"782"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":1036},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"793"},"customOut":{"$id":"794"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"793"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"794"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"807"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurveParent":{"$ref":"807"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"819"},"customOut":{"$id":"820"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"819"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"820"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"831"},"customOut":{"$id":"832"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"831"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"832"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":885},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"845"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":885},"$type":"TransformData"},"CurveParent":{"$ref":"845"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":885},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"857"},"customOut":{"$id":"858"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"857"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":885},"$type":"TransformData"},"CurvePointTangent":{"$ref":"858"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":1036},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"869"},"customOut":{"$id":"870"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"869"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":1036},"$type":"TransformData"},"CurvePointTangent":{"$ref":"870"}},"children":[]}]}]}]}]}]}]},{"name":"roof_run","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[{"name":"start","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":240},"$type":"TransformData"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":270},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":37,"z":285},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":37,"z":285},"$type":"TransformData"}},"children":[]}]}]},{"name":"roof","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"Randomizer":{"$ref":"18"}},"children":[{"name":"3","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":300},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":29,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"959"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"959"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"971"},"customOut":{"$id":"972"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"971"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"972"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":466},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"983"},"customOut":{"$id":"984"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":466},"$type":"TransformData"},"CurvePointTangent":{"$ref":"983"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":466},"$type":"TransformData"},"CurvePointTangent":{"$ref":"984"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"997"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"997"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1009"},"customOut":{"$id":"1010"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1009"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":443.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1010"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":443.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1021"},"customOut":{"$id":"1022"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1021"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":443.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1022"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":390},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":510},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":525},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1061"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.7,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":525},"$type":"TransformData"},"CurveParent":{"$ref":"1061"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":525},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1073"},"customOut":{"$id":"1074"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":525},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1073"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":623.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1074"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":623.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1085"},"customOut":{"$id":"1086"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":525},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1085"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":623.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1086"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":540},"$type":"TransformData"}},"children":[]}]},{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":300},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":29,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1141"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"1141"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1153"},"customOut":{"$id":"1154"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1153"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1154"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":466},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1165"},"customOut":{"$id":"1166"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":466},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1165"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":466},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1166"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1179"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CurveParent":{"$ref":"1179"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1191"},"customOut":{"$id":"1192"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1191"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1192"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":586},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1203"},"customOut":{"$id":"1204"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1203"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1204"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":465},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1217"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":465},"$type":"TransformData"},"CurveParent":{"$ref":"1217"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":465},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1229"},"customOut":{"$id":"1230"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":465},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1229"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":563.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1230"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":563.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1241"},"customOut":{"$id":"1242"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":465},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1241"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":563.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1242"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":510},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":540},"$type":"TransformData"}},"children":[]}]},{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":270},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":300},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":29,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1304"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"1304"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1316"},"customOut":{"$id":"1317"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1316"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1317"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":496},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1328"},"customOut":{"$id":"1329"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":496},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1328"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":496},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1329"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":29,"z":435},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1342"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":435},"$type":"TransformData"},"CurveParent":{"$ref":"1342"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":435},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1354"},"customOut":{"$id":"1355"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1354"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":109,"z":533.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1355"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":533.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1366"},"customOut":{"$id":"1367"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":109,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1366"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":533.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1367"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1380"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CurveParent":{"$ref":"1380"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1392"},"customOut":{"$id":"1393"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1392"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1393"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":586},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1404"},"customOut":{"$id":"1405"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1404"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":586},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1405"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":510},"$type":"TransformData"}},"children":[]}]}]},{"name":"roof","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"},"Randomizer":{"$ref":"19"}},"children":[{"name":"3","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":570},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":600},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":600},"$type":"TransformData"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":29,"z":615},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1469"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":615},"$type":"TransformData"},"CurveParent":{"$ref":"1469"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":615},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1481"},"customOut":{"$id":"1482"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":615},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1481"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":615},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1482"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":766},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1493"},"customOut":{"$id":"1494"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":766},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1493"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":766},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1494"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":645},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1507"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":645},"$type":"TransformData"},"CurveParent":{"$ref":"1507"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":645},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1519"},"customOut":{"$id":"1520"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":645},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1519"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":743.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1520"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":743.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1531"},"customOut":{"$id":"1532"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":645},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1531"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":743.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1532"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":690},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":720},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":810},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":825},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1571"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.7,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":825},"$type":"TransformData"},"CurveParent":{"$ref":"1571"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":825},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1583"},"customOut":{"$id":"1584"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":825},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1583"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":923.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1584"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":923.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1595"},"customOut":{"$id":"1596"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":825},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1595"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":923.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1596"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":840},"$type":"TransformData"}},"children":[]}]},{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":570},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":600},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":600},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":29,"z":615},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1651"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":615},"$type":"TransformData"},"CurveParent":{"$ref":"1651"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":615},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1663"},"customOut":{"$id":"1664"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":615},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1663"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":615},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1664"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":766},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1675"},"customOut":{"$id":"1676"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":766},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1675"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":766},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1676"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":29,"z":735},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1689"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":735},"$type":"TransformData"},"CurveParent":{"$ref":"1689"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":735},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1701"},"customOut":{"$id":"1702"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1701"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1702"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":886},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1713"},"customOut":{"$id":"1714"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1713"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1714"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":765},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1727"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":765},"$type":"TransformData"},"CurveParent":{"$ref":"1727"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":765},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1739"},"customOut":{"$id":"1740"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":765},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1739"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":863.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1740"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":863.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1751"},"customOut":{"$id":"1752"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":765},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1751"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":863.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1752"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":810},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":840},"$type":"TransformData"}},"children":[]}]},{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":480},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":570},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":600},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":600},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":29,"z":645},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1814"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":645},"$type":"TransformData"},"CurveParent":{"$ref":"1814"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":645},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1826"},"customOut":{"$id":"1827"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":645},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1826"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":645},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1827"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":796},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1838"},"customOut":{"$id":"1839"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":796},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1838"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":796},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1839"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":29,"z":735},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1852"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":735},"$type":"TransformData"},"CurveParent":{"$ref":"1852"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":735},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1864"},"customOut":{"$id":"1865"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1864"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":109,"z":833.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1865"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":833.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1876"},"customOut":{"$id":"1877"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":109,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1876"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":833.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1877"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":29,"z":735},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1890"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":735},"$type":"TransformData"},"CurveParent":{"$ref":"1890"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":735},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1902"},"customOut":{"$id":"1903"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1902"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":735},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1903"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":886},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1914"},"customOut":{"$id":"1915"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1914"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":886},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1915"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":780},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":810},"$type":"TransformData"}},"children":[]}]}]},{"name":"roof","components":{"Transform":{"position":{"x":0,"y":0,"z":780},"$type":"TransformData"},"Randomizer":{"$ref":"20"}},"children":[{"name":"3","components":{"Transform":{"position":{"x":0,"y":0,"z":780},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":870},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":900},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":900},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":29,"z":915},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1979"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":915},"$type":"TransformData"},"CurveParent":{"$ref":"1979"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":915},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1991"},"customOut":{"$id":"1992"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1991"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1992"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":1066},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2003"},"customOut":{"$id":"2004"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":1066},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2003"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":1066},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2004"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":945},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2017"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":945},"$type":"TransformData"},"CurveParent":{"$ref":"2017"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":945},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2029"},"customOut":{"$id":"2030"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2029"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":1043.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2030"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1043.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2041"},"customOut":{"$id":"2042"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2041"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1043.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2042"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":990},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1020},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1110},"$type":"TransformData"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":1125},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2081"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.7,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1125},"$type":"TransformData"},"CurveParent":{"$ref":"2081"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1125},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2093"},"customOut":{"$id":"2094"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1125},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2093"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":1223.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2094"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1223.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2105"},"customOut":{"$id":"2106"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":1125},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2105"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1223.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2106"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1140},"$type":"TransformData"}},"children":[]}]},{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":780},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":870},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":900},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":900},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":29,"z":915},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2161"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":915},"$type":"TransformData"},"CurveParent":{"$ref":"2161"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":915},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2173"},"customOut":{"$id":"2174"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2173"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":915},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2174"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":1066},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2185"},"customOut":{"$id":"2186"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":1066},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2185"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":1066},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2186"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":29,"z":1035},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2199"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1035},"$type":"TransformData"},"CurveParent":{"$ref":"2199"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1035},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2211"},"customOut":{"$id":"2212"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1035},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2211"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1035},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2212"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1186},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2223"},"customOut":{"$id":"2224"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1186},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2223"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1186},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2224"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1065},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2237"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":1065},"$type":"TransformData"},"CurveParent":{"$ref":"2237"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1065},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2249"},"customOut":{"$id":"2250"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1065},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2249"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":1163.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2250"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1163.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2261"},"customOut":{"$id":"2262"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":1065},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2261"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1163.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2262"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1110},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1140},"$type":"TransformData"}},"children":[]}]},{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":780},"$type":"TransformData"}},"children":[{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":870},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":900},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":900},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":29,"z":945},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2324"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":945},"$type":"TransformData"},"CurveParent":{"$ref":"2324"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":945},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2336"},"customOut":{"$id":"2337"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2336"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":945},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2337"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":1096},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2348"},"customOut":{"$id":"2349"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":1096},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2348"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":1096},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2349"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":29,"z":1035},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2362"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":1035},"$type":"TransformData"},"CurveParent":{"$ref":"2362"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":1035},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2374"},"customOut":{"$id":"2375"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":1035},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2374"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":109,"z":1133.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2375"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":1133.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2386"},"customOut":{"$id":"2387"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":109,"z":1035},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2386"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":1133.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2387"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":29,"z":1035},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"2400"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":1035},"$type":"TransformData"},"CurveParent":{"$ref":"2400"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":1035},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"2412"},"customOut":{"$id":"2413"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1035},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2412"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1035},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2413"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":1186},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"2424"},"customOut":{"$id":"2425"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":1186},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2424"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":1186},"$type":"TransformData"},"CurvePointTangent":{"$ref":"2425"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1080},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1110},"$type":"TransformData"}},"children":[]}]}]}]}]}]},"routeChunk_default_bonus_short":{"name":"routeChunk_default_bonus_short","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":6,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"},{"_type":"Tube,All","_density":""}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$type":"SYBO.Subway.Level.Randomizer","$id":"10"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"11"},{"$type":"SYBO.Subway.Level.Randomizer","$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"},{"$id":"23"},{"$id":"24"},{"$id":"25"},{"$id":"26"},{"$id":"27"},{"$id":"28"},{"$id":"29"},{"$id":"30"},{"$id":"31"},{"$id":"32"},{"$id":"33"},{"$id":"34"},{"$id":"35"},{"$id":"36"},{"$id":"37"},{"$id":"38"},{"$id":"39"},{"$id":"40"},{"$id":"41"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_bonus_short","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"random","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"10"}},"children":[{"name":"ground_run","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"ground","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"11"}},"children":[{"name":"3","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":180},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":0,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"81"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"81"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"93"},"customOut":{"$id":"94"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"93"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"94"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":496},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"105"},"customOut":{"$id":"106"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":496},"$type":"TransformData"},"CurvePointTangent":{"$ref":"105"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":496},"$type":"TransformData"},"CurvePointTangent":{"$ref":"106"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":375},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"129"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":375},"$type":"TransformData"},"CurveParent":{"$ref":"129"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":375},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"141"},"customOut":{"$id":"142"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"141"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"142"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":526},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"153"},"customOut":{"$id":"154"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":526},"$type":"TransformData"},"CurvePointTangent":{"$ref":"153"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":526},"$type":"TransformData"},"CurvePointTangent":{"$ref":"154"}},"children":[]}]}]}]}]},{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":105},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"170"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":105},"$type":"TransformData"},"CurveParent":{"$ref":"170"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":105},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"182"},"customOut":{"$id":"183"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"182"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"183"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"194"},"customOut":{"$id":"195"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"194"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"195"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":0,"z":105},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"208"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":105},"$type":"TransformData"},"CurveParent":{"$ref":"208"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":105},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"220"},"customOut":{"$id":"221"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"220"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"221"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"232"},"customOut":{"$id":"233"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"232"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"233"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":105},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"246"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":105},"$type":"TransformData"},"CurveParent":{"$ref":"246"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":105},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"258"},"customOut":{"$id":"259"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"258"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"259"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"270"},"customOut":{"$id":"271"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"270"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"271"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":420},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":420},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":420},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]},{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":105},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"317"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":105},"$type":"TransformData"},"CurveParent":{"$ref":"317"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":105},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"329"},"customOut":{"$id":"330"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"329"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":105},"$type":"TransformData"},"CurvePointTangent":{"$ref":"330"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"341"},"customOut":{"$id":"342"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"341"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":256},"$type":"TransformData"},"CurvePointTangent":{"$ref":"342"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":0,"z":315},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"365"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":0,"z":315},"$type":"TransformData"},"CurveParent":{"$ref":"365"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":0,"z":315},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"377"},"customOut":{"$id":"378"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"377"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":315},"$type":"TransformData"},"CurvePointTangent":{"$ref":"378"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":0,"z":466},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"389"},"customOut":{"$id":"390"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":0,"z":466},"$type":"TransformData"},"CurvePointTangent":{"$ref":"389"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":0,"z":466},"$type":"TransformData"},"CurvePointTangent":{"$ref":"390"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":0,"z":375},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"403"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":0,"z":375},"$type":"TransformData"},"CurveParent":{"$ref":"403"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":0,"z":375},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"415"},"customOut":{"$id":"416"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"415"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":375},"$type":"TransformData"},"CurvePointTangent":{"$ref":"416"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":0,"z":526},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"427"},"customOut":{"$id":"428"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":0,"z":526},"$type":"TransformData"},"CurvePointTangent":{"$ref":"427"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":0,"z":526},"$type":"TransformData"},"CurvePointTangent":{"$ref":"428"}},"children":[]}]}]}]},{"name":"blocker_w_coins_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":420},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]}]}]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":7,"z":60},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":7,"z":60},"$type":"TransformData"}},"children":[]}]}]},{"name":"roof_run","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"end","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":405},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"471"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":405},"$type":"TransformData"},"CurveParent":{"$ref":"471"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":405},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"483"},"customOut":{"$id":"484"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":405},"$type":"TransformData"},"CurvePointTangent":{"$ref":"483"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":503.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"484"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":503.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"495"},"customOut":{"$id":"496"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":405},"$type":"TransformData"},"CurvePointTangent":{"$ref":"495"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":503.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"496"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":0,"z":435},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":101},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"509"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":0,"z":435},"$type":"TransformData"},"CurveParent":{"$ref":"509"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":0,"z":435},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"521"},"customOut":{"$id":"522"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"521"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":435},"$type":"TransformData"},"CurvePointTangent":{"$ref":"522"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":0,"z":536},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"533"},"customOut":{"$id":"534"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":0,"z":536},"$type":"TransformData"},"CurvePointTangent":{"$ref":"533"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":0,"z":536},"$type":"TransformData"},"CurvePointTangent":{"$ref":"534"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":450},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"547"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.5,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":450},"$type":"TransformData"},"CurveParent":{"$ref":"547"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":450},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"559"},"customOut":{"$id":"560"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":450},"$type":"TransformData"},"CurvePointTangent":{"$ref":"559"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":548.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"560"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":548.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"571"},"customOut":{"$id":"572"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":450},"$type":"TransformData"},"CurvePointTangent":{"$ref":"571"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":548.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"572"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":480},"$type":"TransformData"}},"children":[]}]},{"name":"start","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":60},"$type":"TransformData"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":90},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":false,"right":true},"$type":"RandomizeOffset"}},"children":[]},{"name":"PickupSpawnPoint(Easy)","components":{"Transform":{"position":{"x":0,"y":37,"z":105},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"Normal","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"OnGround","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":0,"y":37,"z":105},"$type":"TransformData"}},"children":[]}]}]},{"name":"roof","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Randomizer":{"$ref":"12"}},"children":[{"name":"3","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":29,"z":135},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"675"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":135},"$type":"TransformData"},"CurveParent":{"$ref":"675"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":135},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"687"},"customOut":{"$id":"688"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"687"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"688"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"699"},"customOut":{"$id":"700"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"699"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"700"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"713"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"713"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"725"},"customOut":{"$id":"726"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"725"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":263.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"726"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":263.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"737"},"customOut":{"$id":"738"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"737"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":263.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"738"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":210},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":240},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":330},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"781"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.7,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CurveParent":{"$ref":"781"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"793"},"customOut":{"$id":"794"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"793"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":109,"z":443.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"794"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":443.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"805"},"customOut":{"$id":"806"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":109,"z":345},"$type":"TransformData"},"CurvePointTangent":{"$ref":"805"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":443.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"806"}},"children":[]}]}]}]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":360},"$type":"TransformData"}},"children":[]}]},{"name":"2","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Mirror":{"$type":"Mirror"}},"children":[{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":0,"y":29,"z":135},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"859"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":135},"$type":"TransformData"},"CurveParent":{"$ref":"859"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":135},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"871"},"customOut":{"$id":"872"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"871"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":135},"$type":"TransformData"},"CurvePointTangent":{"$ref":"872"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":286},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"883"},"customOut":{"$id":"884"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"883"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":286},"$type":"TransformData"},"CurvePointTangent":{"$ref":"884"}},"children":[]}]}]}]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"897"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"897"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"909"},"customOut":{"$id":"910"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"909"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":109,"z":263.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"910"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":263.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"921"},"customOut":{"$id":"922"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":109,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"921"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":263.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"922"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":210},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":240},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"955"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"955"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"967"},"customOut":{"$id":"968"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"967"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"968"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":406},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"979"},"customOut":{"$id":"980"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":406},"$type":"TransformData"},"CurvePointTangent":{"$ref":"979"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":406},"$type":"TransformData"},"CurvePointTangent":{"$ref":"980"}},"children":[]}]}]}]}]},{"name":"1","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":120},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Jump Curve)","components":{"Transform":{"position":{"x":0,"y":29,"z":150},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":true,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":98.38699},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1024"},"_scaleMode":"PreserveSpacing","_spacingMode":"NonStraight","_curveOffset":0.1,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":0,"y":29,"z":150},"$type":"TransformData"},"CurveParent":{"$ref":"1024"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":0,"y":29,"z":150},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1036"},"customOut":{"$id":"1037"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":29,"z":150},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1036"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":109,"z":248.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1037"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":0,"y":29,"z":248.387},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1048"},"customOut":{"$id":"1049"},"weight":1,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":0,"y":109,"z":150},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1048"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":0,"y":29,"z":248.387},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1049"}},"children":[]}]}]}]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1062"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CurveParent":{"$ref":"1062"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1074"},"customOut":{"$id":"1075"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1074"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":165},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1075"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":-20,"y":29,"z":316},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1086"},"customOut":{"$id":"1087"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":-20,"y":29,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1086"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":-20,"y":29,"z":316},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1087"}},"children":[]}]}]}]},{"name":"train_ramp_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":180},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":210},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"Coins (Line)","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CoinCurve":{"_curveParent":{"_disableGizmos":false,"color":{"r":1,"g":0,"b":0,"a":1},"_cachedCurve":{"MinCoords":{"x":0,"y":0,"z":0},"MaxCoords":{"x":0,"y":0,"z":151},"MinTime":0,"MaxTime":1},"_forceLinearZ":true,"$id":"1120"},"_scaleMode":"NoScale","_spacingMode":"Straight","_curveOffset":0,"_coinIndexToSkip":-1,"_redistributeAlongCurveOnSpeedChange":true,"_debugIsMovingTrain":false,"$type":"SYBO.Subway.Coins.CoinCurve"}},"children":[{"name":"CurveParent","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurveParent":{"$ref":"1120"}},"children":[{"name":"CurvePoint (0)","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePoint":{"t":0,"smoothTangents":false,"customIn":{"$id":"1132"},"customOut":{"$id":"1133"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1132"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":255},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1133"}},"children":[]}]},{"name":"CurvePoint (1)","components":{"Transform":{"position":{"x":20,"y":29,"z":406},"$type":"TransformData"},"CurvePoint":{"t":1,"smoothTangents":false,"customIn":{"$id":"1144"},"customOut":{"$id":"1145"},"weight":20,"$type":"CurvePoint"}},"children":[{"name":"In","components":{"Transform":{"position":{"x":20,"y":29,"z":406},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1144"}},"children":[]},{"name":"Out","components":{"Transform":{"position":{"x":20,"y":29,"z":406},"$type":"TransformData"},"CurvePointTangent":{"$ref":"1145"}},"children":[]}]}]}]}]}]}]}]}]},"routeChunk_default_pogostick_start":{"name":"routeChunk_default_pogostick_start","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":true,"_blockCount":2,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"Low,All"},{"_type":"Fillers,All","_density":"Medium,All"},{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_pogostick_start","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"PickupSpawnPoint(DynamicPogoStick)","components":{"Transform":{"position":{"x":20,"y":7,"z":90},"$type":"TransformData"},"PickupSpawnPoint":{"ContainingRoute":null,"_pickupParent":{},"__spawnPointMode":"WillForcePickupType","__forceSpawnPickupType":"PogoStick","_spawnPointDifficulty":"Easy","_spawnPointHeight":"","$type":"SYBO.Subway.Pickups.PickupSpawnPoint"},"RandomizeOffset":{"randomOffsets":{"left":true,"mid":true,"right":true},"$type":"RandomizeOffset"}},"children":[{"name":"PickupParent","components":{"Transform":{"position":{"x":20,"y":7,"z":90},"$type":"TransformData"}},"children":[]}]}]},"routeChunk_default_tutorial":{"name":"routeChunk_default_tutorial","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"RouteChunk":{"_isRepeatableInSections":false,"_blockCount":34,"_generateEnvironment":true,"_generateEnvironmentBase":true,"_limitedAllowedEnvironmentKinds":[{"_type":"Fillers,All","_density":"High,All"}],"_trackObjects":[],"_forcedEnvironmentBases":[],"_forcedEnvironments":[],"_selectors":[{"$id":"7"},{"$id":"8"},{"$id":"9"},{"$id":"10"},{"$id":"11"},{"$id":"12"},{"$id":"13"},{"$id":"14"},{"$id":"15"},{"$id":"16"},{"$id":"17"},{"$id":"18"},{"$id":"19"},{"$id":"20"},{"$id":"21"},{"$id":"22"},{"$id":"23"},{"$id":"24"},{"$id":"25"},{"$id":"26"},{"$id":"27"},{"$id":"28"},{"$id":"29"},{"$id":"30"},{"$id":"31"},{"$id":"32"}],"_routeTransitionTrigger":null,"Previous":null,"Next":null,"_reportedName":"default_tutorial","PreviewEnvironmentIndex":0,"$type":"SYBO.Subway.Routes.RouteChunk"}},"children":[{"name":"obstacles","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"train_sub_1_gen_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":90},"$type":"TransformData"}},"children":[]},{"name":"blocker_jump_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"}},"children":[]},{"name":"blocker_jump_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":540},"$type":"TransformData"}},"children":[]},{"name":"blocker_roll_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":900},"$type":"TransformData"}},"children":[]},{"name":"blocker_roll_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1080},"$type":"TransformData"}},"children":[]},{"name":"train_sub_1_gen_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1290},"$type":"TransformData"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1320},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1500},"$type":"TransformData"}},"children":[]},{"name":"trains_5_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1680},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"trains_1_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":1800},"$type":"TransformData"}},"children":[]},{"name":"trains_3_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1980},"$type":"TransformData"},"RandomizeOffset":{"randomOffsets":{"left":false,"mid":false,"right":false},"$type":"RandomizeOffset"}},"children":[]},{"name":"gates_mid_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":2520},"$type":"TransformData"}},"children":[]}]},{"name":"Ground","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"Trigger_up","components":{"Transform":{"position":{"x":0,"y":0,"z":203.0626},"$type":"TransformData"},"TutorialEvent":{"displayText":false,"tutorialText":"None","displayMesh":true,"direction":0,"time":1,"endTutorial":false,"allowHoverboard":false,"$type":"TutorialEvent"}},"children":[]},{"name":"Trigger_up","components":{"Transform":{"position":{"x":0,"y":0,"z":413.0626},"$type":"TransformData"},"TutorialEvent":{"displayText":false,"tutorialText":"None","displayMesh":true,"direction":0,"time":0.75,"endTutorial":false,"allowHoverboard":false,"$type":"TutorialEvent"}},"children":[]},{"name":"Trigger_down","components":{"Transform":{"position":{"x":0,"y":0,"z":763.0626},"$type":"TransformData"},"TutorialEvent":{"displayText":false,"tutorialText":"None","displayMesh":true,"direction":180,"time":0.75,"endTutorial":false,"allowHoverboard":false,"$type":"TutorialEvent"}},"children":[]},{"name":"Trigger_down","components":{"Transform":{"position":{"x":0,"y":0,"z":963.0626},"$type":"TransformData"},"TutorialEvent":{"displayText":false,"tutorialText":"None","displayMesh":true,"direction":180,"time":0.65,"endTutorial":false,"allowHoverboard":false,"$type":"TutorialEvent"}},"children":[]},{"name":"Trigger_good","components":{"Transform":{"position":{"x":0,"y":0,"z":1091.433},"$type":"TransformData"},"TutorialEvent":{"displayText":true,"tutorialText":"FreshMoves","displayMesh":false,"direction":0,"time":1,"endTutorial":false,"allowHoverboard":false,"$type":"TutorialEvent"}},"children":[]},{"name":"Trigger_left","components":{"Transform":{"position":{"x":0,"y":0,"z":1343.063},"$type":"TransformData"},"TutorialEvent":{"displayText":false,"tutorialText":"None","displayMesh":true,"direction":90,"time":1,"endTutorial":false,"allowHoverboard":false,"$type":"TutorialEvent"}},"children":[]},{"name":"Trigger_right","components":{"Transform":{"position":{"x":0,"y":0,"z":1523.063},"$type":"TransformData"},"TutorialEvent":{"displayText":false,"tutorialText":"None","displayMesh":true,"direction":-90,"time":0.5,"endTutorial":false,"allowHoverboard":false,"$type":"TutorialEvent"}},"children":[]},{"name":"Trigger_right","components":{"Transform":{"position":{"x":0,"y":0,"z":1643.063},"$type":"TransformData"},"TutorialEvent":{"displayText":false,"tutorialText":"None","displayMesh":true,"direction":-90,"time":0.5,"endTutorial":false,"allowHoverboard":false,"$type":"TutorialEvent"}},"children":[]},{"name":"Trigger_left","components":{"Transform":{"position":{"x":0,"y":0,"z":1823.063},"$type":"TransformData"},"TutorialEvent":{"displayText":false,"tutorialText":"None","displayMesh":true,"direction":90,"time":0.6,"endTutorial":false,"allowHoverboard":false,"$type":"TutorialEvent"}},"children":[]},{"name":"Trigger_hoverboard","components":{"Transform":{"position":{"x":0,"y":0,"z":2195},"$type":"TransformData"},"TutorialEvent":{"displayText":true,"tutorialText":"DoubleTap","displayMesh":false,"direction":0,"time":1,"endTutorial":false,"allowHoverboard":true,"$type":"TutorialEvent"}},"children":[]},{"name":"Trigger_finished","components":{"Transform":{"position":{"x":0,"y":0,"z":2574.015},"$type":"TransformData"},"TutorialEvent":{"displayText":true,"tutorialText":"YouRock","displayMesh":false,"direction":0,"time":1,"endTutorial":true,"allowHoverboard":false,"$type":"TutorialEvent"}},"children":[]}]},{"name":"obstacles_trains_start","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"collider stumble","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"collider stumble","components":{"Transform":{"position":{"x":-20,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":120},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":180},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":300},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":360},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":480},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":540},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":660},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":720},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":840},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":900},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1020},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":20,"y":0,"z":1080},"$type":"TransformData"}},"children":[]},{"name":"trains_3_gen_group_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":1200},"$type":"TransformData"}},"children":[]}]},{"name":"base_environments","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"2_tracks","components":{"Transform":{"position":{"x":0,"y":0,"z":360},"$type":"TransformData"},"EnvironmentBase":{"_type":"Tracks","_numTracks":2,"_blockCount":2,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]},{"name":"2_tracks","components":{"Transform":{"position":{"x":0,"y":0,"z":900},"$type":"TransformData"},"EnvironmentBase":{"_type":"Tracks","_numTracks":2,"_blockCount":2,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]}]},{"name":"environments","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"gates","components":{"Transform":{"position":{"x":0,"y":0,"z":2520},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Gates,All","_density":""},"_blockCount":4,"$type":"SYBO.Subway.Level.Environment"}},"children":[]}]},{"name":"checkpoints","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"checkpoint_1","components":{"Transform":{"position":{"x":0,"y":0,"z":41},"$type":"TransformData"},"CharacterCollisionTrigger":{"$type":"SYBO.Subway.Level.CharacterCollisionTrigger"},"CheckpointTrigger":{"$type":"SYBO.Subway.Level.CheckpointTrigger"}},"children":[]},{"name":"checkpoint_2","components":{"Transform":{"position":{"x":0,"y":0,"z":380},"$type":"TransformData"},"CharacterCollisionTrigger":{"$type":"SYBO.Subway.Level.CharacterCollisionTrigger"},"CheckpointTrigger":{"$type":"SYBO.Subway.Level.CheckpointTrigger"}},"children":[]},{"name":"checkpoint_3","components":{"Transform":{"position":{"x":0,"y":0,"z":560},"$type":"TransformData"},"CharacterCollisionTrigger":{"$type":"SYBO.Subway.Level.CharacterCollisionTrigger"},"CheckpointTrigger":{"$type":"SYBO.Subway.Level.CheckpointTrigger"}},"children":[]},{"name":"checkpoint_4","components":{"Transform":{"position":{"x":0,"y":0,"z":918},"$type":"TransformData"},"CharacterCollisionTrigger":{"$type":"SYBO.Subway.Level.CharacterCollisionTrigger"},"CheckpointTrigger":{"$type":"SYBO.Subway.Level.CheckpointTrigger"}},"children":[]},{"name":"checkpoint_5","components":{"Transform":{"position":{"x":0,"y":0,"z":1104},"$type":"TransformData"},"CharacterCollisionTrigger":{"$type":"SYBO.Subway.Level.CharacterCollisionTrigger"},"CheckpointTrigger":{"$type":"SYBO.Subway.Level.CheckpointTrigger"}},"children":[]},{"name":"checkpoint_6","components":{"Transform":{"position":{"x":0,"y":0,"z":1576},"$type":"TransformData"},"CharacterCollisionTrigger":{"$type":"SYBO.Subway.Level.CharacterCollisionTrigger"},"CheckpointTrigger":{"$type":"SYBO.Subway.Level.CheckpointTrigger"}},"children":[]},{"name":"checkpoint_7","components":{"Transform":{"position":{"x":0,"y":0,"z":2182},"$type":"TransformData"},"CharacterCollisionTrigger":{"$type":"SYBO.Subway.Level.CharacterCollisionTrigger"},"CheckpointTrigger":{"$type":"SYBO.Subway.Level.CheckpointTrigger"}},"children":[]}]},{"name":"environment_constraints","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"},"Environment":{"_environmentKind":{"_type":"Empty,All","_density":""},"_blockCount":2,"$type":"SYBO.Subway.Level.Environment"},"EnvironmentBase":{"_type":"Empty","_numTracks":3,"_blockCount":2,"$type":"SYBO.Subway.Level.EnvironmentBase"}},"children":[]}]}}
\ No newline at end of file
diff --git a/subway-surfers-ny/assets/data/chunks_idle.json b/subway-surfers-ny/assets/data/chunks_idle.json
new file mode 100644
index 00000000..60d697fa
--- /dev/null
+++ b/subway-surfers-ny/assets/data/chunks_idle.json
@@ -0,0 +1 @@
+{"intro":{"name":"intro","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"high_tracks3_high_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":-180},"$type":"TransformData"}},"children":[]},{"name":"bag_place","components":{"Transform":{"position":{"x":0.141,"y":0.604,"z":-18.326},"$type":"TransformData"}},"children":[]},{"name":"Ground","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"trains","components":{"Transform":{"position":{"x":-20,"y":0,"z":0},"$type":"TransformData"}},"children":[{"name":"train_sub_1_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":-30},"$type":"TransformData"}},"children":[]},{"name":"train_start_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":-30},"$type":"TransformData"}},"children":[]},{"name":"train_sub_1_place","components":{"Transform":{"position":{"x":-20,"y":0,"z":30},"$type":"TransformData"}},"children":[]}]},{"name":"high_tracks3_high_group_place","components":{"Transform":{"position":{"x":0,"y":0,"z":0},"$type":"TransformData"}},"children":[]},{"name":"lightSignal_group_place","components":{"Transform":{"position":{"x":10,"y":0,"z":0},"$type":"TransformData"}},"children":[]}]}}
\ No newline at end of file
diff --git a/subway-surfers-ny/assets/data/config.json b/subway-surfers-ny/assets/data/config.json
new file mode 100644
index 00000000..5beca2d0
--- /dev/null
+++ b/subway-surfers-ny/assets/data/config.json
@@ -0,0 +1,21 @@
+{
+ "lang": "en",
+ "bundlepath": " ",
+ "env": "1103_seoul",
+ "env_builtin": "1103_seoul",
+ "char": "jake",
+ "loading_en": "loading",
+ "loading_pt-br": "carregando",
+ "revivals": 3,
+ "reviveTimeout": 6,
+ "pokiSdkDebug": false,
+ "commercials": false,
+ "rewardedBreaks": false,
+ "rewardedBreaksMobile": false,
+ "autoload": false,
+ "leaderboards": false,
+ "useDefaultPrompt": false,
+ "vconsole": false,
+ "monitor": false,
+ "maxNicknameChars": 15
+}
\ No newline at end of file
diff --git a/subway-surfers-ny/assets/data/strings_en.json b/subway-surfers-ny/assets/data/strings_en.json
new file mode 100644
index 00000000..388fc6e9
--- /dev/null
+++ b/subway-surfers-ny/assets/data/strings_en.json
@@ -0,0 +1,53 @@
+{
+ "STR_L_HTML5": "This game uses HTML5. If it loads but does not run, please update your web browser",
+ "menu": "Menu",
+ "toprun": "Top Run",
+ "highscores": "High Scores",
+ "collect": "Collect",
+ "characters": "Characters",
+ "boards": "Boards",
+ "awards": "Awards",
+ "boosts": "Boosts",
+ "free_stuff": "Free Stuff",
+ "store": "Store",
+ "resume": "Resume",
+ "play": "Play",
+ "pause": "Pause",
+ "gameover": "Game Over",
+ "wip": "(WIP)",
+ "free": "Free!",
+ "save_me": "Save me!",
+
+ "leaderboards": "Leaderboards",
+ "score": "Score",
+ "coins": "Coins",
+ "high_score": "High Score",
+ "new_high_score": "New High Score!",
+ "settings": "Settings",
+ "tap_to_play": "Tap to play",
+ "tap_to_play_desktop": "Press space to play",
+ "nickname_prompt": "Set your nickname",
+ "ok": "OK",
+ "cancel": "Cancel",
+
+ "sound": "Sound",
+ "on": "On",
+ "off": "Off",
+ "nickname": "Nickname",
+
+ "tutorial_good": "Fresh Moves!",
+ "tutorial_hoverboard": "Double Tap for\nHoverboard",
+ "tutorial_hoverboard_desktop": "Press Space for\nHoverboard",
+ "tutorial_finished": "You rock! Now GO!",
+ "tutorial_up": "Swipe Up",
+ "tutorial_up_desktop": "Press Arrow Key Up",
+ "tutorial_down": "Swipe Down",
+ "tutorial_down_desktop": "Press Arrow Key Down",
+ "tutorial_left": "Swipe Left",
+ "tutorial_left_desktop": "Press Arrow Key Left",
+ "tutorial_right": "Swipe Right",
+ "tutorial_right_desktop": "Press Arrow Key Right",
+
+ "privacy_policy": "More games",
+ "privacy_policy_link": "https://zazgames.com/"
+}
diff --git a/subway-surfers-ny/assets/font/lilita-one.css b/subway-surfers-ny/assets/font/lilita-one.css
new file mode 100644
index 00000000..a2bca916
--- /dev/null
+++ b/subway-surfers-ny/assets/font/lilita-one.css
@@ -0,0 +1,6 @@
+@font-face {
+ font-family: 'Lilita One';
+ src: url('lilita-one.woff2') format('woff2'), url('lilita-one.woff') format('woff');
+ font-weight: normal;
+ font-style: normal;
+}
\ No newline at end of file
diff --git a/subway-surfers-ny/assets/font/lilita-one.woff2 b/subway-surfers-ny/assets/font/lilita-one.woff2
new file mode 100644
index 00000000..22253895
Binary files /dev/null and b/subway-surfers-ny/assets/font/lilita-one.woff2 differ
diff --git a/subway-surfers-ny/assets/font/titan-one.css b/subway-surfers-ny/assets/font/titan-one.css
new file mode 100644
index 00000000..4ab96a7f
--- /dev/null
+++ b/subway-surfers-ny/assets/font/titan-one.css
@@ -0,0 +1,6 @@
+@font-face {
+ font-family: 'Titan One';
+ src: url('titan-one.woff2') format('woff2'), url('titan-one.woff') format('woff');
+ font-weight: normal;
+ font-style: normal;
+}
\ No newline at end of file
diff --git a/subway-surfers-ny/assets/font/titan-one.woff2 b/subway-surfers-ny/assets/font/titan-one.woff2
new file mode 100644
index 00000000..78ce40f6
Binary files /dev/null and b/subway-surfers-ny/assets/font/titan-one.woff2 differ
diff --git a/subway-surfers-ny/assets/game/board_new_york.fbx b/subway-surfers-ny/assets/game/board_new_york.fbx
new file mode 100644
index 00000000..6e0b3e04
Binary files /dev/null and b/subway-surfers-ny/assets/game/board_new_york.fbx differ
diff --git a/subway-surfers-ny/assets/game/board_new_york01.fbx b/subway-surfers-ny/assets/game/board_new_york01.fbx
new file mode 100644
index 00000000..ca6631db
Binary files /dev/null and b/subway-surfers-ny/assets/game/board_new_york01.fbx differ
diff --git a/subway-surfers-ny/assets/game/board_new_york_tex_mip.png b/subway-surfers-ny/assets/game/board_new_york_tex_mip.png
new file mode 100644
index 00000000..e05fe027
Binary files /dev/null and b/subway-surfers-ny/assets/game/board_new_york_tex_mip.png differ
diff --git a/subway-surfers-ny/assets/game/effects_tex_mip.png b/subway-surfers-ny/assets/game/effects_tex_mip.png
new file mode 100644
index 00000000..617bc61a
Binary files /dev/null and b/subway-surfers-ny/assets/game/effects_tex_mip.png differ
diff --git a/subway-surfers-ny/assets/game/enemies_mip.png b/subway-surfers-ny/assets/game/enemies_mip.png
new file mode 100644
index 00000000..8a766291
Binary files /dev/null and b/subway-surfers-ny/assets/game/enemies_mip.png differ
diff --git a/subway-surfers-ny/assets/game/environment.fbx b/subway-surfers-ny/assets/game/environment.fbx
new file mode 100644
index 00000000..5d2fe780
Binary files /dev/null and b/subway-surfers-ny/assets/game/environment.fbx differ
diff --git a/subway-surfers-ny/assets/game/halo_mip.png b/subway-surfers-ny/assets/game/halo_mip.png
new file mode 100644
index 00000000..1ebdc334
Binary files /dev/null and b/subway-surfers-ny/assets/game/halo_mip.png differ
diff --git a/subway-surfers-ny/assets/game/jetpackSmoke_mip.png b/subway-surfers-ny/assets/game/jetpackSmoke_mip.png
new file mode 100644
index 00000000..c6d04603
Binary files /dev/null and b/subway-surfers-ny/assets/game/jetpackSmoke_mip.png differ
diff --git a/subway-surfers-ny/assets/game/model_avatar_catch.fbx b/subway-surfers-ny/assets/game/model_avatar_catch.fbx
new file mode 100644
index 00000000..d09dde88
Binary files /dev/null and b/subway-surfers-ny/assets/game/model_avatar_catch.fbx differ
diff --git a/subway-surfers-ny/assets/game/model_avatar_movement.fbx b/subway-surfers-ny/assets/game/model_avatar_movement.fbx
new file mode 100644
index 00000000..a7f8134a
Binary files /dev/null and b/subway-surfers-ny/assets/game/model_avatar_movement.fbx differ
diff --git a/subway-surfers-ny/assets/game/model_avatar_powerup_jet_pack.fbx b/subway-surfers-ny/assets/game/model_avatar_powerup_jet_pack.fbx
new file mode 100644
index 00000000..ce4f3062
Binary files /dev/null and b/subway-surfers-ny/assets/game/model_avatar_powerup_jet_pack.fbx differ
diff --git a/subway-surfers-ny/assets/game/model_avatar_powerup_pogostick.fbx b/subway-surfers-ny/assets/game/model_avatar_powerup_pogostick.fbx
new file mode 100644
index 00000000..f3a82388
Binary files /dev/null and b/subway-surfers-ny/assets/game/model_avatar_powerup_pogostick.fbx differ
diff --git a/subway-surfers-ny/assets/game/model_avatar_start.fbx b/subway-surfers-ny/assets/game/model_avatar_start.fbx
new file mode 100644
index 00000000..20cff1fb
Binary files /dev/null and b/subway-surfers-ny/assets/game/model_avatar_start.fbx differ
diff --git a/subway-surfers-ny/assets/game/model_dog_catch.fbx b/subway-surfers-ny/assets/game/model_dog_catch.fbx
new file mode 100644
index 00000000..6f8d490d
Binary files /dev/null and b/subway-surfers-ny/assets/game/model_dog_catch.fbx differ
diff --git a/subway-surfers-ny/assets/game/model_dog_movement.fbx b/subway-surfers-ny/assets/game/model_dog_movement.fbx
new file mode 100644
index 00000000..a4581224
Binary files /dev/null and b/subway-surfers-ny/assets/game/model_dog_movement.fbx differ
diff --git a/subway-surfers-ny/assets/game/model_guard_catch.fbx b/subway-surfers-ny/assets/game/model_guard_catch.fbx
new file mode 100644
index 00000000..dbfe3142
Binary files /dev/null and b/subway-surfers-ny/assets/game/model_guard_catch.fbx differ
diff --git a/subway-surfers-ny/assets/game/model_guard_movement.fbx b/subway-surfers-ny/assets/game/model_guard_movement.fbx
new file mode 100644
index 00000000..c7f538cd
Binary files /dev/null and b/subway-surfers-ny/assets/game/model_guard_movement.fbx differ
diff --git a/subway-surfers-ny/assets/game/ocean_mip.png b/subway-surfers-ny/assets/game/ocean_mip.png
new file mode 100644
index 00000000..f6920ea6
Binary files /dev/null and b/subway-surfers-ny/assets/game/ocean_mip.png differ
diff --git a/subway-surfers-ny/assets/game/props.fbx b/subway-surfers-ny/assets/game/props.fbx
new file mode 100644
index 00000000..a4e9ac80
Binary files /dev/null and b/subway-surfers-ny/assets/game/props.fbx differ
diff --git a/subway-surfers-ny/assets/game/shadow_mip.png b/subway-surfers-ny/assets/game/shadow_mip.png
new file mode 100644
index 00000000..ee689efb
Binary files /dev/null and b/subway-surfers-ny/assets/game/shadow_mip.png differ
diff --git a/subway-surfers-ny/assets/game/spraySplash_mip.png b/subway-surfers-ny/assets/game/spraySplash_mip.png
new file mode 100644
index 00000000..fd2e66a9
Binary files /dev/null and b/subway-surfers-ny/assets/game/spraySplash_mip.png differ
diff --git a/subway-surfers-ny/assets/game/trains.fbx b/subway-surfers-ny/assets/game/trains.fbx
new file mode 100644
index 00000000..2e295965
Binary files /dev/null and b/subway-surfers-ny/assets/game/trains.fbx differ
diff --git a/subway-surfers-ny/assets/idle/environment_idle.fbx b/subway-surfers-ny/assets/idle/environment_idle.fbx
new file mode 100644
index 00000000..be83da77
Binary files /dev/null and b/subway-surfers-ny/assets/idle/environment_idle.fbx differ
diff --git a/subway-surfers-ny/assets/idle/environment_tex_mip.png b/subway-surfers-ny/assets/idle/environment_tex_mip.png
new file mode 100644
index 00000000..96d97998
Binary files /dev/null and b/subway-surfers-ny/assets/idle/environment_tex_mip.png differ
diff --git a/subway-surfers-ny/assets/idle/jake_tex_mip.png b/subway-surfers-ny/assets/idle/jake_tex_mip.png
new file mode 100644
index 00000000..38f382f4
Binary files /dev/null and b/subway-surfers-ny/assets/idle/jake_tex_mip.png differ
diff --git a/subway-surfers-ny/assets/idle/model_avatar_idle_paint.fbx b/subway-surfers-ny/assets/idle/model_avatar_idle_paint.fbx
new file mode 100644
index 00000000..974c1842
Binary files /dev/null and b/subway-surfers-ny/assets/idle/model_avatar_idle_paint.fbx differ
diff --git a/subway-surfers-ny/assets/idle/props_start.fbx b/subway-surfers-ny/assets/idle/props_start.fbx
new file mode 100644
index 00000000..80b84100
Binary files /dev/null and b/subway-surfers-ny/assets/idle/props_start.fbx differ
diff --git a/subway-surfers-ny/assets/idle/props_tex_mip.png b/subway-surfers-ny/assets/idle/props_tex_mip.png
new file mode 100644
index 00000000..0c743a69
Binary files /dev/null and b/subway-surfers-ny/assets/idle/props_tex_mip.png differ
diff --git a/subway-surfers-ny/assets/idle/train_start_mip.png b/subway-surfers-ny/assets/idle/train_start_mip.png
new file mode 100644
index 00000000..09547b14
Binary files /dev/null and b/subway-surfers-ny/assets/idle/train_start_mip.png differ
diff --git a/subway-surfers-ny/assets/idle/trains_start.fbx b/subway-surfers-ny/assets/idle/trains_start.fbx
new file mode 100644
index 00000000..87216076
Binary files /dev/null and b/subway-surfers-ny/assets/idle/trains_start.fbx differ
diff --git a/subway-surfers-ny/assets/idle/trains_tex_mip.png b/subway-surfers-ny/assets/idle/trains_tex_mip.png
new file mode 100644
index 00000000..7c3f9208
Binary files /dev/null and b/subway-surfers-ny/assets/idle/trains_tex_mip.png differ
diff --git a/subway-surfers-ny/assets/placeholder/icon_00_brody.png b/subway-surfers-ny/assets/placeholder/icon_00_brody.png
new file mode 100644
index 00000000..950f7283
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/icon_00_brody.png differ
diff --git a/subway-surfers-ny/assets/placeholder/icon_01_tagbot.png b/subway-surfers-ny/assets/placeholder/icon_01_tagbot.png
new file mode 100644
index 00000000..2fd4c253
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/icon_01_tagbot.png differ
diff --git a/subway-surfers-ny/assets/placeholder/icon_02_tasha.png b/subway-surfers-ny/assets/placeholder/icon_02_tasha.png
new file mode 100644
index 00000000..d8191fe5
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/icon_02_tasha.png differ
diff --git a/subway-surfers-ny/assets/placeholder/icon_03_ninja.png b/subway-surfers-ny/assets/placeholder/icon_03_ninja.png
new file mode 100644
index 00000000..60fa536f
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/icon_03_ninja.png differ
diff --git a/subway-surfers-ny/assets/placeholder/icon_04_lucy.png b/subway-surfers-ny/assets/placeholder/icon_04_lucy.png
new file mode 100644
index 00000000..c918f7c9
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/icon_04_lucy.png differ
diff --git a/subway-surfers-ny/assets/placeholder/icon_05_king.png b/subway-surfers-ny/assets/placeholder/icon_05_king.png
new file mode 100644
index 00000000..8b2f135a
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/icon_05_king.png differ
diff --git a/subway-surfers-ny/assets/placeholder/icon_07_yutani.png b/subway-surfers-ny/assets/placeholder/icon_07_yutani.png
new file mode 100644
index 00000000..ceaa4b46
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/icon_07_yutani.png differ
diff --git a/subway-surfers-ny/assets/placeholder/icon_08_spike.png b/subway-surfers-ny/assets/placeholder/icon_08_spike.png
new file mode 100644
index 00000000..5191a287
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/icon_08_spike.png differ
diff --git a/subway-surfers-ny/assets/placeholder/icon_09_fresh.png b/subway-surfers-ny/assets/placeholder/icon_09_fresh.png
new file mode 100644
index 00000000..5c5f616d
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/icon_09_fresh.png differ
diff --git a/subway-surfers-ny/assets/placeholder/icon_11_tricky.png b/subway-surfers-ny/assets/placeholder/icon_11_tricky.png
new file mode 100644
index 00000000..4ff05146
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/icon_11_tricky.png differ
diff --git a/subway-surfers-ny/assets/placeholder/icon_friend.png b/subway-surfers-ny/assets/placeholder/icon_friend.png
new file mode 100644
index 00000000..87929c87
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/icon_friend.png differ
diff --git a/subway-surfers-ny/assets/placeholder/jake.png b/subway-surfers-ny/assets/placeholder/jake.png
new file mode 100644
index 00000000..5d963eb0
Binary files /dev/null and b/subway-surfers-ny/assets/placeholder/jake.png differ
diff --git a/subway-surfers-ny/assets/preload/splash_mip.png b/subway-surfers-ny/assets/preload/splash_mip.png
new file mode 100644
index 00000000..00ed83ff
Binary files /dev/null and b/subway-surfers-ny/assets/preload/splash_mip.png differ
diff --git a/subway-surfers-ny/assets/ui/ui.json b/subway-surfers-ny/assets/ui/ui.json
new file mode 100644
index 00000000..263a2688
--- /dev/null
+++ b/subway-surfers-ny/assets/ui/ui.json
@@ -0,0 +1,1191 @@
+{
+ "frames": {
+ "base_blurry.png": {
+ "frame": {
+ "x": 2,
+ "y": 2,
+ "w": 512,
+ "h": 90
+ },
+ "rotated": false,
+ "trimmed": false,
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 0,
+ "w": 512,
+ "h": 90
+ },
+ "sourceSize": {
+ "w": 512,
+ "h": 90
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "scoreboard.png": {
+ "frame": {
+ "x": 2,
+ "y": 96,
+ "w": 319,
+ "h": 180
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 319,
+ "h": 180
+ },
+ "sourceSize": {
+ "w": 320,
+ "h": 185
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "base_long.png": {
+ "frame": {
+ "x": 2,
+ "y": 280,
+ "w": 300,
+ "h": 80
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 1,
+ "w": 300,
+ "h": 80
+ },
+ "sourceSize": {
+ "w": 302,
+ "h": 82
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "tutorial_arrow.png": {
+ "frame": {
+ "x": 2,
+ "y": 364,
+ "w": 256,
+ "h": 264
+ },
+ "rotated": false,
+ "trimmed": false,
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 0,
+ "w": 256,
+ "h": 264
+ },
+ "sourceSize": {
+ "w": 256,
+ "h": 264
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "front_icon_top_run.png": {
+ "frame": {
+ "x": 262,
+ "y": 364,
+ "w": 260,
+ "h": 171
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 2,
+ "w": 260,
+ "h": 171
+ },
+ "sourceSize": {
+ "w": 260,
+ "h": 174
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "front_icon_mytour.png": {
+ "frame": {
+ "x": 518,
+ "y": 2,
+ "w": 227,
+ "h": 125
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 1,
+ "w": 227,
+ "h": 125
+ },
+ "sourceSize": {
+ "w": 228,
+ "h": 126
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "front_icon_shop.png": {
+ "frame": {
+ "x": 325,
+ "y": 131,
+ "w": 190,
+ "h": 151
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 1,
+ "w": 190,
+ "h": 151
+ },
+ "sourceSize": {
+ "w": 194,
+ "h": 154
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "front_icon_me.png": {
+ "frame": {
+ "x": 519,
+ "y": 131,
+ "w": 133,
+ "h": 168
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 133,
+ "h": 168
+ },
+ "sourceSize": {
+ "w": 136,
+ "h": 172
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "clock_base.png": {
+ "frame": {
+ "x": 656,
+ "y": 131,
+ "w": 111,
+ "h": 108
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 0,
+ "w": 111,
+ "h": 108
+ },
+ "sourceSize": {
+ "w": 112,
+ "h": 109
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_tv.png": {
+ "frame": {
+ "x": 656,
+ "y": 243,
+ "w": 83,
+ "h": 102
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 1,
+ "w": 83,
+ "h": 102
+ },
+ "sourceSize": {
+ "w": 86,
+ "h": 106
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "btn_base.png": {
+ "frame": {
+ "x": 526,
+ "y": 303,
+ "w": 100,
+ "h": 100
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 1,
+ "w": 100,
+ "h": 100
+ },
+ "sourceSize": {
+ "w": 102,
+ "h": 102
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "base_short.png": {
+ "frame": {
+ "x": 630,
+ "y": 349,
+ "w": 100,
+ "h": 80
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 1,
+ "w": 100,
+ "h": 80
+ },
+ "sourceSize": {
+ "w": 102,
+ "h": 82
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "box_fill_green.png": {
+ "frame": {
+ "x": 526,
+ "y": 407,
+ "w": 55,
+ "h": 85
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 55,
+ "h": 85
+ },
+ "sourceSize": {
+ "w": 55,
+ "h": 86
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "btn_close.png": {
+ "frame": {
+ "x": 526,
+ "y": 496,
+ "w": 78,
+ "h": 82
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 3,
+ "y": 2,
+ "w": 78,
+ "h": 82
+ },
+ "sourceSize": {
+ "w": 83,
+ "h": 86
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "clock_fill.png": {
+ "frame": {
+ "x": 262,
+ "y": 539,
+ "w": 82,
+ "h": 82
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 0,
+ "w": 82,
+ "h": 82
+ },
+ "sourceSize": {
+ "w": 82,
+ "h": 84
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_piggy.png": {
+ "frame": {
+ "x": 348,
+ "y": 539,
+ "w": 81,
+ "h": 62
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 2,
+ "w": 81,
+ "h": 62
+ },
+ "sourceSize": {
+ "w": 84,
+ "h": 64
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "box_border_grey.png": {
+ "frame": {
+ "x": 433,
+ "y": 539,
+ "w": 76,
+ "h": 77
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 1,
+ "w": 76,
+ "h": 77
+ },
+ "sourceSize": {
+ "w": 78,
+ "h": 78
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_high_scores.png": {
+ "frame": {
+ "x": 585,
+ "y": 433,
+ "w": 77,
+ "h": 59
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 4,
+ "w": 77,
+ "h": 59
+ },
+ "sourceSize": {
+ "w": 80,
+ "h": 64
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "diagonal.png": {
+ "frame": {
+ "x": 306,
+ "y": 286,
+ "w": 74,
+ "h": 74
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 74,
+ "h": 74
+ },
+ "sourceSize": {
+ "w": 77,
+ "h": 78
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_daily_challenge.png": {
+ "frame": {
+ "x": 384,
+ "y": 286,
+ "w": 73,
+ "h": 60
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 1,
+ "w": 73,
+ "h": 60
+ },
+ "sourceSize": {
+ "w": 76,
+ "h": 62
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "box_fill_orange.png": {
+ "frame": {
+ "x": 461,
+ "y": 286,
+ "w": 41,
+ "h": 69
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 1,
+ "w": 41,
+ "h": 69
+ },
+ "sourceSize": {
+ "w": 43,
+ "h": 71
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_top_run.png": {
+ "frame": {
+ "x": 666,
+ "y": 433,
+ "w": 48,
+ "h": 69
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 3,
+ "w": 48,
+ "h": 69
+ },
+ "sourceSize": {
+ "w": 50,
+ "h": 72
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_back.png": {
+ "frame": {
+ "x": 608,
+ "y": 506,
+ "w": 69,
+ "h": 60
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 4,
+ "y": 4,
+ "w": 69,
+ "h": 60
+ },
+ "sourceSize": {
+ "w": 76,
+ "h": 68
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_awards.png": {
+ "frame": {
+ "x": 681,
+ "y": 506,
+ "w": 65,
+ "h": 69
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 3,
+ "w": 65,
+ "h": 69
+ },
+ "sourceSize": {
+ "w": 68,
+ "h": 72
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "box_border_grey_small.png": {
+ "frame": {
+ "x": 348,
+ "y": 605,
+ "w": 68,
+ "h": 68
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 2,
+ "w": 68,
+ "h": 68
+ },
+ "sourceSize": {
+ "w": 71,
+ "h": 71
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_upgrades.png": {
+ "frame": {
+ "x": 262,
+ "y": 625,
+ "w": 68,
+ "h": 62
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 2,
+ "w": 68,
+ "h": 62
+ },
+ "sourceSize": {
+ "w": 72,
+ "h": 66
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "base_item.png": {
+ "frame": {
+ "x": 608,
+ "y": 570,
+ "w": 68,
+ "h": 68
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 1,
+ "w": 68,
+ "h": 68
+ },
+ "sourceSize": {
+ "w": 70,
+ "h": 70
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_coins.png": {
+ "frame": {
+ "x": 513,
+ "y": 582,
+ "w": 68,
+ "h": 66
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 1,
+ "w": 68,
+ "h": 66
+ },
+ "sourceSize": {
+ "w": 72,
+ "h": 68
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_boards.png": {
+ "frame": {
+ "x": 420,
+ "y": 620,
+ "w": 67,
+ "h": 63
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 2,
+ "w": 67,
+ "h": 63
+ },
+ "sourceSize": {
+ "w": 70,
+ "h": 66
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_item_jetpack.png": {
+ "frame": {
+ "x": 680,
+ "y": 579,
+ "w": 61,
+ "h": 66
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 61,
+ "h": 66
+ },
+ "sourceSize": {
+ "w": 62,
+ "h": 66
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_item_multiplier.png": {
+ "frame": {
+ "x": 2,
+ "y": 632,
+ "w": 65,
+ "h": 66
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 65,
+ "h": 66
+ },
+ "sourceSize": {
+ "w": 66,
+ "h": 66
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_weekly_hunt.png": {
+ "frame": {
+ "x": 71,
+ "y": 632,
+ "w": 62,
+ "h": 65
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 1,
+ "w": 62,
+ "h": 65
+ },
+ "sourceSize": {
+ "w": 66,
+ "h": 66
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_user.png": {
+ "frame": {
+ "x": 718,
+ "y": 433,
+ "w": 50,
+ "h": 64
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 50,
+ "h": 64
+ },
+ "sourceSize": {
+ "w": 51,
+ "h": 66
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_characters.png": {
+ "frame": {
+ "x": 137,
+ "y": 632,
+ "w": 47,
+ "h": 64
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 3,
+ "w": 47,
+ "h": 64
+ },
+ "sourceSize": {
+ "w": 50,
+ "h": 68
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_house.png": {
+ "frame": {
+ "x": 188,
+ "y": 632,
+ "w": 62,
+ "h": 63
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 5,
+ "y": 6,
+ "w": 62,
+ "h": 63
+ },
+ "sourceSize": {
+ "w": 72,
+ "h": 74
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_item_hoverboard.png": {
+ "frame": {
+ "x": 585,
+ "y": 642,
+ "w": 62,
+ "h": 37
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 3,
+ "y": 2,
+ "w": 62,
+ "h": 37
+ },
+ "sourceSize": {
+ "w": 69,
+ "h": 40
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_collect_coins.png": {
+ "frame": {
+ "x": 334,
+ "y": 677,
+ "w": 52,
+ "h": 62
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 3,
+ "y": 3,
+ "w": 52,
+ "h": 62
+ },
+ "sourceSize": {
+ "w": 56,
+ "h": 66
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_white_missions.png": {
+ "frame": {
+ "x": 254,
+ "y": 691,
+ "w": 62,
+ "h": 58
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 1,
+ "w": 62,
+ "h": 58
+ },
+ "sourceSize": {
+ "w": 66,
+ "h": 59
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_info.png": {
+ "frame": {
+ "x": 734,
+ "y": 349,
+ "w": 29,
+ "h": 60
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 5,
+ "w": 29,
+ "h": 60
+ },
+ "sourceSize": {
+ "w": 37,
+ "h": 71
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_settings.png": {
+ "frame": {
+ "x": 188,
+ "y": 699,
+ "w": 57,
+ "h": 58
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 1,
+ "w": 57,
+ "h": 58
+ },
+ "sourceSize": {
+ "w": 59,
+ "h": 60
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_coin_large.png": {
+ "frame": {
+ "x": 71,
+ "y": 701,
+ "w": 58,
+ "h": 58
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 3,
+ "y": 4,
+ "w": 58,
+ "h": 58
+ },
+ "sourceSize": {
+ "w": 64,
+ "h": 64
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_item_sneakers.png": {
+ "frame": {
+ "x": 2,
+ "y": 702,
+ "w": 57,
+ "h": 58
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 0,
+ "w": 57,
+ "h": 58
+ },
+ "sourceSize": {
+ "w": 58,
+ "h": 58
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_item_magnet.png": {
+ "frame": {
+ "x": 137,
+ "y": 700,
+ "w": 47,
+ "h": 57
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 2,
+ "y": 1,
+ "w": 47,
+ "h": 57
+ },
+ "sourceSize": {
+ "w": 49,
+ "h": 58
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_sound.png": {
+ "frame": {
+ "x": 491,
+ "y": 652,
+ "w": 57,
+ "h": 45
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 1,
+ "y": 1,
+ "w": 57,
+ "h": 45
+ },
+ "sourceSize": {
+ "w": 59,
+ "h": 48
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_key.png": {
+ "frame": {
+ "x": 390,
+ "y": 687,
+ "w": 36,
+ "h": 52
+ },
+ "rotated": false,
+ "trimmed": false,
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 0,
+ "w": 36,
+ "h": 52
+ },
+ "sourceSize": {
+ "w": 36,
+ "h": 52
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_coin.png": {
+ "frame": {
+ "x": 430,
+ "y": 687,
+ "w": 44,
+ "h": 43
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 4,
+ "y": 4,
+ "w": 44,
+ "h": 43
+ },
+ "sourceSize": {
+ "w": 52,
+ "h": 50
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_pause.png": {
+ "frame": {
+ "x": 743,
+ "y": 243,
+ "w": 32,
+ "h": 38
+ },
+ "rotated": false,
+ "trimmed": false,
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 0,
+ "w": 32,
+ "h": 38
+ },
+ "sourceSize": {
+ "w": 32,
+ "h": 38
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "item_duration_bar.png": {
+ "frame": {
+ "x": 630,
+ "y": 303,
+ "w": 11,
+ "h": 34
+ },
+ "rotated": false,
+ "trimmed": false,
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 0,
+ "w": 11,
+ "h": 34
+ },
+ "sourceSize": {
+ "w": 11,
+ "h": 34
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ },
+ "icon_star.png": {
+ "frame": {
+ "x": 743,
+ "y": 285,
+ "w": 29,
+ "h": 29
+ },
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {
+ "x": 5,
+ "y": 4,
+ "w": 29,
+ "h": 29
+ },
+ "sourceSize": {
+ "w": 40,
+ "h": 38
+ },
+ "pivot": {
+ "x": 0.5,
+ "y": 0.5
+ }
+ }
+ },
+ "meta": {
+ "app": "http://github.com/odrick/free-tex-packer-core",
+ "version": "0.2.0",
+ "image": "ui.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 777,
+ "h": 762
+ },
+ "scale": 1
+ }
+}
diff --git a/subway-surfers-ny/assets/ui/ui.png b/subway-surfers-ny/assets/ui/ui.png
new file mode 100644
index 00000000..ac680ac4
Binary files /dev/null and b/subway-surfers-ny/assets/ui/ui.png differ
diff --git a/subway-surfers-ny/index.html b/subway-surfers-ny/index.html
new file mode 100644
index 00000000..35866c40
--- /dev/null
+++ b/subway-surfers-ny/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Subway Surfers New York | 3kh0
+
+
+
+
+
+
+
+
+
diff --git a/subway-surfers-ny/js/boot.js b/subway-surfers-ny/js/boot.js
new file mode 100644
index 00000000..e24689b5
--- /dev/null
+++ b/subway-surfers-ny/js/boot.js
@@ -0,0 +1,122 @@
+! function(t) {
+ var a = {};
+
+ function __webpack_require__(e) {
+ if (a[e]) return a[e].exports;
+ var n = a[e] = {
+ i: e,
+ l: !1,
+ exports: {}
+ };
+ return t[e].call(n.exports, n, n.exports, __webpack_require__), n.l = !0, n.exports
+ }
+ __webpack_require__.m = t, __webpack_require__.c = a, __webpack_require__.d = function(e, n, t) {
+ __webpack_require__.o(e, n) || Object.defineProperty(e, n, {
+ enumerable: !0,
+ get: t
+ })
+ }, __webpack_require__.r = function(e) {
+ "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
+ value: "Module"
+ }), Object.defineProperty(e, "__esModule", {
+ value: !0
+ })
+ }, __webpack_require__.t = function(n, e) {
+ if (1 & e && (n = __webpack_require__(n)), 8 & e) return n;
+ if (4 & e && "object" == typeof n && n && n.__esModule) return n;
+ var t = Object.create(null);
+ if (__webpack_require__.r(t), Object.defineProperty(t, "default", {
+ enumerable: !0,
+ value: n
+ }), 2 & e && "string" != typeof n)
+ for (var a in n) __webpack_require__.d(t, a, function(e) {
+ return n[e]
+ }.bind(null, a));
+ return t
+ }, __webpack_require__.n = function(e) {
+ var n = e && e.__esModule ? function() {
+ return e.default
+ } : function() {
+ return e
+ };
+ return __webpack_require__.d(n, "a", n), n
+ }, __webpack_require__.o = function(e, n) {
+ return Object.prototype.hasOwnProperty.call(e, n)
+ }, __webpack_require__.p = "", __webpack_require__(__webpack_require__.s = 486)
+}({
+ 486: function(e, n, t) {
+ function pathJoin() {
+ for (var e = arguments.length, n = new Array(e), t = 0; t < e; t++) n[t] = arguments[t];
+ return n.join("/")
+ }
+
+ function loadJson(e, n, t) {
+ var a = new XMLHttpRequest;
+ a.addEventListener("load", function() {
+ var e = JSON.parse(this.responseText);
+ n && n(e)
+ }), a.open("GET", e + "?v=1gefx1jwdk0gj12hb"), a.send()
+ }
+
+ function loadScript(e, n) {
+ try {
+ var t = document.createElement("script");
+ n && (t.onload = n), t.src = e + "?v=1gefx1jwdk0gj12hb", document.head.appendChild(t)
+ } catch (e) {}
+ }
+
+ function loadFont(e, n) {
+ var t = document.createElement("link");
+ t.rel = "stylesheet", t.type = "text/css", t.href = e + "?v=1gefx1jwdk0gj12hb", t.media = "all", document.head.appendChild(t);
+ var a = document.createElement("div");
+ a.className = "fontcache", a.style = 'font-family: "' + n + '";', a.textContent = ".", document.body.appendChild(a)
+ }
+
+ function initApp(e) {
+ var n, t, a;
+ n = e.meta, t = pathJoin(n.path, n.splash), (a = document.querySelector("#og-game-holder")).style.backgroundColor = n.color, a.style.backgroundImage = 'url("' + t + '?v=1gefx1jwdk0gj12hb"")', loadFont("assets/font/lilita-one.css", "Lilita One"), loadFont("assets/font/titan-one.css", "Titan One"), window.sharedAppData.config.leaderboards && loadScript("js/leaderboard.js"), window.sharedAppData.config.vconsole && loadScript("https://cdnjs.cloudflare.com/ajax/libs/vConsole/3.3.0/vconsole.min.js"), loadScript("js/inflate.min.js"), loadScript("js/vendor.js"), loadScript("js/main.js")
+ }
+ console.log = function() {
+ return null
+ }, console.warn = function() {
+ return null
+ }, window.GAME_CONFIG || (window.GAME_CONFIG = {
+ fastplay: !1
+ }), loadJson("assets/data/config.json", function(t) {
+ var e, n, a, o = function() {
+ var e = location.search.slice(location.search.indexOf("?") + 1).split("&"),
+ n = {};
+ for (var t in e) {
+ var a = e[t].split("="),
+ o = a[0],
+ r = a[1];
+ void 0 !== r && ("true" !== r && "false" !== r || (r = "true" === r), n[o] = "string" == typeof r && r.match(/^[-.0-9]+$/) ? parseFloat(r) : r)
+ }
+ return n
+ }();
+ for (var r in t.pokiSdkDebug = !1, window.GAME_CONFIG) t[r] = window.GAME_CONFIG[r];
+ for (var r in o) t[r] = o[r];
+ window.sharedAppData = {
+ config: t,
+ bundle: {
+ meta: {
+ path: "./",
+ color: "#ffa4cd",
+ splash: "/assets/preload/splash_mip.png"
+ }
+ }
+ }, e = t.pokiSdkDebug, n = function(e) {
+ if (void 0 === t.adBlocking && (t.adBlocking = e), t.bundlepath && t.env !== t.env_builtin) {
+ var n = pathJoin(t.bundlepath, t.env);
+ loadJson(pathJoin(n, "manifest.json"), function(e) {
+ e.meta.path = n, window.sharedAppData.bundle = e, initApp(window.sharedAppData.bundle)
+ })
+ } else initApp(window.sharedAppData.bundle)
+ }, (a = window.Tabouzigtsdk) ? (a.init().then(function() {
+ a.gameLoadingStart(), n(!1)
+ }).catch(function() {
+ a.gameLoadingStart(), n(!0)
+ }), a.setDebug(e)) : n(!0)
+ })
+ }
+});
\ No newline at end of file
diff --git a/subway-surfers-ny/js/games_lib/ludiAdapter.js b/subway-surfers-ny/js/games_lib/ludiAdapter.js
new file mode 100644
index 00000000..3a8eae59
--- /dev/null
+++ b/subway-surfers-ny/js/games_lib/ludiAdapter.js
@@ -0,0 +1,57 @@
+var myDataLayer = function() {
+ var arr = [];
+
+
+ return arr;
+};
+
+var dataLayer = new myDataLayer;
+var enableADS = parent.enableADS;
+var productKey = parent.productKey;
+var productTitle = parent.productTitle;
+if (parent.AdsState) {
+ var AdsState = parent.AdsState;
+}
+if (parent.adsContainer) {
+ var adsContainer = parent.adsContainer;
+}
+
+if (parent.adsCurrentState) {
+ var adsCurrentState = parent.adsCurrentState;
+}
+
+var playAds = function() {
+ //parent.playAds();
+ sdk.showBanner();
+}
+var getReferrer = function() {
+ return parent.getReferrer();
+}
+
+var show_freeFrame = function() {
+ //return parent.playAds();
+ sdk.showBanner();
+}
+var show_freeFrame_Loc = function(l) {
+ //return parent.playAds();
+ sdk.showBanner();
+}
+var o_setDisplayRewardAds = function(v) {
+ //return parent.o_setDisplayRewardAds(v);
+ sdk.showBanner();
+}
+var ora_isDisplayingReward = function(v) {
+ //return parent.ora_isDisplayingReward(v);
+ sdk.showBanner();
+}
+var ora_getPayloadAmount = function() {
+ return parent.ora_getPayloadAmount();
+}
+var isAdsComplete = function() {
+ return parent.isAdsComplete();
+}
+var myConsoleLog = function() {
+ return parent.myConsoleLog();
+}
+
+var isShowAdScreen = false;
\ No newline at end of file
diff --git a/subway-surfers-ny/js/inflate.min.js b/subway-surfers-ny/js/inflate.min.js
new file mode 100644
index 00000000..33067ae9
--- /dev/null
+++ b/subway-surfers-ny/js/inflate.min.js
@@ -0,0 +1,358 @@
+/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */
+(function() {
+ 'use strict';
+ var l = void 0,
+ aa = this;
+
+ function r(c, d) {
+ var a = c.split("."),
+ b = aa;
+ !(a[0] in b) && b.execScript && b.execScript("var " + a[0]);
+ for (var e; a.length && (e = a.shift());) !a.length && d !== l ? b[e] = d : b = b[e] ? b[e] : b[e] = {}
+ };
+ var t = "undefined" !== typeof Uint8Array && "undefined" !== typeof Uint16Array && "undefined" !== typeof Uint32Array && "undefined" !== typeof DataView;
+
+ function v(c) {
+ var d = c.length,
+ a = 0,
+ b = Number.POSITIVE_INFINITY,
+ e, f, g, h, k, m, n, p, s, x;
+ for (p = 0; p < d; ++p) c[p] > a && (a = c[p]), c[p] < b && (b = c[p]);
+ e = 1 << a;
+ f = new(t ? Uint32Array : Array)(e);
+ g = 1;
+ h = 0;
+ for (k = 2; g <= a;) {
+ for (p = 0; p < d; ++p)
+ if (c[p] === g) {
+ m = 0;
+ n = h;
+ for (s = 0; s < g; ++s) m = m << 1 | n & 1, n >>= 1;
+ x = g << 16 | p;
+ for (s = m; s < e; s += k) f[s] = x;
+ ++h
+ }++g;
+ h <<= 1;
+ k <<= 1
+ }
+ return [f, a, b]
+ };
+
+ function w(c, d) {
+ this.g = [];
+ this.h = 32768;
+ this.d = this.f = this.a = this.l = 0;
+ this.input = t ? new Uint8Array(c) : c;
+ this.m = !1;
+ this.i = y;
+ this.r = !1;
+ if (d || !(d = {})) d.index && (this.a = d.index), d.bufferSize && (this.h = d.bufferSize), d.bufferType && (this.i = d.bufferType), d.resize && (this.r = d.resize);
+ switch (this.i) {
+ case A:
+ this.b = 32768;
+ this.c = new(t ? Uint8Array : Array)(32768 + this.h + 258);
+ break;
+ case y:
+ this.b = 0;
+ this.c = new(t ? Uint8Array : Array)(this.h);
+ this.e = this.z;
+ this.n = this.v;
+ this.j = this.w;
+ break;
+ default:
+ throw Error("invalid inflate mode");
+ }
+ }
+ var A = 0,
+ y = 1,
+ B = {
+ t: A,
+ s: y
+ };
+ w.prototype.k = function() {
+ for (; !this.m;) {
+ var c = C(this, 3);
+ c & 1 && (this.m = !0);
+ c >>>= 1;
+ switch (c) {
+ case 0:
+ var d = this.input,
+ a = this.a,
+ b = this.c,
+ e = this.b,
+ f = d.length,
+ g = l,
+ h = l,
+ k = b.length,
+ m = l;
+ this.d = this.f = 0;
+ if (a + 1 >= f) throw Error("invalid uncompressed block header: LEN");
+ g = d[a++] | d[a++] << 8;
+ if (a + 1 >= f) throw Error("invalid uncompressed block header: NLEN");
+ h = d[a++] | d[a++] << 8;
+ if (g === ~h) throw Error("invalid uncompressed block header: length verify");
+ if (a + g > d.length) throw Error("input buffer is broken");
+ switch (this.i) {
+ case A:
+ for (; e +
+ g > b.length;) {
+ m = k - e;
+ g -= m;
+ if (t) b.set(d.subarray(a, a + m), e), e += m, a += m;
+ else
+ for (; m--;) b[e++] = d[a++];
+ this.b = e;
+ b = this.e();
+ e = this.b
+ }
+ break;
+ case y:
+ for (; e + g > b.length;) b = this.e({
+ p: 2
+ });
+ break;
+ default:
+ throw Error("invalid inflate mode");
+ }
+ if (t) b.set(d.subarray(a, a + g), e), e += g, a += g;
+ else
+ for (; g--;) b[e++] = d[a++];
+ this.a = a;
+ this.b = e;
+ this.c = b;
+ break;
+ case 1:
+ this.j(ba, ca);
+ break;
+ case 2:
+ for (var n = C(this, 5) + 257, p = C(this, 5) + 1, s = C(this, 4) + 4, x = new(t ? Uint8Array : Array)(D.length), S = l, T = l, U = l, u = l, M = l, F = l, z = l, q = l, V = l, q = 0; q < s; ++q) x[D[q]] =
+ C(this, 3);
+ if (!t) {
+ q = s;
+ for (s = x.length; q < s; ++q) x[D[q]] = 0
+ }
+ S = v(x);
+ u = new(t ? Uint8Array : Array)(n + p);
+ q = 0;
+ for (V = n + p; q < V;) switch (M = E(this, S), M) {
+ case 16:
+ for (z = 3 + C(this, 2); z--;) u[q++] = F;
+ break;
+ case 17:
+ for (z = 3 + C(this, 3); z--;) u[q++] = 0;
+ F = 0;
+ break;
+ case 18:
+ for (z = 11 + C(this, 7); z--;) u[q++] = 0;
+ F = 0;
+ break;
+ default:
+ F = u[q++] = M
+ }
+ T = t ? v(u.subarray(0, n)) : v(u.slice(0, n));
+ U = t ? v(u.subarray(n)) : v(u.slice(n));
+ this.j(T, U);
+ break;
+ default:
+ throw Error("unknown BTYPE: " + c);
+ }
+ }
+ return this.n()
+ };
+ var G = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],
+ D = t ? new Uint16Array(G) : G,
+ H = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 258, 258],
+ I = t ? new Uint16Array(H) : H,
+ J = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0],
+ K = t ? new Uint8Array(J) : J,
+ L = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577],
+ da = t ? new Uint16Array(L) : L,
+ ea = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12,
+ 13, 13
+ ],
+ N = t ? new Uint8Array(ea) : ea,
+ O = new(t ? Uint8Array : Array)(288),
+ P, fa;
+ P = 0;
+ for (fa = O.length; P < fa; ++P) O[P] = 143 >= P ? 8 : 255 >= P ? 9 : 279 >= P ? 7 : 8;
+ var ba = v(O),
+ Q = new(t ? Uint8Array : Array)(30),
+ R, ga;
+ R = 0;
+ for (ga = Q.length; R < ga; ++R) Q[R] = 5;
+ var ca = v(Q);
+
+ function C(c, d) {
+ for (var a = c.f, b = c.d, e = c.input, f = c.a, g = e.length, h; b < d;) {
+ if (f >= g) throw Error("input buffer is broken");
+ a |= e[f++] << b;
+ b += 8
+ }
+ h = a & (1 << d) - 1;
+ c.f = a >>> d;
+ c.d = b - d;
+ c.a = f;
+ return h
+ }
+
+ function E(c, d) {
+ for (var a = c.f, b = c.d, e = c.input, f = c.a, g = e.length, h = d[0], k = d[1], m, n; b < k && !(f >= g);) a |= e[f++] << b, b += 8;
+ m = h[a & (1 << k) - 1];
+ n = m >>> 16;
+ if (n > b) throw Error("invalid code length: " + n);
+ c.f = a >> n;
+ c.d = b - n;
+ c.a = f;
+ return m & 65535
+ }
+ w.prototype.j = function(c, d) {
+ var a = this.c,
+ b = this.b;
+ this.o = c;
+ for (var e = a.length - 258, f, g, h, k; 256 !== (f = E(this, c));)
+ if (256 > f) b >= e && (this.b = b, a = this.e(), b = this.b), a[b++] = f;
+ else {
+ g = f - 257;
+ k = I[g];
+ 0 < K[g] && (k += C(this, K[g]));
+ f = E(this, d);
+ h = da[f];
+ 0 < N[f] && (h += C(this, N[f]));
+ b >= e && (this.b = b, a = this.e(), b = this.b);
+ for (; k--;) a[b] = a[b++ - h]
+ }
+ for (; 8 <= this.d;) this.d -= 8, this.a--;
+ this.b = b
+ };
+ w.prototype.w = function(c, d) {
+ var a = this.c,
+ b = this.b;
+ this.o = c;
+ for (var e = a.length, f, g, h, k; 256 !== (f = E(this, c));)
+ if (256 > f) b >= e && (a = this.e(), e = a.length), a[b++] = f;
+ else {
+ g = f - 257;
+ k = I[g];
+ 0 < K[g] && (k += C(this, K[g]));
+ f = E(this, d);
+ h = da[f];
+ 0 < N[f] && (h += C(this, N[f]));
+ b + k > e && (a = this.e(), e = a.length);
+ for (; k--;) a[b] = a[b++ - h]
+ }
+ for (; 8 <= this.d;) this.d -= 8, this.a--;
+ this.b = b
+ };
+ w.prototype.e = function() {
+ var c = new(t ? Uint8Array : Array)(this.b - 32768),
+ d = this.b - 32768,
+ a, b, e = this.c;
+ if (t) c.set(e.subarray(32768, c.length));
+ else {
+ a = 0;
+ for (b = c.length; a < b; ++a) c[a] = e[a + 32768]
+ }
+ this.g.push(c);
+ this.l += c.length;
+ if (t) e.set(e.subarray(d, d + 32768));
+ else
+ for (a = 0; 32768 > a; ++a) e[a] = e[d + a];
+ this.b = 32768;
+ return e
+ };
+ w.prototype.z = function(c) {
+ var d, a = this.input.length / this.a + 1 | 0,
+ b, e, f, g = this.input,
+ h = this.c;
+ c && ("number" === typeof c.p && (a = c.p), "number" === typeof c.u && (a += c.u));
+ 2 > a ? (b = (g.length - this.a) / this.o[2], f = 258 * (b / 2) | 0, e = f < h.length ? h.length + f : h.length << 1) : e = h.length * a;
+ t ? (d = new Uint8Array(e), d.set(h)) : d = h;
+ return this.c = d
+ };
+ w.prototype.n = function() {
+ var c = 0,
+ d = this.c,
+ a = this.g,
+ b, e = new(t ? Uint8Array : Array)(this.l + (this.b - 32768)),
+ f, g, h, k;
+ if (0 === a.length) return t ? this.c.subarray(32768, this.b) : this.c.slice(32768, this.b);
+ f = 0;
+ for (g = a.length; f < g; ++f) {
+ b = a[f];
+ h = 0;
+ for (k = b.length; h < k; ++h) e[c++] = b[h]
+ }
+ f = 32768;
+ for (g = this.b; f < g; ++f) e[c++] = d[f];
+ this.g = [];
+ return this.buffer = e
+ };
+ w.prototype.v = function() {
+ var c, d = this.b;
+ t ? this.r ? (c = new Uint8Array(d), c.set(this.c.subarray(0, d))) : c = this.c.subarray(0, d) : (this.c.length > d && (this.c.length = d), c = this.c);
+ return this.buffer = c
+ };
+
+ function W(c, d) {
+ var a, b;
+ this.input = c;
+ this.a = 0;
+ if (d || !(d = {})) d.index && (this.a = d.index), d.verify && (this.A = d.verify);
+ a = c[this.a++];
+ b = c[this.a++];
+ switch (a & 15) {
+ case ha:
+ this.method = ha;
+ break;
+ default:
+ throw Error("unsupported compression method");
+ }
+ if (0 !== ((a << 8) + b) % 31) throw Error("invalid fcheck flag:" + ((a << 8) + b) % 31);
+ if (b & 32) throw Error("fdict flag is not supported");
+ this.q = new w(c, {
+ index: this.a,
+ bufferSize: d.bufferSize,
+ bufferType: d.bufferType,
+ resize: d.resize
+ })
+ }
+ W.prototype.k = function() {
+ var c = this.input,
+ d, a;
+ d = this.q.k();
+ this.a = this.q.a;
+ if (this.A) {
+ a = (c[this.a++] << 24 | c[this.a++] << 16 | c[this.a++] << 8 | c[this.a++]) >>> 0;
+ var b = d;
+ if ("string" === typeof b) {
+ var e = b.split(""),
+ f, g;
+ f = 0;
+ for (g = e.length; f < g; f++) e[f] = (e[f].charCodeAt(0) & 255) >>> 0;
+ b = e
+ }
+ for (var h = 1, k = 0, m = b.length, n, p = 0; 0 < m;) {
+ n = 1024 < m ? 1024 : m;
+ m -= n;
+ do h += b[p++], k += h; while (--n);
+ h %= 65521;
+ k %= 65521
+ }
+ if (a !== (k << 16 | h) >>> 0) throw Error("invalid adler-32 checksum");
+ }
+ return d
+ };
+ var ha = 8;
+ r("Zlib.Inflate", W);
+ r("Zlib.Inflate.prototype.decompress", W.prototype.k);
+ var X = {
+ ADAPTIVE: B.s,
+ BLOCK: B.t
+ },
+ Y, Z, $, ia;
+ if (Object.keys) Y = Object.keys(X);
+ else
+ for (Z in Y = [], $ = 0, X) Y[$++] = Z;
+ $ = 0;
+ for (ia = Y.length; $ < ia; ++$) Z = Y[$], r("Zlib.Inflate.BufferType." + Z, X[Z]);
+}).call(this);
\ No newline at end of file
diff --git a/subway-surfers-ny/js/main.js b/subway-surfers-ny/js/main.js
new file mode 100644
index 00000000..4cd9ff3f
--- /dev/null
+++ b/subway-surfers-ny/js/main.js
@@ -0,0 +1,13254 @@
+!(function (h) {
+ function webpackJsonpCallback(t) {
+ for (var e, i, n = t[0], o = t[1], s = t[2], a = 0, r = []; a < n.length; a++) (i = n[a]), d[i] && r.push(d[i][0]), (d[i] = 0);
+ for (e in o) Object.prototype.hasOwnProperty.call(o, e) && (h[e] = o[e]);
+ for (c && c(t); r.length; ) r.shift()();
+ return l.push.apply(l, s || []), checkDeferredModules();
+ }
+
+ function checkDeferredModules() {
+ for (var t, e = 0; e < l.length; e++) {
+ for (var i = l[e], n = !0, o = 1; o < i.length; o++) {
+ var s = i[o];
+ 0 !== d[s] && (n = !1);
+ }
+ n && (l.splice(e--, 1), (t = __webpack_require__((__webpack_require__.s = i[0]))));
+ }
+ return t;
+ }
+ var i = {},
+ d = {
+ 1: 0,
+ },
+ l = [];
+
+ function __webpack_require__(t) {
+ if (i[t]) return i[t].exports;
+ var e = (i[t] = {
+ i: t,
+ l: !1,
+ exports: {},
+ });
+ return h[t].call(e.exports, e, e.exports, __webpack_require__), (e.l = !0), e.exports;
+ }
+ (__webpack_require__.m = h),
+ (__webpack_require__.c = i),
+ (__webpack_require__.d = function (t, e, i) {
+ __webpack_require__.o(t, e) ||
+ Object.defineProperty(t, e, {
+ enumerable: !0,
+ get: i,
+ });
+ }),
+ (__webpack_require__.r = function (t) {
+ "undefined" != typeof Symbol &&
+ Symbol.toStringTag &&
+ Object.defineProperty(t, Symbol.toStringTag, {
+ value: "Module",
+ }),
+ Object.defineProperty(t, "__esModule", {
+ value: !0,
+ });
+ }),
+ (__webpack_require__.t = function (e, t) {
+ if ((1 & t && (e = __webpack_require__(e)), 8 & t)) return e;
+ if (4 & t && "object" == typeof e && e && e.__esModule) return e;
+ var i = Object.create(null);
+ if (
+ (__webpack_require__.r(i),
+ Object.defineProperty(i, "default", {
+ enumerable: !0,
+ value: e,
+ }),
+ 2 & t && "string" != typeof e)
+ )
+ for (var n in e)
+ __webpack_require__.d(
+ i,
+ n,
+ function (t) {
+ return e[t];
+ }.bind(null, n)
+ );
+ return i;
+ }),
+ (__webpack_require__.n = function (t) {
+ var e =
+ t && t.__esModule
+ ? function () {
+ return t["default"];
+ }
+ : function () {
+ return t;
+ };
+ return __webpack_require__.d(e, "a", e), e;
+ }),
+ (__webpack_require__.o = function (t, e) {
+ return Object.prototype.hasOwnProperty.call(t, e);
+ }),
+ (__webpack_require__.p = "");
+ var t = (this.webpackJsonp = this.webpackJsonp || []),
+ e = t.push.bind(t);
+ (t.push = webpackJsonpCallback), (t = t.slice());
+ for (var n = 0; n < t.length; n++) webpackJsonpCallback(t[n]);
+ var c = e;
+ l.push([199, 2]), checkDeferredModules();
+ })({
+ 127: function (t, e, i) {
+ "use strict";
+ i.r(e),
+ (e["default"] = {
+ easy: i(430),
+ expert: i(439),
+ normal: i(446),
+ hard: i(455),
+ main: i(462),
+ special: i(468),
+ });
+ },
+ 129: function (t, e) {
+ t.exports =
+ "//precision highp float;\nvarying vec2 vUvs;\n\nuniform sampler2D diffuse;\nvarying vec3 vNormal;\nvarying float vLight;\nvarying vec3 vPosition;\nvarying vec3 vView;\n\nvoid main()\n{\n\t// vec3 p = vec3(vView * vPosition);\n\t// vec3 v = normalize(-p);\n\t// float vdn = 1.0 - max(dot(v, vNormal), 0.0); \n\n // // gl_FragColor = texture2D(diffuse, vec2(vUvs.x, 1.-vUvs.y));//directionalLightWeighting;\n // // gl_FragColor.rgb = mix(gl_FragColor.rgb*vLight, gl_FragColor.rgb, 0.7);\n\n // if (vdn <= 1.0) {\n // \tgl_FragColor.rgb = vec3(0, 0, 0);\n\t// } else {\n\t// \tgl_FragColor.rgb = vec3(1, 1, 1);\t\n\t// }\n \n vec3 nn = normalize(vNormal);\n vec3 light_dir = normalize(vPosition);\n vec3 eye_dir = normalize(-vPosition);\n vec3 reflect_dir = normalize(reflect(light_dir, nn));\n\t\n float spec = max(dot(reflect_dir, eye_dir), 0.0);\n\tfloat diffuse = max(dot(-light_dir, nn), 0.0);\n\n float intensity = 0.6 * diffuse + 0.4 * spec;\n\n \tif (intensity > 0.9) {\n \t\tintensity = 1.1;\n \t}\n \telse if (intensity > 0.5) {\n \t\tintensity = 0.7;\n \t}\n \telse {\n \t\tintensity = 0.0;\n \t}\n\n \t// gl_FragColor = texture2D(diffuse, vec2(vUvs.x, 1.-vUvs.y));\n \t// vec3 col = mix(gl_FragColor.rgb*vLight, gl_FragColor.rgb, 0.7);\n \tgl_FragColor.rgb = vec3(1, 1, 1) * intensity;\n \n}\n";
+ },
+ 130: function (t, e) {
+ t.exports =
+ "\nattribute vec3 position;\nattribute vec3 normals;\nattribute vec4 bone_indices;\nattribute vec2 uvs;\n\nattribute vec4 weights;\n\nvarying vec2 vUvs;\nvarying vec3 vNormal;\nvarying float vLight;\nvarying vec3 vPosition;\nvarying vec3 vView;\n\nuniform mat4 view;\nuniform mat4 model;\nuniform mat3 normal;\nuniform mat4 projection;\n\nuniform mat4 bones[26];\n\nvoid main() {\n\n\tvUvs = uvs;\n\n\tvec4 outPosition = vec4(0.0);\n\tvec4 originalPosition = vec4(position, 1.);\n\n\tmat4 boneMatrix = mat4(0.0);\n\n\tboneMatrix += bones[int(bone_indices.x)] * weights.x;\n\tboneMatrix += bones[int(bone_indices.y)] * weights.y;\n\tboneMatrix += bones[int(bone_indices.z)] * weights.z;\n\tboneMatrix += bones[int(bone_indices.w)] * weights.w;\n\t// vNormal = normalize( normal * (vec4(boneMatrix * vec4(normals,0.0)).xyz) );\n\n\tvec3 transformedNormal = normalize( normal * (vec4(boneMatrix * vec4(normals,0.0)).xyz) );\n\tvNormal = transformedNormal;\n\tvPosition = position;\n\n\tvec3 p;\n\tvView = vec3(view * vec4(p, 0.0));\n\n\t// no light for now\n\t// vLight = max(dot(transformedNormal, vec3(0.0, 0.0,1.0)), 0.0);\n\tvLight = 1.0;\n\n gl_Position = projection * view * model * boneMatrix * originalPosition;\n}\n";
+ },
+ 132: function (t) {
+ t.exports = {
+ default: {
+ image: {},
+ fonts: {},
+ audio: {},
+ model: {},
+ json: {},
+ animate: {},
+ misc: {},
+ },
+ audio: {
+ image: {},
+ fonts: {},
+ audio: {
+ "audio/guard_catch": {
+ mp3: "audio/guard_catch.mp3",
+ ogg: "audio/guard_catch.ogg",
+ },
+ "audio/guard_proximity": {
+ mp3: "audio/guard_proximity.mp3",
+ ogg: "audio/guard_proximity.ogg",
+ },
+ "audio/guard_start": {
+ mp3: "audio/guard_start.mp3",
+ ogg: "audio/guard_start.ogg",
+ },
+ "audio/hero_death": {
+ mp3: "audio/hero_death.mp3",
+ ogg: "audio/hero_death.ogg",
+ },
+ "audio/hero_death_hitcam": {
+ mp3: "audio/hero_death_hitcam.mp3",
+ ogg: "audio/hero_death_hitcam.ogg",
+ },
+ "audio/hero_dodge": {
+ mp3: "audio/hero_dodge.mp3",
+ ogg: "audio/hero_dodge.ogg",
+ },
+ "audio/hero_foot_l": {
+ mp3: "audio/hero_foot_l.mp3",
+ ogg: "audio/hero_foot_l.ogg",
+ },
+ "audio/hero_foot_r": {
+ mp3: "audio/hero_foot_r.mp3",
+ ogg: "audio/hero_foot_r.ogg",
+ },
+ "audio/hero_hoverboard_crash": {
+ mp3: "audio/hero_hoverboard_crash.mp3",
+ ogg: "audio/hero_hoverboard_crash.ogg",
+ },
+ "audio/hero_jump": {
+ mp3: "audio/hero_jump.mp3",
+ ogg: "audio/hero_jump.ogg",
+ },
+ "audio/hero_revive": {
+ mp3: "audio/hero_revive.mp3",
+ ogg: "audio/hero_revive.ogg",
+ },
+ "audio/hero_roll": {
+ mp3: "audio/hero_roll.mp3",
+ ogg: "audio/hero_roll.ogg",
+ },
+ "audio/hero_sneakers_foot_l": {
+ mp3: "audio/hero_sneakers_foot_l.mp3",
+ ogg: "audio/hero_sneakers_foot_l.ogg",
+ },
+ "audio/hero_sneakers_foot_r": {
+ mp3: "audio/hero_sneakers_foot_r.mp3",
+ ogg: "audio/hero_sneakers_foot_r.ogg",
+ },
+ "audio/hero_sneakers_jump": {
+ mp3: "audio/hero_sneakers_jump.mp3",
+ ogg: "audio/hero_sneakers_jump.ogg",
+ },
+ "audio/hero_stumble": {
+ mp3: "audio/hero_stumble.mp3",
+ ogg: "audio/hero_stumble.ogg",
+ },
+ "audio/pickup_coin": {
+ mp3: "audio/pickup_coin.mp3",
+ ogg: "audio/pickup_coin.ogg",
+ },
+ "audio/pickup_powerup": {
+ mp3: "audio/pickup_powerup.mp3",
+ ogg: "audio/pickup_powerup.ogg",
+ },
+ "audio/special_jetpack": {
+ mp3: "audio/special_jetpack.mp3",
+ ogg: "audio/special_jetpack.ogg",
+ },
+ "audio/special_jetpack_start": {
+ mp3: "audio/special_jetpack_start.mp3",
+ ogg: "audio/special_jetpack_start.ogg",
+ },
+ "audio/special_magnet": {
+ mp3: "audio/special_magnet.mp3",
+ ogg: "audio/special_magnet.ogg",
+ },
+ "audio/theme": {
+ mp3: "audio/theme.mp3",
+ ogg: "audio/theme.ogg",
+ },
+ "audio/ui_button": {
+ mp3: "audio/ui_button.mp3",
+ ogg: "audio/ui_button.ogg",
+ },
+ },
+ model: {},
+ json: {},
+ animate: {},
+ misc: {},
+ },
+ data: {
+ image: {},
+ fonts: {},
+ audio: {},
+ model: {},
+ json: {
+ "data/config": {
+ default: "data/config.json",
+ },
+ "data/strings_en": {
+ default: "data/strings_en.json",
+ },
+ "data/strings_pt-br": {
+ default: "data/strings_pt-br.json",
+ },
+ },
+ animate: {},
+ misc: {},
+ },
+ chunks_game: {
+ image: {},
+ fonts: {},
+ audio: {},
+ model: {},
+ json: {},
+ animate: {},
+ misc: {
+ "data/chunks_game": {
+ tags: {
+ manifest: !0,
+ },
+ default: "data/chunks_game.json",
+ },
+ },
+ },
+ chunks_idle: {
+ image: {},
+ fonts: {},
+ audio: {},
+ model: {},
+ json: {},
+ animate: {},
+ misc: {
+ "data/chunks_idle": {
+ tags: {
+ manifest: !0,
+ },
+ default: "data/chunks_idle.json",
+ },
+ },
+ },
+ font: {
+ image: {},
+ fonts: {},
+ audio: {},
+ model: {},
+ json: {},
+ animate: {},
+ misc: {
+ "font/lilita-one": {
+ default: "font/lilita-one.css",
+ },
+ "font/lilita-one-1": {
+ default: "font/lilita-one.woff",
+ },
+ "font/lilita-one-2": {
+ default: "font/lilita-one.woff2",
+ },
+ "font/titan-one": {
+ default: "font/titan-one.css",
+ },
+ "font/titan-one-1": {
+ default: "font/titan-one.woff",
+ },
+ "font/titan-one-2": {
+ default: "font/titan-one.woff2",
+ },
+ },
+ },
+ game: {
+ image: {
+ "game/board_new_york_tex": {
+ default: "game/board_new_york_tex.png",
+ low: "game/board_new_york_tex_mip.png",
+ },
+ "game/effects_tex": {
+ default: "game/effects_tex.png",
+ low: "game/effects_tex_mip.png",
+ },
+ "game/enemies": {
+ default: "game/enemies.png",
+ low: "game/enemies_mip.png",
+ },
+ "game/halo": {
+ default: "game/halo.png",
+ low: "game/halo_mip.png",
+ },
+ "game/jetpackSmoke": {
+ default: "game/jetpackSmoke.png",
+ low: "game/jetpackSmoke_mip.png",
+ },
+ "game/ocean": {
+ default: "game/ocean.png",
+ low: "game/ocean_mip.png",
+ },
+ "game/shadow": {
+ default: "game/shadow.png",
+ low: "game/shadow_mip.png",
+ },
+ "game/spraySplash": {
+ default: "game/spraySplash.png",
+ low: "game/spraySplash_mip.png",
+ },
+ },
+ fonts: {},
+ audio: {},
+ model: {},
+ json: {},
+ animate: {},
+ misc: {
+ "game/board_new_york": {
+ default: "game/board_new_york.fbx",
+ },
+ "game/board_new_york01": {
+ default: "game/board_new_york01.fbx",
+ },
+ "game/environment": {
+ default: "game/environment.fbx",
+ },
+ "game/model_avatar_catch": {
+ default: "game/model_avatar_catch.fbx",
+ },
+ "game/model_avatar_movement": {
+ default: "game/model_avatar_movement.fbx",
+ },
+ "game/model_avatar_powerup_jet_pack": {
+ default: "game/model_avatar_powerup_jet_pack.fbx",
+ },
+ "game/model_avatar_powerup_pogostick": {
+ default: "game/model_avatar_powerup_pogostick.fbx",
+ },
+ "game/model_avatar_start": {
+ default: "game/model_avatar_start.fbx",
+ },
+ "game/model_dog_catch": {
+ default: "game/model_dog_catch.fbx",
+ },
+ "game/model_dog_movement": {
+ default: "game/model_dog_movement.fbx",
+ },
+ "game/model_guard_catch": {
+ default: "game/model_guard_catch.fbx",
+ },
+ "game/model_guard_movement": {
+ default: "game/model_guard_movement.fbx",
+ },
+ "game/props": {
+ default: "game/props.fbx",
+ },
+ "game/trains": {
+ default: "game/trains.fbx",
+ },
+ },
+ },
+ idle: {
+ image: {
+ "idle/environment_tex": {
+ default: "idle/environment_tex.png",
+ low: "idle/environment_tex_mip.png",
+ },
+ "idle/jake_tex": {
+ default: "idle/jake_tex.png",
+ low: "idle/jake_tex_mip.png",
+ },
+ "idle/props_tex": {
+ default: "idle/props_tex.png",
+ low: "idle/props_tex_mip.png",
+ },
+ "idle/train_start": {
+ default: "idle/train_start.png",
+ low: "idle/train_start_mip.png",
+ },
+ "idle/trains_tex": {
+ default: "idle/trains_tex.png",
+ low: "idle/trains_tex_mip.png",
+ },
+ },
+ fonts: {},
+ audio: {},
+ model: {},
+ json: {},
+ animate: {},
+ misc: {
+ "idle/environment_idle": {
+ default: "idle/environment_idle.fbx",
+ },
+ "idle/model_avatar_idle_paint": {
+ default: "idle/model_avatar_idle_paint.fbx",
+ },
+ "idle/props_start": {
+ default: "idle/props_start.fbx",
+ },
+ "idle/trains_start": {
+ default: "idle/trains_start.fbx",
+ },
+ },
+ },
+ placeholder: {
+ image: {
+ "placeholder/box_base": {
+ default: "placeholder/box_base.png",
+ },
+ "placeholder/icon_00_brody": {
+ default: "placeholder/icon_00_brody.png",
+ },
+ "placeholder/icon_01_tagbot": {
+ default: "placeholder/icon_01_tagbot.png",
+ },
+ "placeholder/icon_02_tasha": {
+ default: "placeholder/icon_02_tasha.png",
+ },
+ "placeholder/icon_03_ninja": {
+ default: "placeholder/icon_03_ninja.png",
+ },
+ "placeholder/icon_04_lucy": {
+ default: "placeholder/icon_04_lucy.png",
+ },
+ "placeholder/icon_05_king": {
+ default: "placeholder/icon_05_king.png",
+ },
+ "placeholder/icon_06_frizzy": {
+ default: "placeholder/icon_06_frizzy.png",
+ },
+ "placeholder/icon_07_yutani": {
+ default: "placeholder/icon_07_yutani.png",
+ },
+ "placeholder/icon_08_spike": {
+ default: "placeholder/icon_08_spike.png",
+ },
+ "placeholder/icon_09_fresh": {
+ default: "placeholder/icon_09_fresh.png",
+ },
+ "placeholder/icon_10_jake": {
+ default: "placeholder/icon_10_jake.png",
+ },
+ "placeholder/icon_11_tricky": {
+ default: "placeholder/icon_11_tricky.png",
+ },
+ "placeholder/icon_friend": {
+ default: "placeholder/icon_friend.png",
+ },
+ "placeholder/jake": {
+ default: "placeholder/jake.png",
+ },
+ },
+ fonts: {},
+ audio: {},
+ model: {},
+ json: {},
+ animate: {},
+ misc: {},
+ },
+ preload: {
+ image: {
+ "preload/splash": {
+ tags: {
+ quant: !0,
+ },
+ default: "preload/splash.png",
+ low: "preload/splash_mip.png",
+ },
+ },
+ fonts: {},
+ audio: {},
+ model: {},
+ json: {},
+ animate: {},
+ misc: {},
+ },
+ ui: {
+ image: {
+ "ui/ui": {
+ tags: {
+ fix: !0,
+ tps: !0,
+ manifest: !0,
+ },
+ default: "ui/ui.json",
+ },
+ },
+ fonts: {},
+ audio: {},
+ model: {},
+ json: {},
+ animate: {},
+ misc: {},
+ },
+ };
+ },
+ 186: function (t, e) {
+ t.exports =
+ "\nattribute vec3 position;\nattribute vec3 normals;\nattribute vec2 uvs;\n\nuniform mat4 projection;\nuniform mat4 view;\n\nvarying vec3 vNormal;\nvarying vec3 vPosition;\nvarying vec4 vScreenPosition;\n\n#ifdef INSTANCING\n\tattribute vec3 i_mat1;\n\tattribute vec3 i_mat2;\n\tattribute vec3 i_mat3;\n\tattribute vec3 i_mat4;\n attribute vec3 i_norm1;\n\tattribute vec3 i_norm2;\n\tattribute vec3 i_norm3;\n#else\n uniform mat4 model;\n uniform mat3 normal;\n#endif\n\n#if defined( MAP ) || defined( EMISSIVE_MAP ) || defined( OCCLUSION_MAP )\n\tvarying vec2 vUv;\n uniform vec4 uMapFrame;\n#endif\n\n#ifdef FOG\n uniform float uFogDistance;\n uniform float uFogDensity;\n varying float vFogFactor;\n uniform vec3 uFogColor;\n varying vec3 vFogColor;\n#endif\n\n\n#ifdef BEND\n\nuniform vec2 uBend;\n\nvec4 bend(vec4 pos) {\n float dx = uBend.x;\n float dy = uBend.y;\n float z_sqr = pos.w * pos.w;\n\tpos.x = pos.x + z_sqr * dx;\n\tpos.y = pos.y + z_sqr * dy;\n\treturn pos;\n}\n\n#endif\n\n#HOOK_VERTEX_START\n\nvoid main() {\n\t\n#if defined( MAP ) || defined( EMISSIVE_MAP )\n\tvUv = (uvs * uMapFrame.zw ) + uMapFrame.xy;\n#endif\n\n#ifdef INSTANCING\n mat4 model = mat4(vec4(i_mat1, 0.), \n vec4(i_mat2, 0.), \n vec4(i_mat3, 0.), \n vec4(i_mat4, 1.));\n\n mat3 normal = mat3(i_norm1, \n i_norm2, \n i_norm3);\n#endif\n\n vec3 transformed = position;\n\n vNormal = normalize( normal * normals);\n \n #HOOK_VERTEX_MAIN\n\n\tvec4 worldPosition = model * vec4(transformed, 1.0);\n\tvec4 worldViewPosition = projection * view * worldPosition;\n // clamp z position?\n // worldViewPosition.z = mod(worldViewPosition.z, 3000.0);\n vPosition = worldPosition.xyz;\n vScreenPosition = worldViewPosition;\n \n \n#ifdef BEND\n gl_Position = bend(worldViewPosition);\n#else\n gl_Position = worldViewPosition;\n#endif \n\n#ifdef FOG\n float depth = worldViewPosition.z - uFogDistance;\n vFogFactor = clamp(depth / uFogDistance, 0.0, 1.0);\n vFogColor = uFogColor;\n#endif\n\n\t#HOOK_VERTEX_END\n\n}";
+ },
+ 187: function (t, e) {
+ t.exports =
+ "uniform vec3 uGlobalAmbient;\nuniform float uOpacity;\nuniform vec3 uAmbiantLight;\n\nvarying vec3 vNormal;\nvarying vec3 vPosition;\nvarying vec4 vScreenPosition;\n\n#ifdef COLOR\nuniform vec3 uColor;\n#endif\n\n#ifdef OCCLUSION_MAP\nuniform sampler2D uOcclusionMap;\n#endif\n\n#if defined( MAP ) || defined( EMISSIVE_MAP ) || defined( OCCLUSION_MAP )\nvarying vec2 vUv;\n#endif\n\n#ifdef MAP\nuniform sampler2D uMap;\n#endif\n\n#ifdef FOG\nvarying float vFogFactor;\nvarying vec3 vFogColor;\n#endif\n\n#HOOK_LIGHT_UNIFROMS\n\nvec3 gammaCorrectInput(vec3 color) {\n return pow(color, vec3(2.2));\n}\n\nfloat gammaCorrectInput(float color) {\n return pow(color, 2.2);\n}\n\nvec4 gammaCorrectInput(vec4 color) {\n return vec4(pow(color.rgb, vec3(2.2)), color.a);\n}\n\nvec3 gammaCorrectOutput(vec3 color) {\n color += vec3(0.0000001);\n return pow(color, vec3(0.45));\n}\n\nvec4 texture2DSRGB(sampler2D tex, vec2 uv) {\n vec4 rgba = texture2D(tex, uv);\n rgba.rgb = gammaCorrectInput(rgba.rgb);\n return rgba;\n}\n\n\n#HOOK_FRAGMENT_START\n\nvoid main() {\n vec4 finalColor = vec4(0.0, 0.0, 0.0, uOpacity);\n vec4 diffuseColor = vec4(1.0, 1.0, 1.0, uOpacity);\n\n#ifdef COLOR\n diffuseColor.rgb *= uColor;\n#endif\n\n#ifdef MAP\n // diffuseColor *= texture2DSRGB(uMap, vUv);\n diffuseColor *= texture2D(uMap, vUv);\n#endif\n\n #HOOK_LIGHT;\n\n finalColor.rgb = diffuseColor.rgb;\n finalColor *= diffuseColor.a;\n \n #HOOK_FRAGMENT_MAIN\n\n \n gl_FragColor = vec4(finalColor.rgb * finalColor.a, finalColor.a);\n \n #HOOK_FRAGMENT_END\n\n#ifdef FOG\n // FORCING FOG COLOR TO PREVENT A BUG WHERE SOME RED FOG OBJECT WHERE SHOWING UP \n gl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(0.388, 0.698, 1.0), vFogFactor);\n#endif\n\n // gl_FragColor.rgb = gammaCorrectOutput(gl_FragColor.rgb);\n\n\n#ifdef RAILS\n if (vPosition.y < 1.2) return;\n\n float reflWidth = 1.5;\n float railDist = 7.0;\n float laneWidth = 20.0;\n vec3 reflColor = vec3(1.0, 1.0, 1.0);\n float reflFactor = abs(vScreenPosition.z - 100.0) * 0.02;\n if (reflFactor < 0.0) reflFactor = 0.0;\n if (reflFactor > 1.0) return;\n\n\n // Middle lane\n if (vPosition.x > -4.0 && vPosition.x < -2.5) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n } else if (vPosition.x > 2.5 && vPosition.x < 4.0) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n }\n\n // Left lane\n if (vPosition.x > -4.0 - laneWidth && vPosition.x < -2.5 - laneWidth) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n } else if (vPosition.x > 2.5 - laneWidth && vPosition.x < 4.0 - laneWidth) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n }\n\n // Right lane\n if (vPosition.x > -4.0 + laneWidth && vPosition.x < -2.5 + laneWidth) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n } else if (vPosition.x > 2.5 + laneWidth && vPosition.x < 4.0 + laneWidth) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n }\n#endif\n}\n";
+ },
+ 188: function (t, e) {
+ t.exports =
+ "attribute vec3 position;\nattribute vec3 normals;\nattribute vec2 uvs;\n\nuniform mat4 projection;\nuniform mat4 view;\nuniform mat4 model;\nuniform mat3 normal;\n\n#if defined( MAP ) || defined( EMISSIVE_MAP ) || defined( OCCLUSION_MAP )\nvarying vec2 vUv;\nuniform vec4 uMapFrame;\n#endif\n\n\n#HOOK_VERTEX_START\n\nvoid main() {\n\t\n#if defined( MAP ) || defined( EMISSIVE_MAP )\n\t//vUv = uvs;\n\tvUv = (uvs * uMapFrame.zw ) + uMapFrame.xy;\n#endif\n \n #HOOK_VERTEX_MAIN\n\t\n vec4 worldPosition = model * vec4(position, 1.0);\n\tvec4 worldViewPosition = projection * view * worldPosition;\n\tgl_Position = worldViewPosition;\n\t\n #HOOK_VERTEX_END\n}";
+ },
+ 189: function (t, e) {
+ t.exports =
+ "#ifdef COLOR\nuniform vec3 uColor;\n#endif\n\n#if defined( MAP ) || defined( EMISSIVE_MAP ) || defined( OCCLUSION_MAP )\nvarying vec2 vUv;\n#endif\n\n#ifdef MAP\nuniform sampler2D uMap;\n#endif\n\nvoid main() {\n gl_FragColor = texture2D(uMap, vUv);\n gl_FragColor.rgb *= uColor.rgb;\n}\n";
+ },
+ 190: function (t, e) {
+ t.exports =
+ "\nattribute vec3 position;\nattribute vec3 normals;\nattribute vec2 uvs;\n\nuniform mat4 projection;\nuniform mat4 view;\n\n\n\nvarying vec3 vNormal;\nvarying vec3 vPosition;\nvarying vec4 vScreenPosition;\n\nuniform float uTime;\nvarying float vTime;\n\n\n#ifdef INSTANCING\n\tattribute vec3 i_mat1;\n\tattribute vec3 i_mat2;\n\tattribute vec3 i_mat3;\n\tattribute vec3 i_mat4;\n\n attribute vec3 i_norm1;\n\tattribute vec3 i_norm2;\n\tattribute vec3 i_norm3;\n\n#else\n uniform mat4 model;\n uniform mat3 normal;\n#endif\n\n#if defined( MAP ) || defined( EMISSIVE_MAP ) || defined( OCCLUSION_MAP )\n\tvarying vec2 vUv;\n uniform vec4 uMapFrame;\n#endif\n\n#define FOG\n\n#ifdef FOG\n uniform float uFogDistance;\n uniform float uFogDensity;\n varying float vFogFactor;\n uniform vec3 uFogColor;\n varying vec3 vFogColor;\n#endif\n\n\n\n#HOOK_VERTEX_START\n\nuniform vec2 uBend;\nvec4 bend(vec4 pos) {\n // hardcoding values just for testing\n // float dx = -0.001;\n // float dy = -0.0003;\n float dx = uBend.x;\n float dy = uBend.y;\n float z_sqr = pos.w * pos.w;\n\tpos.x = pos.x + z_sqr * dx;\n\tpos.y = pos.y + z_sqr * dy;\n\treturn pos;\n}\n\nvec4 wave(vec4 pos, float t) {\n pos.y += sin(pos.z*0.05) * cos(pos.x*0.05) * 5.0 + 5.0;\n\treturn pos;\n}\n\nvoid main() {\n #if defined( MAP ) || defined( EMISSIVE_MAP )\n\t//vUv = uvs;\n\tvUv = (uvs * uMapFrame.zw ) + uMapFrame.xy;\n \n\t#endif\n\n #ifdef INSTANCING\n\n mat4 model = mat4(vec4(i_mat1, 0.), \n vec4(i_mat2, 0.), \n vec4(i_mat3, 0.), \n vec4(i_mat4, 1.));\n\n mat3 normal = mat3(i_norm1, \n i_norm2, \n i_norm3);\n\n #endif\n\n vec3 transformed = position;\n\n vNormal = normalize( normal * normals);\n \n #HOOK_VERTEX_MAIN\n\n\tvec4 worldPosition = model * vec4(transformed, 1.0);\n\tvec4 worldViewPosition = projection * view * worldPosition;\n vPosition = worldPosition.xyz;\n vTime = worldPosition.z * 0.1;\n \n // clamp z position?\n // worldViewPosition.z = mod(worldViewPosition.z, 3000.0);\n\n vScreenPosition = worldViewPosition;\n\n\t// gl_Position = worldViewPosition;\n worldViewPosition = wave(worldViewPosition, uTime);\n gl_Position = bend(worldViewPosition);\n\n\t#ifdef FOG\n // float depth = worldViewPosition.z - uFogDistance;\n // vFogFactor = exp(-depth * uFogDensity);\n // vFogFactor = clamp(vFogFactor, 0.0, 1.0);\n // vFogColor = uFogColor;\n float depth = worldViewPosition.z - uFogDistance;\n vFogFactor = clamp(depth / uFogDistance, 0.0, 1.0);\n vFogColor = uFogColor;\n #endif\n\n\t#HOOK_VERTEX_END\n\n}";
+ },
+ 191: function (t, e) {
+ t.exports =
+ "\n\nuniform vec3 uGlobalAmbient;\n\nuniform float uOpacity;\n\nuniform vec3 uAmbiantLight;\n\nvarying vec3 vNormal;\nvarying vec3 vPosition;\nvarying vec4 vScreenPosition;\n\n#ifdef COLOR\nuniform vec3 uColor;\n#endif\n\n#ifdef OCCLUSION_MAP\nuniform sampler2D uOcclusionMap;\n#endif\n\n#if defined( MAP ) || defined( EMISSIVE_MAP ) || defined( OCCLUSION_MAP )\nvarying vec2 vUv;\n#endif\n\n#ifdef MAP\nuniform sampler2D uMap;\n#endif\n\n// #define FOG\n\n#ifdef FOG\n varying float vFogFactor;\n varying vec3 vFogColor;\n#endif\n\nvarying float vTime;\n\n#HOOK_LIGHT_UNIFROMS\n\n/** \n gamma stuff!\n*/\nvec3 gammaCorrectInput(vec3 color) {\n return pow(color, vec3(2.2));\n}\n\nfloat gammaCorrectInput(float color) {\n return pow(color, 2.2);\n}\n\nvec4 gammaCorrectInput(vec4 color) {\n return vec4(pow(color.rgb, vec3(2.2)), color.a);\n}\n\nvec3 gammaCorrectOutput(vec3 color) {\n color += vec3(0.0000001);\n return pow(color, vec3(0.45));\n}\n\nvec4 texture2DSRGB(sampler2D tex, vec2 uv) {\n vec4 rgba = texture2D(tex, uv);\n rgba.rgb = gammaCorrectInput(rgba.rgb);\n return rgba;\n}\n\n\nfloat diffuse(vec3 N, vec3 L) {\n\treturn max(dot(N, L), 0.0);\n}\n\nvec3 diffuseLighting(vec3 N, vec3 L, vec3 C) {\n\treturn diffuse(N, L) * C;\n}\n\n/// speculer lights...\nuniform vec3 uSpecular;\n\n#ifdef SHININESS_FLOAT\n uniform float uShininess;\n#endif\n\n#ifdef SHININESS_MAP\n uniform sampler2D uShininessMap;\n#endif\n\n// we write the specular to here..\nfloat dShininess;\n\n// glosyness..\nvoid getShininess() {\n dShininess = 1.0;\n #ifdef SHININESS_FLOAT\n dShininess *= uShininess;\n #endif\n #ifdef SHININESS_MAP\n dShininess *= texture2D(uShininessMap, vUv).r;\n #endif\n \n //IOS hack.. \n dShininess += 0.0000001;\n}\n\n/// emissive lights...\n#ifdef EMISSIVE_FLOAT\n uniform float uEmissive;\n#endif\n\n#ifdef EMISSIVE_COLOR\n uniform vec3 uEmissiveColor;\n#endif\n\n#ifdef EMISSIVE_MAP\n uniform sampler2D uEmissiveMap;\n#endif\n\n// we write the specular to here..\nvec3 dEmissive;\n\n// glosyness..\nvec3 getEmission() {\n vec3 emission = vec3(1.);\n\n #ifdef EMISSIVE_FLOAT\n emission *= uEmissive;\n #endif\n\n #ifdef EMISSIVE_COLOR\n emission *= uEmissiveColor;\n #endif\n \n #ifdef EMISSIVE_MAP\n emission *= texture2D(uEmissiveMap, vUv).rgb;\n #endif\n \n return emission;\n}\n\nvec3 specularLighting(vec3 N, vec3 L, vec3 V) \n{\n vec3 R = reflect(-L, N); // Reflected light vector\n\n float specular = pow(max(dot(R, -V), 0.0), dShininess + 0.0001);\n \n return specular * uSpecular;\n}\n\n#define saturate(a) clamp( a, 0.0, 1.0 )\n\n\n#HOOK_FRAGMENT_START\n\nvoid main() {\n vec4 finalColor = vec4(0.0,0.0,0.0, uOpacity);\n vec4 diffuseColor = vec4(1., 1., 1., uOpacity);\n\n\n #ifdef COLOR\n diffuseColor.rgb *= uColor;\n #endif\n\n #ifdef MAP\n diffuseColor *= texture2DSRGB(uMap, vec2(vUv.x, vUv.y + sin(vScreenPosition.z* 0.0005) * 0.5));\n \n #endif\n\n #ifdef OCCLUSION_MAP\n diffuseColor *= texture2DSRGB(uOcclusionMap, vUv);\n #endif\n\n vec3 lighting = vec3(0.0);\n vec3 specular = vec3(0.0);\n\n lighting += uGlobalAmbient;\n\n vec3 N = normalize(vNormal);\n vec3 V = normalize(-vPosition);\n \n // some temp variables \n vec3 L;\n vec3 lightDirection;\n float attenuation;\n float dist;\n\n getShininess();\n // do lighting..\n #HOOK_LIGHT;\n\n finalColor.rgb = diffuseColor.rgb * lighting;// + uEmissive;\n\n /// finalColor.rgb += specular;//mix(finalColor.rgb, specularLighting, )\n finalColor *= diffuseColor.a;\n \n #HOOK_FRAGMENT_MAIN\n\n \n #ifdef EMISSIVE\n\n finalColor.rgb += getEmission();\n\n #endif\n\n gl_FragColor = vec4(finalColor.rgb * finalColor.a, finalColor.a);\n \n #HOOK_FRAGMENT_END\n\n #ifdef FOG\n // gl_FragColor.rgb = mix(vec3(0.388, 0.698, 1.0), gl_FragColor.rgb, vFogFactor);\n // gl_FragColor.rgb = mix(gl_FragColor.rgb, vFogColor, vFogFactor);\n // FORCING FOG COLOR TO PREVENT A BUG WHERE SOME RED FOG OBJECT WHERE SHOWING UP \n gl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(0.388, 0.698, 1.0), vFogFactor);\n #endif\n\n gl_FragColor.rgb = gammaCorrectOutput(gl_FragColor.rgb);\n\n\n #ifdef RAILS\n if (vPosition.y < 1.2) return;\n\n float reflWidth = 1.5;\n float railDist = 7.0;\n float laneWidth = 20.0;\n vec3 reflColor = vec3(1.0, 1.0, 1.0);\n float reflFactor = abs(vScreenPosition.z - 100.0) * 0.02;\n if (reflFactor < 0.0) reflFactor = 0.0;\n if (reflFactor > 1.0) return;\n\n\n // Middle lane\n if (vPosition.x > -4.0 && vPosition.x < -2.5) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n } else if (vPosition.x > 2.5 && vPosition.x < 4.0) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n }\n\n // Left lane\n if (vPosition.x > -4.0 - laneWidth && vPosition.x < -2.5 - laneWidth) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n } else if (vPosition.x > 2.5 - laneWidth && vPosition.x < 4.0 - laneWidth) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n }\n\n // Right lane\n if (vPosition.x > -4.0 + laneWidth && vPosition.x < -2.5 + laneWidth) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n } else if (vPosition.x > 2.5 + laneWidth && vPosition.x < 4.0 + laneWidth) {\n gl_FragColor.rgb = mix(reflColor, gl_FragColor.rgb, reflFactor);\n }\n #endif\n}\n";
+ },
+ 199: function (t, e, i) {
+ i(200), (t.exports = i(487));
+ },
+ 430: function (t, e, i) {
+ "use strict";
+ i.r(e),
+ (e["default"] = {
+ default_train_tops_2: i(431),
+ "route_section_default_s-s": i(432),
+ "default_b-s-b": i(433),
+ "default_s-b-s-b": i(434),
+ "default_s-s-s-s": i(435),
+ default_tunnel_notrain: i(436),
+ default_choice: i(437),
+ default_train_tops_1: i(438),
+ });
+ },
+ 431: function (t) {
+ t.exports = {
+ name: "route_section_default_train_tops_2",
+ start: [],
+ mid: ["routeChunk_default_train_tops_2"],
+ end: [],
+ };
+ },
+ 432: function (t) {
+ t.exports = {
+ name: "route_section_default_s-s",
+ start: [],
+ mid: ["routeChunk_default_s-s"],
+ end: [],
+ };
+ },
+ 433: function (t) {
+ t.exports = {
+ name: "route_section_default_b-s-b",
+ start: [],
+ mid: ["routeChunk_default_b-s-b"],
+ end: [],
+ };
+ },
+ 434: function (t) {
+ t.exports = {
+ name: "route_section_default_s-b-s-b",
+ start: [],
+ mid: ["routeChunk_default_s-b-s-b"],
+ end: [],
+ };
+ },
+ 435: function (t) {
+ t.exports = {
+ name: "route_section_default_s-s-s-s",
+ start: [],
+ mid: ["routeChunk_default_s-s-s-s"],
+ end: [],
+ };
+ },
+ 436: function (t) {
+ t.exports = {
+ name: "route_section_default_tunnel_notrain",
+ start: [],
+ mid: ["routeChunk_default_tunnel_notrain"],
+ end: [],
+ };
+ },
+ 437: function (t) {
+ t.exports = {
+ name: "route_section_default_choice",
+ start: [],
+ mid: ["routeChunk_default_choice"],
+ end: [],
+ };
+ },
+ 438: function (t) {
+ t.exports = {
+ name: "route_section_default_train_tops_1",
+ start: [],
+ mid: ["routeChunk_default_train_tops_1"],
+ end: [],
+ };
+ },
+ 439: function (t, e, i) {
+ "use strict";
+ i.r(e),
+ (e["default"] = {
+ default_short_train_tops_moving_multiple: i(440),
+ default_short_2_tracks: i(441),
+ default_short_train_tops_moving: i(442),
+ default_ramp_2: i(443),
+ default_short_train_tops_moving_combined: i(444),
+ default_short_1_track: i(445),
+ });
+ },
+ 440: function (t) {
+ t.exports = {
+ name: "route_section_default_short_train_tops_moving_multiple",
+ start: [],
+ mid: ["routeChunk_short_train_tops_moving_multiple"],
+ end: [],
+ };
+ },
+ 441: function (t) {
+ t.exports = {
+ name: "route_section_default_short_2_tracks",
+ start: ["routeChunk_short_2_tracks_start"],
+ mid: ["routeChunk_short_2_tracks_mid_var_1", "routeChunk_short_2_tracks_mid_var_2"],
+ end: ["routeChunk_short_2_tracks_end"],
+ };
+ },
+ 442: function (t) {
+ t.exports = {
+ name: "route_section_default_short_train_tops_moving",
+ start: [],
+ mid: ["routeChunk_short_train_tops_moving"],
+ end: [],
+ };
+ },
+ 443: function (t) {
+ t.exports = {
+ name: "route_section_default_ramp_2",
+ start: [],
+ mid: ["routeChunk_ramp_2"],
+ end: [],
+ };
+ },
+ 444: function (t) {
+ t.exports = {
+ name: "route_section_default_short_train_tops_moving_combined",
+ start: [],
+ mid: ["routeChunk_short_train_tops_moving_combined"],
+ end: [],
+ };
+ },
+ 445: function (t) {
+ t.exports = {
+ name: "route_section_default_short_1_track",
+ start: [],
+ mid: ["routeChunk_short_1_track"],
+ end: [],
+ };
+ },
+ 446: function (t, e, i) {
+ "use strict";
+ i.r(e),
+ (e["default"] = {
+ default_train_tops_moving: i(447),
+ default_epic: i(448),
+ default_train_tops_moving_multiple: i(449),
+ default_2_tracks: i(450),
+ default_ramp_1: i(451),
+ default_tunnel: i(452),
+ default_train_tops_moving_combined: i(453),
+ default_1_track: i(454),
+ });
+ },
+ 447: function (t) {
+ t.exports = {
+ name: "route_section_default_train_tops_moving",
+ start: [],
+ mid: ["routeChunk_default_train_tops_moving"],
+ end: [],
+ };
+ },
+ 448: function (t) {
+ t.exports = {
+ name: "route_section_default_epic",
+ start: [],
+ mid: ["routeChunk_default_epic"],
+ end: [],
+ };
+ },
+ 449: function (t) {
+ t.exports = {
+ name: "route_section_default_train_tops_moving_multiple",
+ start: [],
+ mid: ["routeChunk_default_train_tops_moving_multiple"],
+ end: [],
+ };
+ },
+ 450: function (t) {
+ t.exports = {
+ name: "route_section_default_2_tracks",
+ start: ["routeChunk_default_2_tracks_start"],
+ mid: ["routeChunk_default_2_tracks_mid_var_1", "routeChunk_default_2_tracks_mid_var_2"],
+ end: ["routeChunk_default_2_tracks_end"],
+ };
+ },
+ 451: function (t) {
+ t.exports = {
+ name: "route_section_default_ramp_1",
+ start: [],
+ mid: ["routeChunk_default_ramp_1"],
+ end: [],
+ };
+ },
+ 452: function (t) {
+ t.exports = {
+ name: "route_section_default_tunnel",
+ start: [],
+ mid: ["routeChunk_default_tunnel"],
+ end: [],
+ };
+ },
+ 453: function (t) {
+ t.exports = {
+ name: "route_section_default_train_tops_moving_combined",
+ start: [],
+ mid: ["routeChunk_default_train_tops_moving_combined"],
+ end: [],
+ };
+ },
+ 454: function (t) {
+ t.exports = {
+ name: "route_section_default_1_track",
+ start: [],
+ mid: ["routeChunk_short_1_track"],
+ end: [],
+ ignored_start: ["routeChunk_default_1_track_start"],
+ ignored_mid: ["routeChunk_default_1_track_mid_var_1", "routeChunk_default_1_track_mid_var_2"],
+ ignored_end: ["routeChunk_default_1_track_end"],
+ };
+ },
+ 455: function (t, e, i) {
+ "use strict";
+ i.r(e),
+ (e["default"] = {
+ default_4_units_3_tracks_choice: i(456),
+ "default_4_units_3_tracks_s-b-s-b": i(457),
+ "default_4_units_3_tracks_b-s-b": i(458),
+ default_epic_various: i(459),
+ "default_4_units_3_tracks_s-s": i(460),
+ "default_4_units_3_tracks_s-s-s-s": i(461),
+ });
+ },
+ 456: function (t) {
+ t.exports = {
+ name: "route_section_default_4_units_3_tracks_choice",
+ start: [],
+ mid: ["routeChunk_4_units_3_tracks_choice"],
+ end: [],
+ };
+ },
+ 457: function (t) {
+ t.exports = {
+ name: "route_section_default_4_units_3_tracks_s-b-s-b",
+ start: [],
+ mid: ["routeChunk_4_units_3_tracks_s-b-s-b"],
+ end: [],
+ };
+ },
+ 458: function (t) {
+ t.exports = {
+ name: "route_section_default_4_units_3_tracks_b-s-b",
+ start: [],
+ mid: ["routeChunk_4_units_3_tracks_b-s-b"],
+ end: [],
+ };
+ },
+ 459: function (t) {
+ t.exports = {
+ name: "route_section_default_epic_various",
+ start: [],
+ mid: ["routeChunk_epic_various"],
+ end: [],
+ };
+ },
+ 460: function (t) {
+ t.exports = {
+ name: "route_section_default_4_units_3_tracks_s-s",
+ start: [],
+ mid: ["routeChunk_4_units_3_tracks_s-s"],
+ end: [],
+ };
+ },
+ 461: function (t) {
+ t.exports = {
+ name: "route_section_default_4_units_3_tracks_s-s-s-s",
+ start: [],
+ mid: ["routeChunk_4_units_3_tracks_s-s-s-s"],
+ end: [],
+ };
+ },
+ 462: function (t, e, i) {
+ "use strict";
+ i.r(e),
+ (e["default"] = {
+ default_start: i(463),
+ default_fallback: i(464),
+ default_start_short: i(465),
+ default_jetpack_landing: i(466),
+ default_no_gameplay: i(467),
+ });
+ },
+ 463: function (t) {
+ t.exports = {
+ name: "routeSection_default_start",
+ start: [],
+ mid: ["routeChunk_default_start1", "routeChunk_default_start2"],
+ end: [],
+ };
+ },
+ 464: function (t) {
+ t.exports = {
+ name: "routeSection_default_fallback",
+ start: [],
+ mid: ["routeChunk_default_fallback"],
+ end: [],
+ };
+ },
+ 465: function (t) {
+ t.exports = {
+ name: "routeSection_default_start_short",
+ start: [],
+ mid: ["routeChunk_default_fallback"],
+ end: [],
+ };
+ },
+ 466: function (t) {
+ t.exports = {
+ name: "routeSection_default_jetpack_landing",
+ start: [],
+ mid: ["routeChunk_default_jetpack_landing"],
+ end: [],
+ };
+ },
+ 467: function (t) {
+ t.exports = {
+ name: "routeSection_default_no_gameplay",
+ start: [],
+ mid: ["routeChunk_default_no_gameplay_1", "routeChunk_default_no_gameplay_2", "routeChunk_default_no_gameplay_epic"],
+ end: [],
+ };
+ },
+ 468: function (t, e, i) {
+ "use strict";
+ i.r(e),
+ (e["default"] = {
+ tutorial: i(469),
+ default_bonus_short: i(470),
+ default_bonus_long: i(471),
+ default_pogostick_start: i(472),
+ });
+ },
+ 469: function (t) {
+ t.exports = {
+ name: "routeSection_tutorial",
+ start: [],
+ mid: ["routeChunk_tutorial"],
+ end: [],
+ };
+ },
+ 470: function (t) {
+ t.exports = {
+ name: "routeSection_default_bonus_short",
+ start: [],
+ mid: ["routeChunk_bonus_short"],
+ end: [],
+ };
+ },
+ 471: function (t) {
+ t.exports = {
+ name: "routeSection_default_bonus_long",
+ start: [],
+ mid: ["routeChunk_bonus_long"],
+ end: [],
+ };
+ },
+ 472: function (t) {
+ t.exports = {
+ name: "routeSection_default_pogostick_start",
+ start: [],
+ mid: ["routeChunk_default_pogostick_start"],
+ end: [],
+ };
+ },
+ 475: function (t) {
+ t.exports = {
+ file: "model_avatar_idle_paint.fbx",
+ texture: "jake_tex",
+ fps: 24,
+ clips: {
+ idle: [1, 220],
+ },
+ };
+ },
+ 476: function (t) {
+ t.exports = {
+ file: "model_avatar_powerup_jet_pack.fbx",
+ texture: "jake_tex",
+ fps: 25,
+ clips: {
+ Jetpack_forward: [1, 12],
+ Jetpack_BarrelRoll_right: [20, 30],
+ Jetpack_BarrelRoll_left: [40, 50],
+ Jetpack_changeLane_left: [60, 70],
+ Jetpack_changeLane_right: [80, 90],
+ Jetpack_forward_2: [100, 123],
+ Double_Headstart: [130, 172],
+ Triple_Headstart: [202, 242],
+ },
+ };
+ },
+ 477: function (t) {
+ t.exports = {
+ file: "model_avatar_movement.fbx",
+ texture: "jake_tex",
+ fps: 24,
+ clips: {
+ run: [-53, -6],
+ dodgeLeft: [200, 212],
+ dodgeRight: [230, 242],
+ jump: [87, 103],
+ hangtime: [106, 118],
+ landing: [120, 124],
+ roll: [151, 164],
+ death_bounce: [400, 416],
+ hold_magnet: [280, 281],
+ h_run: [514, 538, 1],
+ h_jump: [551, 553],
+ h_hangtime: [556, 568],
+ h_landing: [570, 578],
+ h_roll: [581, 594],
+ introRun: [-50, -21],
+ stumbleCornerLeft: [311, 330],
+ stumbleCornerRight: [291, 311],
+ stumble: [335, 355],
+ stumbleSideRight: [362, 372],
+ stumbleSideLeft: [382, 392],
+ death_upper: [420, 428],
+ death_lower: [440, 452],
+ death_movingTrain: [460, 495],
+ h_left: [610, 623],
+ h_right: [640, 653],
+ superRun: [740, 760],
+ h_Grind1: [670, 684],
+ h_Grind2: [700, 720],
+ h_skate_on: [770, 781],
+ h_Grind1_land: [661, 670],
+ h_Grind2_land: [691, 700],
+ h_jump2_kickflip_flip: [800, 820],
+ h_jump3_bs360grab: [830, 850],
+ h_jump4_360_flip: [866, 889],
+ h_Grind3: [923, 943],
+ h_Grind3_land: [904, 923],
+ run2: [960, 970],
+ run3: [1e3, 1010],
+ h_jump5_Impossible_flip: [1400, 1423],
+ h_jump6_nollie: [1430, 1457],
+ h_jump7_heelflip_flip: [1500, 1524],
+ h_jump8_pop_shuvit_flip: [1560, 1583],
+ h_jump9_fs360grab: [1600, 1628],
+ h_jump10_heel360_flip: [1650, 1674],
+ h_jump11_fs_salto: [1690, 1718],
+ jump_salto: [1300, 1324],
+ run4_long: [1070, 1180],
+ jump2: [60, 78],
+ hangtime2: [65, 78],
+ landing2: [78, 84],
+ jump3: [1720, 1738],
+ hangtime3: [1725, 1738],
+ landing3: [1739, 1744],
+ stumble_low: [1200, 1215],
+ IconJump: [63, 63.1],
+ IconRoll: [154, 154.1],
+ _run_06_old: [1, 11],
+ DoubleJump_Jump: [1750, 1754],
+ DoubleJump_Hangtime_01_star: [1756, 1778],
+ DoubleJump_Hangtime_02_BackFlip: [1780, 1802],
+ DoubleJump_Hangtime_03_360: [1805, 1831],
+ run_HighScore_main: [1950, 1989],
+ run_HighScore_hatadjust: [2005, 2044],
+ run_HighScore_xianHat: [2060, 2099],
+ run_HighScore_Yutani: [2110, 2149],
+ run_HighScore_Ninja: [2160, 2199],
+ run_HighScore_Tagbot: [2210, 2249],
+ run_HighScore_VeniceMain: [2260, 2299],
+ run_HighScore_HolidayMainandOutfit1: [2310, 2349],
+ run_HighScore_MexicoOutfit1: [2360, 2399],
+ },
+ };
+ },
+ 478: function (t) {
+ t.exports = {
+ file: "model_avatar_catch.fbx",
+ texture: "jake_tex",
+ fps: 25,
+ offset: 0,
+ clips: {
+ Avatar_Catch_Shoulder: [300, 400],
+ Avatar_Catch_Right_Pickup: [150, 248],
+ Avatar_Catch_Left_Pickup: [2, 100],
+ },
+ };
+ },
+ 479: function (t) {
+ t.exports = {
+ file: "model_avatar_powerup_pogostick.fbx",
+ texture: "jake_tex",
+ fps: 25,
+ offset: 0,
+ clips: {
+ pogostick_SpinMove: [1, 50],
+ pogostick_kicking: [60, 76],
+ pogostick_Hangtime_kick: [82, 102],
+ pogostick_ChangeLane_right: [120, 126],
+ pogostick_ChangeLane_left: [132, 138],
+ pogostick_Hangtime_flying: [150, 183],
+ pogostick_Hangtime_front_flip1: [200, 233],
+ },
+ };
+ },
+ 480: function (t) {
+ t.exports = {
+ file: "model_avatar_start.fbx",
+ texture: "jake_tex",
+ fps: 24,
+ clips: {
+ start_run: [7, 53],
+ },
+ };
+ },
+ 481: function (t) {
+ t.exports = {
+ file: "model_guard_movement.fbx",
+ texture: "enemies",
+ fps: 25,
+ offset: 51,
+ clips: {
+ Guard_run: [1, 13],
+ Guard_grap_after: [24, 48],
+ Guard_jump: [52, 75],
+ Guard_hangtime: [59, 65],
+ Guard_landing: [71, 77],
+ Guard_dodgeRight: [80, 93],
+ Guard_dodgeLeft: [100, 113],
+ Guard_whistle: [125, 149],
+ Guard_death_movingTrain: [173, 210],
+ Guard_playIntro: [-50, -21],
+ Guard_roll: [220, 228],
+ },
+ };
+ },
+ 482: function (t) {
+ t.exports = {
+ file: "model_guard_catch.fbx",
+ texture: "enemies",
+ fps: 25,
+ offset: 0,
+ clips: {
+ Guard_Catch_Shoulder: [300, 400],
+ Guard_Catch_Right_Pickup: [150, 248],
+ Guard_Catch_Left_Pickup: [2, 100],
+ },
+ };
+ },
+ 483: function (t) {
+ t.exports = {
+ file: "model_dog_movement.fbx",
+ texture: "enemies",
+ fps: 25,
+ offset: 50,
+ clips: {
+ Dog_run: [1, 14],
+ "Dog_Fast Run": [20, 40],
+ "Dog_Run offset": [-6, 6],
+ Dog_jump: [52, 75],
+ Dog_hangtime: [37, 46],
+ Dog_landing: [46, 51],
+ Dog_dodgeRight: [80, 93],
+ Dog_dodgeLeft: [100, 113],
+ Dog_whistle: [125, 149],
+ Dog_death_movingTrain: [173, 210],
+ Dog_playIntro: [-50, -21],
+ Dog_Bite_After: [220, 228],
+ },
+ };
+ },
+ 484: function (t) {
+ t.exports = {
+ file: "model_dog_catch.fbx",
+ texture: "enemies",
+ fps: 25,
+ offset: 0,
+ clips: {
+ Dog_Catch_Shoulder: [300, 400],
+ Dog_Catch_Right: [150, 248],
+ Dog_Catch_Left: [2, 100],
+ },
+ };
+ },
+ 487: function (t, e, i) {
+ "use strict";
+ i.r(e);
+ var c = i(0),
+ a = i(133),
+ r = i(21),
+ h = i(184),
+ d = i(14),
+ n = i(12),
+ l = i.n(n),
+ o = i(185),
+ s = i.n(o),
+ u = i(126),
+ p = i.n(u),
+ m = i(13),
+ f = i.n(m),
+ g = (function () {
+ function Platform() {}
+ return (
+ (Platform.getUrlParams = function () {
+ var t = location.search,
+ e = {},
+ i = t.slice(t.indexOf("?") + 1).split("&"),
+ n = Array.isArray(i),
+ o = 0;
+ for (i = n ? i : i[Symbol.iterator](); ; ) {
+ var s;
+ if (n) {
+ if (o >= i.length) break;
+ s = i[o++];
+ } else {
+ if ((o = i.next()).done) break;
+ s = o.value;
+ }
+ var a = s.split("="),
+ r = a[0],
+ h = a[1];
+ void 0 !== h && (("true" !== h && "false" !== h) || (h = "true" === h), (e[r] = "string" == typeof h && h.match(/^[-.0-9]+$/) ? parseFloat(h) : h));
+ }
+ return e;
+ }),
+ (Platform.getUrlParam = function (t, e) {
+ var i = this.getUrlParams();
+ return void 0 !== i[t] ? i[t] : e;
+ }),
+ Platform
+ );
+ })(),
+ B = new ((function () {
+ function Config() {
+ (this.fps = 60),
+ (this.frameSkip = 0),
+ (this.ticker = !1),
+ (this.smoothDelta = !0),
+ (this.deltaCap = 5),
+ (this.frameByFrame = 0),
+ (this.culling = !0),
+ (this.fixedPhysicsSteps = 0),
+ (this.vertp = ""),
+ (this.fragp = ""),
+ (this.maxViewportScale = 1.75),
+ (this.debug = !1),
+ (this.monitor = !1),
+ (this.blocks = !1),
+ (this.models = !0),
+ (this.routeSection = ""),
+ (this.timeScale = 1),
+ (this.forceTube = !1),
+ (this.optm = !1),
+ (this.god = !1),
+ (this.freejump = !1),
+ (this.shortcuts = !1),
+ (this.laneWidth = 20),
+ (this.blockSize = 90),
+ (this.visibleMaxDistance = 1e3),
+ (this.visibleMinDistance = -500),
+ (this.fog = !0),
+ (this.bend = !0),
+ (this.bendX = -65e-5),
+ (this.bendY = -3e-4),
+ (this.fillers = !0),
+ (this.ground = !0),
+ (this.speed = 0),
+ (this.speedProgr = 0.25),
+ (this.speedProgrInterval = 500),
+ (this.maxSpeed = 5),
+ (this.gravity = 0.055),
+ (this.cameraFov = 68),
+ (this.cameraPosX = 0),
+ (this.cameraPosY = 33.8),
+ (this.cameraPosZ = 33),
+ (this.cameraModX = 0.75),
+ (this.cameraRotX = -0.375),
+ (this.cameraRotY = 0),
+ (this.cameraRotZ = 0),
+ (this.mobile = !1),
+ (this.env = "191_new_york"),
+ (this.volume = 0.5),
+ (this.theme = !0),
+ (this.fastplay = !1),
+ (this.autoload = !1),
+ (this.workers = 1),
+ (this.section = "title"),
+ (this.tutorial = !1),
+ (this.intro = !0),
+ (this.loadAll = !0),
+ this.override(window.GAME_CONFIG),
+ this.override(g.getUrlParams());
+ }
+ return (
+ (Config.prototype.override = function (t) {
+ if (t) for (var e in this) void 0 !== t[e] && ((this[e] = t[e]), "debug" === e && ((this.monitor = this.debug), (this.shortcuts = this.debug)));
+ }),
+ Config
+ );
+ })())(),
+ y = i(3),
+ v = i.n(y),
+ _ = i(92),
+ b = i.n(_),
+ w = i(93),
+ k = i.n(w),
+ x = i(45),
+ C = i.n(x),
+ S = i(37),
+ z = i.n(S),
+ T = i(186),
+ P = i.n(T),
+ M = i(187),
+ E = i.n(M);
+ var O = (function (n) {
+ var t, e;
+
+ function PhongBendMaterial(t, e) {
+ void 0 === t && (t = {}), void 0 === e && (e = {});
+ var i = [e.fog ? "#define FOG" : "", e.rails ? "#define RAILS" : "", "#define BEND"];
+ return (t.uniforms = PhongBendMaterial.unformGroup()), n.call(this, t, P.a, E.a, i, e.rails ? "phong-rails" : "phong") || this;
+ }
+ return (
+ (e = n),
+ ((t = PhongBendMaterial).prototype = Object.create(e.prototype)),
+ ((t.prototype.constructor = t).__proto__ = e),
+ (PhongBendMaterial.unformGroup = function () {
+ return (
+ this._uniformGroup ||
+ (this._uniformGroup = new c.UniformGroup(
+ {
+ uTime: 0,
+ uBend: new Float32Array([0, 0]),
+ uFogDensity: 0.008,
+ uFogDistance: 450,
+ uFogColor: new Float32Array([0.388, 0.698, 1]),
+ },
+ !1
+ )),
+ this._uniformGroup.uniforms
+ );
+ }),
+ PhongBendMaterial
+ );
+ })(z.a);
+ var R = (function (i) {
+ var t, e;
+
+ function PhongBendRailsMaterial(t, e) {
+ return (
+ void 0 === t && (t = {}),
+ void 0 === e && (e = {}),
+ Object.assign(e, {
+ rails: !0,
+ }),
+ i.call(this, t, e) || this
+ );
+ }
+ return (e = i), ((t = PhongBendRailsMaterial).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e), PhongBendRailsMaterial;
+ })(O);
+ var I = (function (r) {
+ var t, e;
+
+ function RampGeometry(t, e, i) {
+ var n;
+ void 0 === t && (t = 1), void 0 === e && (e = 1), void 0 === i && (i = 1), (n = r.call(this) || this);
+ var o = new Float32Array([
+ -0.5,
+ -0.5,
+ 0.5,
+ 0.5,
+ -0.5,
+ 0.5,
+ 0.5,
+ 0.5,
+ 0.5,
+ -0.5,
+ 0.5,
+ 0.5,
+ -0.5,
+ -0.5,
+ -0.5,
+ -0.5,
+ 0.5,
+ -0.5,
+ 0.5,
+ 0.5,
+ -0.5,
+ 0.5,
+ -0.5,
+ -0.5,
+ -0.5,
+ 0.5,
+ -0.5,
+ -0.5,
+ -0.5,
+ 0.5,
+ 0.5,
+ -0.5,
+ 0.5,
+ 0.5,
+ 0.5,
+ -0.5,
+ -0.5,
+ -0.5,
+ -0.5,
+ 0.5,
+ -0.5,
+ -0.5,
+ 0.5,
+ -0.5,
+ 0.5,
+ -0.5,
+ -0.5,
+ 0.5,
+ 0.5,
+ -0.5,
+ -0.5,
+ 0.5,
+ 0.5,
+ -0.5,
+ 0.5,
+ 0.5,
+ 0.5,
+ 0.5,
+ -0.5,
+ 0.5,
+ -0.5,
+ -0.5,
+ -0.5,
+ -0.5,
+ -0.5,
+ 0.5,
+ -0.5,
+ 0.5,
+ 0.5,
+ -0.5,
+ 0.5,
+ -0.5,
+ ]),
+ s = new Float32Array([
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ ]),
+ a = new Uint16Array([0, 0, 0, 0, 0, 0, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 19, 0, 0, 0, 20, 21, 23, 0, 0, 0]);
+ return n.addAttribute("position", o, 3), n.addAttribute("normals", s, 3), n.addIndex(a), n;
+ }
+ return (e = r), ((t = RampGeometry).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e), RampGeometry;
+ })(c.Geometry),
+ L = (function () {
+ function Random() {}
+ return (
+ (Random.color = function () {
+ return Math.floor(16777215 * Math.random());
+ }),
+ (Random.range = function (t, e, i) {
+ void 0 === i && (i = !1);
+ var n = t + (e - t) * Math.random();
+ return i ? Math.floor(n) : n;
+ }),
+ (Random.pick = function () {
+ for (var t = arguments.length, e = new Array(t), i = 0; i < t; i++) e[i] = arguments[i];
+ return e[Math.floor(Math.random() * e.length)];
+ }),
+ (Random.item = function (t) {
+ if (Array.isArray(t)) return t[Math.floor(Math.random() * t.length)];
+ var e = Object.keys(t);
+ return t[e[Math.floor(Math.random() * e.length)]];
+ }),
+ Random
+ );
+ })(),
+ j = i(188),
+ F = i.n(j),
+ A = i(189),
+ D = i.n(A);
+ var G = (function (i) {
+ var t, e;
+
+ function ParticleMaterial(t, e) {
+ void 0 === t && (t = {}), void 0 === e && (e = {});
+ return (t.uniforms = {}), i.call(this, t, F.a, D.a, [], "particle") || this;
+ }
+ return (e = i), ((t = ParticleMaterial).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e), ParticleMaterial;
+ })(z.a),
+ N = O,
+ X = null,
+ Y = {
+ "environment.fbx": "environment_tex",
+ "environment_start.fbx": "environment_tex",
+ "environment_idle.fbx": "environment_tex",
+ "trains.fbx": "trains_tex",
+ "trains_start.fbx": "trains_tex",
+ "model_dog.fbx": "enemies",
+ "model_guard.fbx": "enemies",
+ "board_new_york.fbx": "board_new_york_tex",
+ "avatar_jake.fbx": "jake_tex",
+ "model_avatar-movement.fbx": "jake_tex",
+ "props.fbx": "props_tex",
+ "props_start.fbx": "props_tex",
+ },
+ H = (function () {
+ function Model() {}
+ return (
+ (Model.box = function (t, e, i) {
+ void 0 === e && (e = L.color()), void 0 === i && (i = 1);
+ var n = new c.State();
+ (n.blend = i < 1), (n.depthTest = !0);
+ var o = new b.a(t.width, t.height, t.depth, 1, 1, 64),
+ s = new N(
+ {
+ color: e,
+ opacity: i,
+ },
+ {
+ fog: B.fog,
+ }
+ );
+ return new v.a({
+ geometry: o,
+ material: s,
+ state: n,
+ });
+ }),
+ (Model.ramp = function (t, e, i) {
+ void 0 === e && (e = L.color()), void 0 === i && (i = 1);
+ var n = new c.State();
+ (n.blend = i < 1), (n.depthTest = !0);
+ var o = new I(1, 1, 1),
+ s = new N(
+ {
+ color: e,
+ opacity: i,
+ },
+ {
+ fog: B.fog,
+ }
+ );
+ return new v.a({
+ geometry: o,
+ material: s,
+ state: n,
+ });
+ }),
+ (Model.plane = function (t, e, i, n, o) {
+ void 0 === i && (i = 1);
+ var s = new c.State();
+ (s.blend = i < 1), (s.depthTest = !0), o && (s.blendMode = o);
+ var a = this.getTexture(n);
+ if (!a) throw new Error("Map not found for " + mapFile);
+ var r = new k.a(t, e, 4, 4),
+ h = new N(
+ {
+ map: a,
+ opacity: i,
+ },
+ {
+ fog: B.fog,
+ }
+ );
+ return new v.a({
+ geometry: r,
+ material: h,
+ state: s,
+ });
+ }),
+ (Model.particle = function (t, e, i, n, o) {
+ void 0 === i && (i = 1);
+ var s = new c.State();
+ (s.blend = !0), (s.depthTest = !1), o && (s.blendMode = o);
+ var a = this.getTexture(n);
+ if (!a) throw new Error("Map not found for " + mapFile);
+ var r = new k.a(t, e, 4, 4),
+ h = new G({
+ map: a,
+ opacity: i,
+ });
+ return new v.a({
+ geometry: r,
+ material: h,
+ state: s,
+ });
+ }),
+ (Model.particleMesh = function (t, e, i, n) {
+ void 0 === i && (i = 1), void 0 === n && (n = 0);
+ var o = new c.State();
+ (o.blend = !0), (o.depthTest = !1), (o.blendMode = n);
+ var s = this.getTexture(e);
+ if (!s) throw new Error("Map not found for " + mapFile);
+ var a = new G({
+ map: s,
+ opacity: i,
+ }),
+ r = this.getEntity(t).view3d.geometry;
+ return new v.a({
+ geometry: r,
+ material: a,
+ state: o,
+ });
+ }),
+ (Model.tint = function (t, e) {
+ t.view3d && t.view3d.material && (t.view3d.material.color = e);
+ for (var i = this.entityChildren(t), n = i.length; n--; ) {
+ var o = i[n];
+ this.tint(o, e);
+ }
+ }),
+ (Model.normalizeName = function (t) {
+ return t.replace("\0", " ");
+ }),
+ (Model.cloneEntity = function (t) {
+ if (!t) throw new Error("Invalid entity to clone");
+ var e = t.view3d.geometry,
+ i = t.view3d.material,
+ n = t.view3d.state;
+ return new v.a({
+ geometry: e,
+ material: i,
+ state: n,
+ });
+ }),
+ (Model.entityChildren = function (t) {
+ return (t.container && t.container.children ? t.container.children : []).slice(0);
+ }),
+ (Model.findFileName = function (t) {
+ var e = t.split("/");
+ for (var i in e) if (e[i].endsWith(".fbx")) return e[i];
+ return "";
+ }),
+ (Model.findScene = function (t) {
+ if (!t) throw new Error("Scene name is empty");
+ if (c.sceneCache[t]) return c.sceneCache[t];
+ for (var e in c.sceneCache) if (e.endsWith(t)) return c.sceneCache[e];
+ return null;
+ }),
+ (Model.getScene = function (t) {
+ var e = this.findScene(t);
+ if (!e) throw new Error("Scene not found: " + t);
+ return e;
+ }),
+ (Model.hasScene = function (t) {
+ for (var e in c.sceneCache) if (e.match(t)) return !0;
+ return !1;
+ }),
+ (Model.whichScene = function () {
+ for (var t = arguments.length, e = new Array(t), i = 0; i < t; i++) e[i] = arguments[i];
+ for (var n in e) if (this.findEntity(e[n])) return e[n];
+ return null;
+ }),
+ (Model.forEach = function (t, e) {
+ e(t);
+ for (var i = this.entityChildren(t), n = i.length; n--; ) this.forEach(i[n], e);
+ }),
+ (Model.applyTexture = function (t, e, i) {
+ if ((void 0 === i && (i = !0), t.view3d && t.view3d.material))
+ if (i) {
+ var n = !!t.__path.match("track"),
+ o = this.getTexture(e),
+ s = new N(
+ {
+ map: o,
+ },
+ {
+ fog: B.fog,
+ rails: n,
+ }
+ );
+ t.view3d.material = s;
+ } else t.view3d.material.map = this.getTexture(e);
+ for (var a = this.entityChildren(t), r = a.length; r--; ) this.applyTexture(a[r], e, i);
+ }),
+ (Model.getTexture = function (t) {
+ var e = c.utils.TextureCache[t];
+ if (!e) {
+ var i = c.utils.TextureCache;
+ for (var n in i)
+ if (n.match(t)) {
+ e = i[n];
+ break;
+ }
+ }
+ if (!e) throw new Error("Texture not found for " + t);
+ return "ocean" === t && (e.baseTexture.wrapMode = c.WRAP_MODES.REPEAT), e;
+ }),
+ (Model.entityMap = function (t, e, i, n) {
+ void 0 === t && (t = null), void 0 === e && (e = {}), void 0 === i && (i = ""), void 0 === n && (n = 4), t && t.pixiTree && (t = t.pixiTree);
+ var o = t ? this.entityChildren(t) : c.sceneCache,
+ s = o === c.sceneCache;
+ for (var a in ((n -= 1), o)) {
+ var r = o[a].pixiTree || o[a];
+ if (s) {
+ var h = a.match(/\?v=/) ? a.replace(/(\?v\=.+)/, "") : a;
+ (o[h] = o[a]), (a = h);
+ }
+ var d = this.normalizeName(t && r.__name ? r.__name : a),
+ l = i + "/" + d;
+ (r.__path = l), (r.__file = this.findFileName(l)), (r.__name = d), (r.__scene = r.__file ? this.findScene(r.__file) : null), (e[l] = r), n && this.entityMap(r, e, l, n);
+ }
+ return e;
+ }),
+ (Model.cachedEntityMap = function () {
+ return X || (X = this.refreshCache()), X;
+ }),
+ (Model.refreshCache = function () {
+ X = this.entityMap(null, {}, "", 5);
+ }),
+ (Model.findEntity = function (t, e, i) {
+ if ((void 0 === i && (i = 4), !t)) throw new Error("A path must be provided");
+ var n = e ? this.entityMap(e, {}, "", i) : this.cachedEntityMap();
+ if (n[t]) return n[t];
+ for (var o in n) if (o.endsWith(t) && !o.match("_old")) return n[o];
+ return null;
+ }),
+ (Model.getEntity = function (t, e) {
+ if ((void 0 === e && (e = ""), !t)) throw new Error("A path must be provided");
+ var i = this.findEntity(t);
+ if (!i) throw new Error("Entity not found: " + t);
+ if (e) this.applyTexture(i, e);
+ else {
+ var n = Y[i.__file];
+ if (!n) throw new Error("Texture not found for entity: " + i.name + " file: " + i.__file);
+ n && this.applyTexture(i, n);
+ }
+ return i;
+ }),
+ (Model.getEntityClone = function (t, e, i, n) {
+ if ((void 0 === e && (e = ""), void 0 === i && (i = !0), void 0 === n && (n = null), !i)) {
+ var o = n || C.a,
+ s = "string" == typeof t ? this.getEntity(t, e) : t,
+ a = s.view3d.geometry,
+ r = new o({
+ map: s.view3d.material.map,
+ }),
+ h = s.view3d.state;
+ return new v.a({
+ geometry: a,
+ material: r,
+ state: h,
+ });
+ }
+ var d = this.getEntity(t, e);
+ if (!d) throw new Error("Entity not found by name: " + t);
+ return B.culling || (d.view3d.state.culling = !1), this.cloneEntity(d);
+ }),
+ (Model.getEntityCloneBlend = function (t, e, i, n) {
+ void 0 === e && (e = ""), void 0 === i && (i = 1), void 0 === n && (n = 0);
+ var o = this.getEntity(t, e),
+ s = o.view3d.geometry,
+ a = o.view3d.material;
+ a.opacity = i;
+ var r = o.view3d.state;
+ return (
+ (r.blend = i < 1),
+ (r.depthTest = !0),
+ n && (r.blendMode = n),
+ new v.a({
+ geometry: s,
+ material: a,
+ state: r,
+ })
+ );
+ }),
+ (Model.getEntityCloneColor = function (t, e, i) {
+ void 0 === i && (i = !0);
+ var n = i ? N : C.a,
+ o = this.getEntity(t);
+ if (!o) throw new Error("Entity not found: " + t);
+ var s = o.view3d.geometry,
+ a = new n(
+ {
+ color: e,
+ },
+ {
+ fog: B.fog,
+ }
+ ),
+ r = o.view3d.state;
+ return new v.a({
+ geometry: s,
+ material: a,
+ state: r,
+ });
+ }),
+ (Model.getEntityCloneOpaque = function (t, e, i) {
+ void 0 === e && (e = ""), void 0 === i && (i = !0);
+ var n = i ? N : C.a,
+ o = "string" == typeof t ? this.getEntity(t) : t;
+ e || (e = Y[o.__file]);
+ var s = this.getTexture(e);
+ if (!o) throw new Error("Entity not found: " + t);
+ var a = o.view3d.geometry,
+ r = new n(
+ {
+ map: s,
+ },
+ {
+ fog: B.fog,
+ }
+ ),
+ h = o.view3d.state;
+ return new v.a({
+ geometry: a,
+ material: r,
+ state: h,
+ });
+ }),
+ Model
+ );
+ })(),
+ U = i(4),
+ V = (function () {
+ function Math2() {}
+ return (
+ (Math2.oldLerp = function (t, e, i, n, o) {
+ return void 0 === n && (n = 0), void 0 === o && (o = 0), n && e - n <= t && t <= e + n ? e : t * (1 - i) + e * i;
+ }),
+ (Math2.lerp = function (t, e, i, n) {
+ return void 0 === n && (n = 0), n && e - n <= t && t <= e + n ? e : t + (e - t) * (i < 0 ? 0 : 1 < i ? 1 : i);
+ }),
+ (Math2.lerpCap = function (t, e, i, n, o) {
+ if ((void 0 === n && (n = 0), void 0 === o && (o = 0), n && e - n <= t && t <= e + n)) return e;
+ var s = (i < 0 ? 0 : 1 < i ? 1 : i) * (e - t);
+ return o && (s = this.clamp(s, -o, o)), t + s;
+ }),
+ (Math2.clamp = function (t, e, i) {
+ return void 0 === e && (e = 0), void 0 === i && (i = 1), t < e ? e : i < t ? i : t;
+ }),
+ (Math2.sign = function (t, e) {
+ return void 0 === e && (e = !1), e ? (t < 0 ? -1 : 0 < t ? 1 : 0) : t < 0 ? -1 : 1;
+ }),
+ (Math2.ease = function (t, e, i, n) {
+ var o = -(t - e) * i;
+ return n ? this.clamp(o, -n, n) : o;
+ }),
+ (Math2.lerpVec3 = function (t, e, i, n, o) {
+ return void 0 === o && (o = 0), (t.x = this.lerp(e.x, i.x, n, o)), (t.y = this.lerp(e.y, i.y, n, o)), (t.z = this.lerp(e.z, i.z, n, o)), t;
+ }),
+ (Math2.smoothStep = function (t, e, i) {
+ return (i = this.clamp((i - t) / (e - t), 0, 1)) * i * (3 - 2 * i);
+ }),
+ (Math2.smoothDamp = function (t, e, i, n, o, s) {
+ var a = 2 / (n = Math.max(1e-4, n)),
+ r = a * s,
+ h = 1 / (1 + r + 0.479999989271164 * r * r + 0.234999999403954 * r * r * r),
+ d = t - e,
+ l = e,
+ c = o * n,
+ u = this.clamp(d, -c, c),
+ p = (i + a * u) * s;
+ i = (i - a * p) * h;
+ var m = (e = t - u) + (u + p) * h;
+ return 0 < l - t == l < m && (i = ((m = l) - l) / s), m;
+ }),
+ Math2
+ );
+ })();
+
+ function _defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ (V.PI_HALF = 0.5 * Math.PI), (V.PI_QUARTER = 0.25 * Math.PI), (V.PI_DOUBLE = 2 * Math.PI), (V.DEG_TO_RAD = 0.0174533);
+ var q = (function () {
+ function Vector3(t, e, i) {
+ void 0 === t && (t = 0), void 0 === e && (e = 0), void 0 === i && (i = 0), (this.vec = U.vec3.create()), (this.x = t), (this.y = e), (this.z = i);
+ }
+ var t,
+ e,
+ i,
+ n = Vector3.prototype;
+ return (
+ (n.reset = function (t, e, i) {
+ void 0 === t && (t = 0), void 0 === e && (e = 0), void 0 === i && (i = 0), (this.vec[0] = t), (this.vec[1] = e), (this.vec[2] = i);
+ }),
+ (n.copy = function (t) {
+ (this.vec[0] = t.vec[0]), (this.vec[1] = t.vec[1]), (this.vec[2] = t.vec[2]);
+ }),
+ (n.clone = function () {
+ return new Vector3(this.vec[0], this.vec[1], this.vec[2]);
+ }),
+ (n.distance = function (t) {
+ return U.vec3.distance(this.vec, t.vec);
+ }),
+ (n.magnitude = function () {
+ return U.vec3.length(this.vec);
+ }),
+ (n.add = function (t) {
+ U.vec3.add(this.vec, this.vec, t.vec);
+ }),
+ (n.subtract = function (t) {
+ U.vec3.add(this.vec, this.vec, t.vec);
+ }),
+ (n.lerp = function (t, e, i, n) {
+ void 0 === i && (i = 0), void 0 === n && (n = 0), -1 !== e ? V.lerpVec3(this, this, t, e, i, n) : this.copy(t);
+ }),
+ (t = Vector3),
+ (e = [
+ {
+ key: "x",
+ get: function () {
+ return this.vec[0];
+ },
+ set: function (t) {
+ this.vec[0] = t;
+ },
+ },
+ {
+ key: "y",
+ get: function () {
+ return this.vec[1];
+ },
+ set: function (t) {
+ this.vec[1] = t;
+ },
+ },
+ {
+ key: "z",
+ get: function () {
+ return this.vec[2];
+ },
+ set: function (t) {
+ this.vec[2] = t;
+ },
+ },
+ ]) && _defineProperties(t.prototype, e),
+ i && _defineProperties(t, i),
+ Vector3
+ );
+ })();
+
+ function CameraSystem_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+
+ function CameraSystem_createClass(t, e, i) {
+ return e && CameraSystem_defineProperties(t.prototype, e), i && CameraSystem_defineProperties(t, i), t;
+ }
+
+ function _assertThisInitialized(t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ }
+
+ function CameraSystem_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ (q.UP = new q(0, 1, 0)), (q.RIGHT = new q(1, 0, 0)), (q.FORWARD = new q(0, 0, -1)), (q.DOWN = new q(0, -1, 0)), (q.LEFT = new q(-1, 0, 0)), (q.BACK = new q(0, 0, 1)), (q.ZERO = new q(0, 0, 0)), (q.ONE = new q(1, 1, 1));
+ var W = (function (n) {
+ function CameraSystem(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).game = t.game),
+ i.game.onIdle.add(_assertThisInitialized(i)),
+ i.game.onRun.add(_assertThisInitialized(i)),
+ i.game.onEnterTunnel.add(_assertThisInitialized(i)),
+ i.game.onExitTunnel.add(_assertThisInitialized(i)),
+ i
+ );
+ }
+ CameraSystem_inheritsLoose(CameraSystem, n);
+ var t = CameraSystem.prototype;
+ return (
+ (t.idle = function () {
+ this.rig && this.rig.reset(), (this.running = !1), (this._shakePower = 0), (this.tunnel = !1);
+ }),
+ (t.run = function () {
+ this.rig && this.rig.resetLevel("_tunnel"), (this.running = !0), (this.tunnel = !1);
+ }),
+ (t.enterTunnel = function () {
+ this.tunnel = !0;
+ }),
+ (t.exitTunnel = function () {
+ this.tunnel = !1;
+ }),
+ (t.setup = function () {
+ this.rig ||
+ ((this.rig = new Z(this.game.view3d.camera)),
+ this.game.addChild(this.rig),
+ (this.game.view3d.camera.x = 0),
+ (this.game.view3d.camera.y = 0),
+ (this.game.view3d.camera.z = 0),
+ (this.game.view3d.camera.rx = 0),
+ (this.game.view3d.camera.ry = 0),
+ (this.game.view3d.camera.rz = 0),
+ (this.game.view3d.camera.camera.near = 3),
+ (this.game.view3d.camera.camera.far = 1e3));
+ }),
+ (t.update = function (t) {
+ this.rig || this.setup(), this.running ? this.updateRunning(t) : this.updateIdle(t);
+ }),
+ (t.updateIdle = function (t) {
+ this._controlled ||
+ ((this.rig.idleX = -21.94232),
+ (this.rig.idleY = -13.06444),
+ (this.rig.idleZ = 11.95625),
+ (this.rig.idleRotX = 16.37991 * V.DEG_TO_RAD),
+ (this.rig.idleRotY = 59.09998 * V.DEG_TO_RAD),
+ (this.rig.mainX = 0),
+ (this.rig.mainY = B.cameraPosY),
+ (this.rig.mainZ = B.cameraPosZ),
+ (this.rig.mainRotX = B.cameraRotX),
+ (this.rig.mainRotY = 0),
+ (this.rig.fov = 71.99513));
+ }),
+ (t.updateRunning = function (t) {
+ if ((this._animating && this.updateAnimation(t), !this._controlled)) {
+ (this.rig.idleX = 0), (this.rig.idleY = 0), (this.rig.idleZ = 0), (this.rig.idleRotX = 0), (this.rig.idleRotY = 0);
+ var e = this.game.stats.x * B.cameraModX;
+ this.rig.mainX = V.lerp(this.rig.mainX, e, 0.3 * t);
+ var i = this.game.hero.player.cameraY + B.cameraPosY;
+ B.cameraRotX;
+ (this.rig.mainY = V.lerp(this.rig.mainY, i, 0.3 * t)),
+ (this.rig.mainZ = this.game.stats.z + B.cameraPosZ),
+ (this.rig.mainRotX = V.lerp(this.rig.mainRotX, B.cameraRotX, 0.1 * t)),
+ (this.rig.mainRotY = 0),
+ (this.rig.fov = B.cameraFov);
+ }
+ this.updateTunnel(t), this.updateShake(t);
+ }),
+ (t.updateTunnel = function (t) {
+ var e = this.tunnel,
+ i = this.rig._tunnel;
+ if (e || 0 !== i.rx || 0 !== this.rig.y) {
+ var n = -4.621953 * V.DEG_TO_RAD,
+ o = e ? B.cameraPosY - 18.30177 : 0,
+ s = e ? B.cameraRotX - n : 0,
+ a = 0.25 * this.game.stats.speed + 0.5;
+ (i.y = V.smoothDamp(i.y, -o, 0, 0.2, 1.2 * a, t)), (i.rx = V.smoothDamp(i.rx, -s, 0, 0.05, 0.1 * a, t));
+ }
+ }),
+ (t.updateShake = function (t) {
+ var e = this.rig;
+ (this._shakePower || 0 !== e.x || 0 !== this.rig.y) &&
+ ((e.y = L.range(-this._shakePower, this._shakePower)), (e.x = L.range(-this._shakePower, this._shakePower)), (this._shakePower -= 0.5 * t), this._shakePower < 0 && (this._shakePower = 0));
+ }),
+ (t.takeControl = function () {
+ return (this._controlled = !0), this.rig;
+ }),
+ (t.releaseControl = function () {
+ this._controlled = !1;
+ }),
+ (t.shake = function (t) {
+ this._shakePower = t;
+ }),
+ (t.animate = function (t, e, i, n) {
+ for (var o in ((this._controlled = !0), (this._animating = !0), this._animStart || (this._animStart = {}), this._animEnd || (this._animEnd = {}), (this._animCurve = i), (this._animTime = e), t))
+ (this._animStart[o] = this.rig[o]), (this._animEnd[o] = t[o]);
+ }),
+ (t.updateAnimation = function (t) {}),
+ (t.animateEnd = function () {
+ (this._controlled = !1), (this._animating = !1);
+ }),
+ (t.rigProps = function (t) {
+ return Object.assign(
+ {
+ idleX: this.rig.idleX,
+ idleY: this.rig.idleY,
+ idleZ: this.rig.idleZ,
+ idleRotX: this.rig.idleRotX,
+ idleRotY: this.rig.idleRotY,
+ mainX: this.rig.mainX,
+ mainY: this.rig.mainY,
+ mainZ: this.rig.mainZ,
+ mainRotX: this.rig.mainRotX,
+ mainRotY: this.rig.mainRotY,
+ },
+ t
+ );
+ }),
+ CameraSystem_createClass(CameraSystem, [
+ {
+ key: "profile",
+ get: function () {
+ return (
+ this._profile || (this._profile = {}),
+ this.rig &&
+ ((this._profile.idleX = this.rig.idleX),
+ (this._profile.idleY = this.rig.idleY),
+ (this._profile.idleZ = this.rig.idleZ),
+ (this._profile.idleRotX = this.rig.idleRotX),
+ (this._profile.idleRotY = this.rig.idleRotY),
+ (this._profile.mainX = this.rig.mainX),
+ (this._profile.mainY = this.rig.mainY),
+ (this._profile.mainZ = this.rig.mainZ),
+ (this._profile.mainRotX = this.rig.mainRotX),
+ (this._profile.mainRotY = this.rig.mainRotY),
+ (this._profile.fov = this.game.view3d.camera.camera.fov),
+ (this._profile.near = this.game.view3d.camera.camera.near),
+ (this._profile.far = this.game.view3d.camera.camera.far)),
+ this._profile
+ );
+ },
+ },
+ ]),
+ CameraSystem
+ );
+ })(f.a),
+ Z = (function (s) {
+ function CameraRig(t) {
+ var e;
+ void 0 === t && (t = null), ((e = s.call(this) || this).camera = t), (e.levels = ["_idle", "_idleRotY", "_idleRotX", "_main", "_mainRotY", "_mainRotX", "_tunnel"]);
+ var i = _assertThisInitialized(e);
+ for (var n in e.levels) {
+ var o = new v.a();
+ (e[e.levels[n]] = o), i.addChild(o), (i = o), t && o.addChild(t);
+ }
+ return e;
+ }
+ CameraSystem_inheritsLoose(CameraRig, s);
+ var t = CameraRig.prototype;
+ return (
+ (t.reset = function () {
+ for (var t in this.levels) this.resetLevel(this.levels[t]);
+ }),
+ (t.resetLevel = function (t) {
+ var e = this[t];
+ (e.x = 0), (e.y = 0), (e.z = 0), (e.rx = 0), (e.ry = 0);
+ }),
+ (t.resetIdle = function () {
+ this.resetLevel("_idle");
+ }),
+ CameraSystem_createClass(CameraRig, [
+ {
+ key: "fov",
+ get: function () {
+ return this.camera.camera.fov;
+ },
+ set: function (t) {
+ this.camera.camera.fov = t;
+ },
+ },
+ {
+ key: "idleX",
+ get: function () {
+ return this._idle.x;
+ },
+ set: function (t) {
+ this._idle.x = t;
+ },
+ },
+ {
+ key: "idleY",
+ get: function () {
+ return this._idle.y;
+ },
+ set: function (t) {
+ this._idle.y = t;
+ },
+ },
+ {
+ key: "idleZ",
+ get: function () {
+ return this._idle.z;
+ },
+ set: function (t) {
+ this._idle.z = t;
+ },
+ },
+ {
+ key: "idleRotX",
+ get: function () {
+ return this._idleRotX.rx;
+ },
+ set: function (t) {
+ this._idleRotX.rx = t;
+ },
+ },
+ {
+ key: "idleRotY",
+ get: function () {
+ return this._idleRotY.ry;
+ },
+ set: function (t) {
+ this._idleRotY.ry = t;
+ },
+ },
+ {
+ key: "mainX",
+ get: function () {
+ return this._main.x;
+ },
+ set: function (t) {
+ this._main.x = t;
+ },
+ },
+ {
+ key: "mainY",
+ get: function () {
+ return this._main.y;
+ },
+ set: function (t) {
+ this._main.y = t;
+ },
+ },
+ {
+ key: "mainZ",
+ get: function () {
+ return this._main.z;
+ },
+ set: function (t) {
+ this._main.z = t;
+ },
+ },
+ {
+ key: "mainRotX",
+ get: function () {
+ return this._mainRotX.rx;
+ },
+ set: function (t) {
+ this._mainRotX.rx = t;
+ },
+ },
+ {
+ key: "mainRotY",
+ get: function () {
+ return this._mainRotY.ry;
+ },
+ set: function (t) {
+ this._mainRotY.ry = t;
+ },
+ },
+ ]),
+ CameraRig
+ );
+ })(v.a);
+ var K = i(5),
+ J = i.n(K);
+
+ function Box_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var Q = (function () {
+ function Box(t, e, i) {
+ void 0 === t && (t = 1), void 0 === e && (e = 1), void 0 === i && (i = 1), (this.size = new q(t, e, i)), (this.center = new q(0, 0, 0));
+ }
+ var t,
+ e,
+ i,
+ n = Box.prototype;
+ return (
+ (n.copy = function (t) {
+ this.size.copy(t.size), this.center.copy(t.center);
+ }),
+ (n.resize = function (t, e, i) {
+ void 0 === t && (t = 1), void 0 === e && (e = 1), void 0 === i && (i = 1), (this.size.x = t), (this.size.y = e), (this.size.z = i);
+ }),
+ (n.reposition = function (t, e, i) {
+ void 0 === t && (t = 1), void 0 === e && (e = 1), void 0 === i && (i = 1), (this.center.x = t), (this.center.y = e), (this.center.z = i);
+ }),
+ (n.hitTest = function (t, e) {
+ void 0 === e && (e = null);
+ var i = this.left <= t.right && this.right >= t.left,
+ n = this.bottom <= t.top && this.top >= t.bottom,
+ o = this.front <= t.back && this.back >= t.front;
+ if (!(i && n && o)) return null;
+ var s = e;
+ s || (this._intersection || (this._intersection = new Box()), (s = this._intersection));
+ var a = Math.max(this.left, t.left),
+ r = Math.min(this.right, t.right),
+ h = Math.max(this.bottom, t.bottom),
+ d = Math.min(this.top, t.top),
+ l = Math.max(this.front, t.front),
+ c = Math.min(this.back, t.back);
+ return (s.size.x = r - a), (s.size.y = d - h), (s.size.z = c - l), (s.center.x = a + 0.5 * s.size.x), (s.center.y = h + 0.5 * s.size.y), (s.center.z = c - 0.5 * s.size.z), s;
+ }),
+ (t = Box),
+ (e = [
+ {
+ key: "x",
+ get: function () {
+ return this.center.x;
+ },
+ set: function (t) {
+ this.center.x = t;
+ },
+ },
+ {
+ key: "y",
+ get: function () {
+ return this.center.y;
+ },
+ set: function (t) {
+ this.center.y = t;
+ },
+ },
+ {
+ key: "z",
+ get: function () {
+ return this.center.z;
+ },
+ set: function (t) {
+ this.center.z = t;
+ },
+ },
+ {
+ key: "left",
+ get: function () {
+ return this.center.x - 0.5 * this.size.x;
+ },
+ set: function (t) {
+ this.center.x = t + 0.5 * this.size.x;
+ },
+ },
+ {
+ key: "right",
+ get: function () {
+ return this.center.x + 0.5 * this.size.x;
+ },
+ set: function (t) {
+ this.center.x = t - 0.5 * this.size.x;
+ },
+ },
+ {
+ key: "top",
+ get: function () {
+ return this.center.y + 0.5 * this.size.y;
+ },
+ set: function (t) {
+ this.center.y = t - 0.5 * this.size.y;
+ },
+ },
+ {
+ key: "bottom",
+ get: function () {
+ return this.center.y - 0.5 * this.size.y;
+ },
+ set: function (t) {
+ this.center.y = t + 0.5 * this.size.y;
+ },
+ },
+ {
+ key: "front",
+ get: function () {
+ return this.center.z - 0.5 * this.size.z;
+ },
+ set: function (t) {
+ this.center.z = t + 0.5 * this.size.z;
+ },
+ },
+ {
+ key: "back",
+ get: function () {
+ return 0.5 * this.size.z + this.center.z;
+ },
+ set: function (t) {
+ this.center.z = t - 0.5 * this.size.z;
+ },
+ },
+ {
+ key: "width",
+ get: function () {
+ return this.size.x;
+ },
+ set: function (t) {
+ this.size.x = t;
+ },
+ },
+ {
+ key: "height",
+ get: function () {
+ return this.size.y;
+ },
+ set: function (t) {
+ this.size.y = t;
+ },
+ },
+ {
+ key: "depth",
+ get: function () {
+ return this.size.z;
+ },
+ set: function (t) {
+ this.size.z = t;
+ },
+ },
+ ]) && Box_defineProperties(t.prototype, e),
+ i && Box_defineProperties(t, i),
+ Box
+ );
+ })(),
+ $ = (function () {
+ function Collision() {
+ (this.act = null), (this.pas = null), (this.hit = new Q()), (this.flags = Collision.NONE);
+ }
+ return (
+ (Collision.prototype.reset = function () {
+ (this.act = null), (this.pas = null), (this.flags = Collision.NONE);
+ }),
+ Collision
+ );
+ })();
+ ($.NONE = 0), ($.LEFT = 4), ($.TOP = 8), ($.RIGHT = 16), ($.BOTTOM = 32), ($.FRONT = 64), ($.BACK = 128), ($.INSIDE = 256), ($.SLOPE = 512);
+ var tt = i(8),
+ et = i.n(tt);
+
+ function Body_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var it = (function (n) {
+ var t, e;
+
+ function Body(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).trigger = e.trigger || !1),
+ (i.ghost = e.ghost || !1),
+ (i.deco = e.deco || !1),
+ (i.movable = e.movable || !1),
+ (i.box = new Q(1, 1, 1)),
+ (i.origin = new Q(1, 1, 1)),
+ (i.velocity = new q()),
+ (i.sensor = e.sensor ? new Q(0.2, 100, 1) : null),
+ (i.ground = 0),
+ (i.groundBefore = 0),
+ (i.groundChangeTolerance = 0),
+ (i.colliding = []),
+ (i.triggering = []),
+ B.blocks && !e.noView && i.drawView(),
+ (i.onCollisionEnter = new et.a("onCollisionEnter", 1)),
+ (i.onCollisionExit = new et.a("onCollisionExit", 1)),
+ (i.onTriggerEnter = new et.a("onTriggerEnter", 1)),
+ (i.onTriggerExit = new et.a("onTriggerExit", 1)),
+ (t.z = 9999),
+ i
+ );
+ }
+ (e = n), ((t = Body).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ o,
+ s,
+ a = Body.prototype;
+ return (
+ (a.reset = function () {
+ (this.ground = 0), (this.colliding = []), (this.triggering = []), this.origin.copy(this.box), this.velocity.reset(), this.resetGroundChangeTolerance();
+ }),
+ (a.drawView = function () {
+ this.view ||
+ (this.entity.ramp ? (this.view = H.ramp(this.box, this.data.boxColor, 0.75)) : (this.view = H.box(this.box, this.data.boxColor, 0.75)),
+ this.entity.addChild(this.view),
+ this.sensor && ((this.sensorView = H.box(this.sensor, this.data.boxColor, 0.5)), (this.sensorView.y = -50), this.entity.addChild(this.sensorView)));
+ }),
+ (a.render = function () {
+ (this.entity.transform.position.x = this.box.center.x),
+ (this.entity.transform.position.y = this.box.center.y),
+ (this.entity.transform.position.z = this.box.center.z),
+ this.view && ((this.view.scale.x = this.box.size.x), (this.view.scale.y = this.box.size.y), (this.view.scale.z = this.box.size.z)),
+ !B.models && this.entity.model && (this.entity.model.active = !1);
+ }),
+ (a.matchEntityPosition = function () {
+ (this.entity.x = this.box.center.x), (this.entity.y = this.box.center.y), (this.entity.z = this.box.center.z);
+ }),
+ (a.move = function (t) {
+ (this.origin.center.x = this.box.center.x),
+ (this.origin.center.y = this.box.center.y),
+ (this.origin.center.z = this.box.center.z),
+ (this.origin.size.x = this.box.size.x),
+ (this.origin.size.y = this.box.size.y),
+ (this.origin.size.z = this.box.size.z),
+ (this.box.center.z += this.velocity.z * t),
+ (this.box.center.x += this.velocity.x * t),
+ (this.box.center.y += this.velocity.y * t),
+ this.box.bottom <= this.ground && !this.ghost && ((this.box.bottom = this.ground), (this.velocity.y = 0)),
+ this.sensor && ((this.sensor.x = this.box.x), (this.sensor.y = this.box.y - 50), (this.sensor.z = this.box.z)),
+ this.groundChangeTolerance && ((this.groundChangeTolerance -= t), this.groundChangeTolerance < 0 && (this.groundChangeTolerance = 0));
+ }),
+ (a.onCollision = function (t) {
+ t.flags & $.RIGHT && ((this.velocity.x = 0), (this.lane -= 1)),
+ t.flags & $.LEFT && ((this.velocity.x = 0), (this.lane += 1)),
+ t.flags & $.FRONT && (this.velocity.z = 0),
+ t.flags & $.BOTTOM && (this.velocity.y = 0),
+ t.flags & $.TOP && (this.velocity.y = 0);
+ }),
+ (a.triggerEnter = function (t, e) {
+ this.onTriggerEnter.dispatch(t);
+ }),
+ (a.triggerExit = function (t, e) {
+ this.onTriggerExit.dispatch(t);
+ }),
+ (a.collisionEnter = function (t, e) {
+ (e.flags & $.LEFT || e.flags & $.RIGHT) && (this.velocity.x = 0),
+ (e.flags & $.TOP || e.flags & $.BOTTOM) && (this.velocity.y = 0),
+ (e.flags & $.FRONT || e.flags & $.BACK) && (this.velocity.z = 0),
+ this.onCollisionEnter.dispatch(e);
+ }),
+ (a.collisionExit = function (t, e) {
+ this.onCollisionExit.dispatch(e);
+ }),
+ (a.isColliding = function (t) {
+ return 0 <= this.colliding.indexOf(t);
+ }),
+ (a.isTrigering = function (t) {
+ return 0 <= this.colliding.indexOf(t);
+ }),
+ (a.resetGroundChangeTolerance = function () {
+ this.groundChangeTolerance = 0;
+ }),
+ (i = Body),
+ (o = [
+ {
+ key: "ascending",
+ get: function () {
+ return this.origin.y < this.box.y;
+ },
+ },
+ {
+ key: "descending",
+ get: function () {
+ return this.origin.y > this.box.y;
+ },
+ },
+ {
+ key: "hangtime",
+ get: function () {
+ var t = -0.2 < this.velocity.y && this.velocity.y < 0.2;
+ return !this.landed && t;
+ },
+ },
+ {
+ key: "airborne",
+ get: function () {
+ return !this.landed;
+ },
+ },
+ {
+ key: "stable",
+ get: function () {
+ return this.origin.y === this.box.y;
+ },
+ },
+ {
+ key: "landed",
+ get: function () {
+ return this.bottom <= this.ground + 1 && !this.ghost;
+ },
+ },
+ {
+ key: "moving",
+ get: function () {
+ return 0 !== this.velocity.x || 0 !== this.velocity.y || 0 !== this.velocity.z;
+ },
+ },
+ {
+ key: "dodging",
+ get: function () {
+ var t = this.velocity.x;
+ return t < -0.25 ? -1 : 0.25 < t ? 1 : 0;
+ },
+ },
+ {
+ key: "canJump",
+ get: function () {
+ return !!this.groundChangeTolerance || this.landed;
+ },
+ },
+ {
+ key: "x",
+ get: function () {
+ return this.box.center.x;
+ },
+ set: function (t) {
+ this.box.center.x = t;
+ },
+ },
+ {
+ key: "y",
+ get: function () {
+ return this.box.center.y;
+ },
+ set: function (t) {
+ this.box.center.y = t;
+ },
+ },
+ {
+ key: "z",
+ get: function () {
+ return this.box.center.z;
+ },
+ set: function (t) {
+ this.box.center.z = t;
+ },
+ },
+ {
+ key: "left",
+ get: function () {
+ return this.box.left;
+ },
+ set: function (t) {
+ this.box.left = t;
+ },
+ },
+ {
+ key: "right",
+ get: function () {
+ return this.box.right;
+ },
+ set: function (t) {
+ this.box.right = t;
+ },
+ },
+ {
+ key: "top",
+ get: function () {
+ return this.box.top;
+ },
+ set: function (t) {
+ this.box.top = t;
+ },
+ },
+ {
+ key: "bottom",
+ get: function () {
+ return this.box.bottom;
+ },
+ set: function (t) {
+ this.box.bottom = t;
+ },
+ },
+ {
+ key: "front",
+ get: function () {
+ return this.box.front;
+ },
+ set: function (t) {
+ this.box.front = t;
+ },
+ },
+ {
+ key: "back",
+ get: function () {
+ return this.box.back;
+ },
+ set: function (t) {
+ this.box.back = t;
+ },
+ },
+ {
+ key: "width",
+ get: function () {
+ return this.box.size.x;
+ },
+ set: function (t) {
+ this.box.size.x = t;
+ },
+ },
+ {
+ key: "height",
+ get: function () {
+ return this.box.size.y;
+ },
+ set: function (t) {
+ this.box.size.y = t;
+ },
+ },
+ {
+ key: "depth",
+ get: function () {
+ return this.box.size.z;
+ },
+ set: function (t) {
+ this.box.size.z = t;
+ },
+ },
+ {
+ key: "center",
+ get: function () {
+ return this.box.center;
+ },
+ },
+ {
+ key: "size",
+ get: function () {
+ return this.box.size;
+ },
+ },
+ {
+ key: "phx",
+ get: function () {
+ return this.box.center.x;
+ },
+ set: function (t) {
+ var e = t - this.box.center.x;
+ this.velocity.x = e;
+ },
+ },
+ {
+ key: "phy",
+ get: function () {
+ return this.center.y;
+ },
+ set: function (t) {
+ var e = t - this.box.center.y;
+ this.velocity.y = e;
+ },
+ },
+ {
+ key: "phz",
+ get: function () {
+ return this.center.z;
+ },
+ set: function (t) {
+ var e = t - this.box.center.z;
+ this.velocity.z = e;
+ },
+ },
+ ]) && Body_defineProperties(i.prototype, o),
+ s && Body_defineProperties(i, s),
+ Body
+ );
+ })(J.a);
+ var nt = {
+ speed: 0,
+ },
+ ot = (function (n) {
+ var t, e;
+
+ function Movable(t, e) {
+ var i;
+ return void 0 === e && (e = {}), (e = Object.assign({}, nt, e)), ((i = n.call(this, t, e) || this).speed = e.speed), (i.lastDest = null), i;
+ }
+ (e = n), ((t = Movable).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Movable.prototype;
+ return (
+ (i.reset = function () {
+ (this.speed = 0), (this.entity.body.movable = !1), this.entity.body.velocity.reset();
+ }),
+ (i.update = function (t) {
+ if (!this.entity.game.hero.player.dead && this.speed && this.entity.active) {
+ null !== this.lastDest && ((this.entity.body.back = this.lastDest), (this.entity.body.origin.back = this.lastDest));
+ var e = this.target - this.entity.game.stats.z,
+ i = this.origin + e * this.speed,
+ n = i - this.entity.body.back;
+ (this.entity.body.velocity.z = n), (this.lastDest = i);
+ }
+ }),
+ (i.run = function (t, e) {
+ (this.speed = t), (this.origin = this.entity.body.back), (this.target = e), (this.lastDest = this.origin), (this.entity.body.movable = 0 < this.speed);
+ }),
+ Movable
+ );
+ })(J.a);
+ var st = (function (n) {
+ var t, e;
+
+ function Collectible(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).entity.body.solid = !1), i;
+ }
+ (e = n), ((t = Collectible).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Collectible.prototype;
+ return (
+ (i.reset = function () {
+ (this.entity.active = !0), (this.collected = !1);
+ }),
+ (i.collect = function (t) {
+ this.collected ||
+ ((this.collected = !0),
+ (this.entity.active = !1),
+ this.entity.body && ((this.entity.body.movable = 0), this.entity.body.velocity.reset()),
+ this.entity.attractable && (this.entity.attractable.attracted = !1),
+ this.entity.onCollect && this.entity.onCollect(t));
+ }),
+ Collectible
+ );
+ })(J.a);
+ var at = (function (n) {
+ var t, e;
+
+ function Attractable(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).startPosition = new q()), (i.endPosition = new q()), i.reset(), i;
+ }
+ (e = n), ((t = Attractable).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Attractable.prototype;
+ return (
+ (i.reset = function () {
+ (this.speedX = L.range(0.001, 0.005)), (this.speedY = L.range(0.001, 0.005)), (this.speedZ = L.range(0.001, 0.005)), (this.attracted = !1), (this.entity.body.movable = !1);
+ }),
+ (i.update = function (t) {
+ if (this.entity.game && this.entity.active) {
+ var e = this.entity.game.hero;
+ if ((this.attracted && this.entity.game.state !== pn.RUNNING && ((this.attracted = !1), (this.entity.active = !1)), this.attracted && this.attractionUpdate(t), !this.attracted && this.entity.game.state === pn.RUNNING))
+ if (e.magnet.isOn()) this.entity.body.center.distance(e.body.center) < 110 && this.attractionStart();
+ else if (e.sneakers.isOn()) {
+ var i = Math.abs(this.entity.body.x - e.body.x),
+ n = e.body.y - this.entity.body.y,
+ o = Math.abs(e.body.z - this.entity.body.z);
+ e.body.airborne && i < 10 && 0 < n && n < 50 && o < 50 && this.attractionStart();
+ }
+ }
+ }),
+ (i.attractionStart = function () {
+ (this.attracted = !0), this.entity.movable && this.entity.movable.reset();
+ var t = this.entity.game.hero;
+ (this.entity.body.movable = !0),
+ (this.entity.body.ghost = !0),
+ (this.startPosition.x = this.entity.body.x),
+ (this.startPosition.y = this.entity.body.y),
+ (this.startPosition.z = this.entity.body.z),
+ (this.endPosition.x = t.body.x),
+ (this.endPosition.y = t.body.y),
+ (this.endPosition.z = t.body.z + t.body.velocity.z);
+ var e = this.startPosition.distance(this.endPosition);
+ (this.duration = 0.2 * e), this.duration < 4 && (this.duration = 4), (this.time = 0);
+ }),
+ (i.attractionUpdate = function (t) {
+ var e = this.entity.game.hero,
+ i = this.time / this.duration;
+ (this.endPosition.x = e.body.x), (this.endPosition.y = e.body.y), (this.endPosition.z = e.body.z + 2 * e.body.velocity.z), V.lerpVec3(this.entity.body, this.startPosition, this.endPosition, i * i), (this.time += t);
+ }),
+ (i.updateAttraction2 = function (t) {
+ var e = -hero.body.velocity.z,
+ i = (hero.body.velocity.y, this.entity.body.x - hero.body.x),
+ n = this.entity.body.y - hero.body.y,
+ o = this.entity.body.z - hero.body.z;
+ (this.entity.body.velocity.x = -i * this.speedX),
+ (this.entity.body.velocity.y = -n * this.speedY),
+ (this.entity.body.velocity.z = -o * this.speedZ),
+ (this.speedX = V.clamp(this.speedX + 0.003 * e, 0, 2)),
+ (this.speedY = V.clamp(this.speedY + 0.003 * e, 0, 2)),
+ (this.speedZ = V.clamp(this.speedZ + 0.003, 0, 2)),
+ this.entity.body.z >= hero.body.z - 1 &&
+ ((this.entity.body.x = hero.body.x),
+ (this.entity.body.y = hero.body.y),
+ (this.entity.body.z = hero.body.z),
+ (this.entity.body.velocity.x = 0),
+ (this.entity.body.velocity.y = 0),
+ (this.entity.body.velocity.z = 0),
+ (this.attracted = !1),
+ (this.entity.body.movable = !1),
+ (this.entity.body.ghost = !1));
+ }),
+ Attractable
+ );
+ })(J.a);
+ var rt = {
+ rotationSpeed: 0.1,
+ },
+ ht = 1,
+ dt = (function (n) {
+ var t, e;
+
+ function Floating(t, e) {
+ var i;
+ return void 0 === e && (e = {}), (e = Object.assign({}, rt, e)), ((i = n.call(this, t, e) || this).startingRot = null), (i.index = null), i;
+ }
+ (e = n), ((t = Floating).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Floating.prototype;
+ return (
+ (i.reset = function () {
+ (this.startingRot = null), (this.index = ht++);
+ }),
+ (i.update = function (t) {
+ this.entity.model && (null === this.startingRot && ((this.startingRot = 0.4 * ht++), (this.entity.model.ry = this.startingRot)), (this.entity.model.ry -= t * this.data.rotationSpeed));
+ }),
+ Floating
+ );
+ })(J.a);
+ var lt = (function (n) {
+ var t, e;
+
+ function Shine(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).view = H.plane(15, 15, 0.9, "halo_mip.png", 1)),
+ (i.view.view3d.state.blend = !0),
+ (i.view.view3d.state.depthTest = !0),
+ (i.view.view3d.orderBias = 999),
+ (i.view.z = -1.2),
+ t.addChild(i.view),
+ i
+ );
+ }
+ return (
+ (e = n),
+ ((t = Shine).prototype = Object.create(e.prototype)),
+ ((t.prototype.constructor = t).__proto__ = e),
+ (Shine.prototype.update = function (t) {
+ var e = this.entity.game.hero.body,
+ i = this.entity.body.z - e.z,
+ n = 1 - V.clamp(-i / 500);
+ this.view.scale.set(1.1 * n);
+ }),
+ Shine
+ );
+ })(J.a);
+ var ct = {
+ type: "coin",
+ },
+ ut = (function (n) {
+ var t, e;
+
+ function Pop(t, e) {
+ var i;
+ return void 0 === e && (e = {}), (e = Object.assign({}, ct, e)), ((i = n.call(this, t, e) || this).view = H.getEntityCloneBlend("/star7", "effects_tex", 0.9, 3)), (i.view.rotation.y = Math.PI), (i.duration = 8), i.reset(), i;
+ }
+ (e = n), ((t = Pop).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Pop.prototype;
+ return (
+ (i.reset = function () {
+ this.view.parent && this.entity.removeChild(this.view), (this.view.active = !1), this.view.scale.set(0), (this.count = 0);
+ }),
+ (i.update = function (t) {
+ if (this.count) {
+ this.count -= t;
+ var e = 0.5 + 0.75 * (1 - this.count / this.duration);
+ this.view.scale.set(e), this.count <= 0 && this.reset();
+ }
+ }),
+ (i.play = function () {
+ (this.view.rotation.z = V.PI_DOUBLE * Math.random()), (this.count = this.duration), (this.view.active = !0), this.view.scale.set(0.5), this.entity.addChild(this.view);
+ }),
+ Pop
+ );
+ })(J.a);
+ var pt = (function (e) {
+ var t, i;
+
+ function Coin() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ ghost: !0,
+ boxColor: 16776960,
+ }),
+ t.add(at),
+ t.add(ot),
+ t.add(st),
+ t.add(dt, {
+ rotationSpeed: 0.06,
+ }),
+ B.optm || t.add(lt),
+ (t.body.width = 10),
+ (t.body.height = 10),
+ (t.body.depth = 10),
+ (t.trigger = 0),
+ (t.speed = 0),
+ t
+ );
+ }
+ (i = e), ((t = Coin).prototype = Object.create(i.prototype)), ((t.prototype.constructor = t).__proto__ = i);
+ var n = Coin.prototype;
+ return (
+ (n.createView = function () {
+ this.model || ((this.model = H.getEntityCloneOpaque("/currency/currency_coin", "props_tex")), this.addChild(this.model));
+ }),
+ (n.reset = function (t) {
+ this.movable.reset(), this.body.velocity.reset(), this.attractable.reset(), (this.body.movable = !1), (this.active = !0);
+ }),
+ (n.update = function (t) {
+ this.body.movable && this.game && (heroBody.z <= this.trigger ? (this.body.velocity.z = this.speed) : (this.body.velocity.z = 0));
+ }),
+ (n.init = function () {
+ this.createView(), this.movable.reset(), this.attractable.reset(), this.body.velocity.reset(), (this.body.movable = !1), (this.active = !0);
+ }),
+ (n.onCollect = function (t) {
+ (this.game.stats.coins += 1),
+ this.game.sfx.play("pickup_coin", {
+ volume: 0.5,
+ }),
+ this.game.hero.pop.play();
+ }),
+ Coin
+ );
+ })(v.a);
+
+ function Train_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ (pt.cache = function (t, e) {
+ void 0 === e && (e = 50), t.pool.prepopulate(pt, amout);
+ }),
+ (pt.match = function (t) {
+ return !!t.name.match(/Coin \(/) || !!t.name.match(/Coins \(/);
+ }),
+ (pt.factory = function (t, e, i) {
+ if (e.name.match(/Line/)) {
+ if (50 < e.components.Transform.position.y) return;
+ for (var n = e.components.CoinCurve._curveOffset, o = e.components.CoinCurve._curveParent._cachedCurve.MaxCoords.z, s = o * n, a = o / 5, r = 0; r < 5; r++) {
+ var h = pt.spawnCoin(t, e, i),
+ d = r * a - s;
+ (h.body.z -= d), (h.arc = !1);
+ }
+ } else e.name.match(/Jump Curve/) ? pt.spawnJumpCurve(t, e, i) : pt.spawnCoin(t, e, i);
+ }),
+ (pt.spawnCoin = function (t, e, i) {
+ var n = t.game.pool.get(pt),
+ o = e.components.Transform.position.x,
+ s = e.components.Transform.position.y,
+ a = e.components.Transform.position.z;
+ return (
+ (n.body.x = o),
+ (n.body.bottom = s),
+ (n.body.z = t.z - a),
+ i.px && (n.body.x = i.px),
+ i.offsetX && (n.body.x = i.offsetX),
+ i.flip && (n.body.x *= -1),
+ 150 < n.body.bottom && (n.body.bottom = 29),
+ n.init(e),
+ i.py && (n.body.bottom = i.py),
+ i.bottom && (n.body.bottom = i.bottom),
+ (n.arc = !1),
+ t.game.addChild(n),
+ n
+ );
+ }),
+ (pt.spawnLine = function (t, e, i, n, o) {
+ void 0 === o && (o = 5);
+ for (var s = 29 * o * 0.5 - 15, a = 0; a < o; a++) {
+ var r = t.game.pool.get(pt);
+ (r.body.z = n - 30 * a + s), (r.body.bottom = i), (r.body.x = e), r.init(), (r.arc = !1), t.game.addChild(r);
+ }
+ }),
+ (pt.spawnCurve = function (t, e, i, n) {
+ for (var o = 50 * t.game.stats.speed, s = Math.floor(o / 13), a = o / s, r = (a - 1) * s * 0.5 - 0.5 * a, h = Math.PI / (s - 1), d = 0; d < s; d++) {
+ var l = t.game.pool.get(pt);
+ (l.body.z = n - d * a + r), (l.body.bottom = i + 22 * Math.sin(h * d)), (l.body.x = e), l.init(), (l.arc = !0), t.game.addChild(l);
+ }
+ }),
+ (pt.spawnJumpCurve = function (t, e, i) {
+ for (var n = 50 * t.game.stats.speed, o = Math.floor(n / 14), s = e.components.CoinCurve ? e.components.CoinCurve._curveOffset : 0.5, a = n / o, r = Math.PI / o, h = n * s, d = 0; d < o; d++) {
+ var l = pt.spawnCoin(t, e, i),
+ c = d * a - h,
+ u = 22 * Math.sin(r * d);
+ (l.body.bottom += u), (l.body.z -= c), (l.arc = !0);
+ }
+ });
+ var mt = (function (e) {
+ function Train() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ boxColor: 16711680,
+ }),
+ t.add(ot, {
+ speed: 0,
+ }),
+ (t.body.width = 18),
+ (t.body.height = 29),
+ (t.body.depth = 58),
+ t
+ );
+ }
+ Train_inheritsLoose(Train, e);
+ var t = Train.prototype;
+ return (
+ (t.reset = function (t) {
+ this.body.velocity.reset();
+ }),
+ (t.clean = function (t) {
+ for (var e = this.wagons.length; e--; ) {
+ var i = this.wagons[e];
+ t.game.pool["return"](i), this.removeChild(i);
+ }
+ }),
+ Train
+ );
+ })(v.a),
+ ft = (function (e) {
+ function TrainStandard() {
+ var t;
+ return ((t = e.call(this) || this).model = H.getEntityClone("train_standard")), (t.model.y = 0.5 * -t.body.height), (t.model.ry = Math.PI), t.addChild(t.model), t;
+ }
+ return Train_inheritsLoose(TrainStandard, e), TrainStandard;
+ })(mt),
+ gt = (function (e) {
+ function TrainCargo() {
+ var t;
+ return ((t = e.call(this) || this).model = H.getEntityClone("train_cargo")), (t.model.y = 0.5 * -t.body.height), (t.model.ry = Math.PI), t.addChild(t.model), t;
+ }
+ return Train_inheritsLoose(TrainCargo, e), TrainCargo;
+ })(mt),
+ yt = (function (e) {
+ function TrainSub() {
+ var t;
+ return ((t = e.call(this) || this).model = H.getEntityClone("train_sub")), (t.model.y = 0.5 * -t.body.height), (t.model.ry = Math.PI), t.addChild(t.model), t;
+ }
+ return Train_inheritsLoose(TrainSub, e), TrainSub;
+ })(mt),
+ vt = [ft, gt, yt];
+
+ function Blocker_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ (mt.factory = function (t, e, i) {
+ var n = null;
+ n = e.name.match("sub") ? yt : e.name.match("cargo") ? gt : e.name.match("standard") ? ft : L.pick.apply(L, vt);
+ for (var o = t.name.match("intro") ? "z" : "back", s = parseInt(e.name.match(/_(\d)_/)[1]), a = e.name.match(/coins/), r = 60 * s, h = s, d = 0, l = Number.NEGATIVE_INFINITY, c = 0, u = null; h--; ) {
+ ((u = t.game.pool.get(n)).chunk = t), (c = ue.get(e, "components.MovingTrainPlaceholder._speed", 0));
+ var p = e.components.Transform.position.x,
+ m = e.components.Transform.position.z,
+ f = 60 * h;
+ (u.body.x = null !== i.offsetX ? i.offsetX : p), (u.body.bottom = 0);
+ var g = t.z - m - f;
+ (u.body[o] = g), d || (d = u.body[o] + 0.6 * r + 30), i.flip && (u.body.x *= -1), u.movable.run(c, d), t.game.addChild(u), u.body.back > l && (l = u.body.back);
+ }
+ if (a)
+ for (var y = Math.ceil(1.1 * s), v = l - 50, _ = 0; _ < y; _++) {
+ var b = pt.spawnCoin(t, e, i);
+ (b.body.x = u.body.x), (b.body.bottom = 29), (b.body.z = v - 30 * _), b.movable.run(c, d);
+ }
+ }),
+ (mt.cache = function (t, e) {
+ void 0 === e && (e = 10), t.pool.prepopulate(ft, amout), t.pool.prepopulate(gt, amout), t.pool.prepopulate(yt, amout);
+ });
+ var _t = (function (e) {
+ function Blocker() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ ghost: !0,
+ }),
+ (t.body.width = 16),
+ (t.body.height = 26),
+ (t.body.depth = 1),
+ (t.model = null),
+ t
+ );
+ }
+ return (
+ Blocker_inheritsLoose(Blocker, e),
+ (Blocker.prototype.init = function (t, e) {
+ (this.model.ry = Math.PI), (this.model.z = -5), this.addChild(this.model);
+ }),
+ Blocker
+ );
+ })(v.a),
+ bt = (function (i) {
+ function BlockerJump() {
+ var t;
+ return ((t = i.call(this) || this).model = H.getEntityCloneOpaque("/blocker_jump", "environment_tex")), t;
+ }
+ return (
+ Blocker_inheritsLoose(BlockerJump, i),
+ (BlockerJump.prototype.init = function (t, e) {
+ i.prototype.init.call(this, t, e), (this.body.height = 26);
+ }),
+ BlockerJump
+ );
+ })(_t),
+ wt = {
+ jump: bt,
+ roll: (function (i) {
+ function BlockerRoll() {
+ var t;
+ return ((t = i.call(this) || this).model = H.getEntityCloneOpaque("/blocker_roll", "environment_tex")), t;
+ }
+ return (
+ Blocker_inheritsLoose(BlockerRoll, i),
+ (BlockerRoll.prototype.init = function (t, e) {
+ i.prototype.init.call(this, t, e), (this.body.height = 19), (this.body.bottom = 10), (this.model.y = -this.body.height / 2 - this.body.bottom);
+ }),
+ BlockerRoll
+ );
+ })(_t),
+ standard: (function (i) {
+ function BlockerStandard() {
+ var t;
+ return ((t = i.call(this) || this).model = H.getEntityCloneOpaque("/blocker_standard", "environment_tex")), t;
+ }
+ return (
+ Blocker_inheritsLoose(BlockerStandard, i),
+ (BlockerStandard.prototype.init = function (t, e) {
+ i.prototype.init.call(this, t, e), (this.body.height = 4), (this.body.bottom = 10), (this.model.y = -this.body.height / 2 - this.body.bottom);
+ }),
+ BlockerStandard
+ );
+ })(_t),
+ };
+
+ function Ramp_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ _t.factory = function (t, e, i) {
+ var n = L.pick.apply(L, Object.keys(wt));
+ e.name.match("jump") && (n = "jump"), e.name.match("roll") && (n = "roll");
+ var o = wt[n],
+ s = t.game.pool.get(o),
+ a = e.components.Transform.position.x,
+ r = e.components.Transform.position.z;
+ (s.body.front = t.z - r),
+ (s.body.x = a),
+ i.offsetX && (s.body.x = i.offsetX),
+ i.flip && (s.body.x *= -1),
+ s.init(t, e),
+ t.game.addChild(s),
+ e.name.match("w_coins") && (o === bt ? pt.spawnCurve(t, s.body.x, 0, s.body.z) : pt.spawnLine(t, s.body.x, 0, s.body.z));
+ };
+ var kt = (function (e) {
+ function Ramp() {
+ var t;
+ return (
+ ((t = e.call(this) || this).ramp = !0),
+ t.add(it),
+ (t.body.width = 18),
+ (t.body.height = 29),
+ (t.body.depth = 70),
+ (t.model = H.getEntityClone("/train_ramp")),
+ (t.model.position.y = 0.5 * -t.body.height),
+ (t.model.rotation.y = Math.PI),
+ (t.model.z = -8),
+ t.addChild(t.model),
+ t
+ );
+ }
+ return (
+ Ramp_inheritsLoose(Ramp, e),
+ (Ramp.prototype.init = function (t, e, i) {
+ var n = e.components.Transform.position.x,
+ o = e.components.Transform.position.z;
+ (this.body.x = n), (this.body.bottom = 0), (this.body.z = t.z - o + 6), i.offsetX && (this.body.x = i.offsetX), i.flip && (this.body.x *= -1);
+ var s = t.game.pool.get(xt);
+ s.reset(), (s.body.width = 0.2), (s.body.height = this.body.height), (s.body.depth = 0.7 * this.body.depth), (s.body.x = this.body.left), (s.body.y = this.body.y), (s.body.z = this.body.z), t.game.addChild(s);
+ var a = t.game.pool.get(xt);
+ a.reset(), (a.body.width = 0.2), (a.body.height = this.body.height), (a.body.depth = 0.7 * this.body.depth), (a.body.x = this.body.right), (a.body.y = this.body.y), (a.body.z = this.body.z), t.game.addChild(a);
+ }),
+ Ramp
+ );
+ })(v.a),
+ xt = (function (e) {
+ function Side() {
+ var t;
+ return (t = e.call(this) || this).add(it), t;
+ }
+ return (
+ Ramp_inheritsLoose(Side, e),
+ (Side.prototype.reset = function () {
+ (this.body.deco = !1), this.body.box.size.reset(), this.body.box.center.reset();
+ }),
+ Side
+ );
+ })(v.a);
+ var Ct = (function (e) {
+ var t, i;
+
+ function LightSignal() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ ghost: !0,
+ soft: !0,
+ }),
+ (t.body.width = 4),
+ (t.body.height = 42),
+ (t.body.depth = 4),
+ (t.model = H.getEntityClone("/lightSignal")),
+ (t.model.ry = Math.PI),
+ (t.model.y = 0.5 * -t.body.height),
+ t.addChild(t.model),
+ t
+ );
+ }
+ return (
+ (i = e),
+ ((t = LightSignal).prototype = Object.create(i.prototype)),
+ ((t.prototype.constructor = t).__proto__ = i),
+ (LightSignal.prototype.init = function (t, e, i) {
+ (this.body.x = e.components.Transform.position.x), i.flip && (this.body.x *= -1), (this.body.bottom = 0), (this.body.z = t.z - e.components.Transform.position.z);
+ }),
+ LightSignal
+ );
+ })(v.a),
+ St = (function () {
+ function Curve() {}
+ return (
+ (Curve.calculateJumpVerticalSpeed = function (t, e) {
+ if (t < 0) throw new Error("Jump height cannot be negative");
+ return Math.sqrt(2 * t * e);
+ }),
+ (Curve.calculateJumpLength = function (t, e, i) {
+ return (2 * t * this.calculateJumpVerticalSpeed(e)) / i;
+ }),
+ (Curve.linear = function (t) {
+ return t;
+ }),
+ (Curve.expoIn = function (t) {
+ return 0 === t ? t : Math.pow(2, 10 * (t - 1));
+ }),
+ (Curve.expoOut = function (t) {
+ return 1 === t ? t : 1 - Math.pow(2, -10 * t);
+ }),
+ (Curve.expoInOut = function (t) {
+ return 0 === t || 1 === t ? t : t < 0.5 ? 0.5 * Math.pow(2, 20 * t - 10) : -0.5 * Math.pow(2, 10 - 20 * t) + 1;
+ }),
+ (Curve.sineIn = function (t) {
+ var e = Math.cos(t * Math.PI * 0.5);
+ return Math.abs(e) < 1e-14 ? 1 : 1 - e;
+ }),
+ (Curve.sineOut = function (t) {
+ return Math.sin((t * Math.PI) / 2);
+ }),
+ (Curve.sineInOut = function (t) {
+ return -0.5 * (Math.cos(Math.PI * t) - 1);
+ }),
+ (Curve.quadIn = function (t) {
+ return t * t;
+ }),
+ (Curve.quadOut = function (t) {
+ return -t * (t - 2);
+ }),
+ (Curve.quadInOut = function (t) {
+ return (t /= 0.5) < 1 ? 0.5 * t * t : -0.5 * (--t * (t - 2) - 1);
+ }),
+ (Curve.quartIn = function (t) {
+ return Math.pow(t, 4);
+ }),
+ (Curve.quartOut = function (t) {
+ return Math.pow(t - 1, 3) * (1 - t) + 1;
+ }),
+ (Curve.quartInOut = function (t) {
+ return t < 0.5 ? 8 * Math.pow(t, 4) : -8 * Math.pow(t - 1, 4) + 1;
+ }),
+ (Curve.quintIn = function (t) {
+ return t * t * t * t * t;
+ }),
+ (Curve.quintOut = function (t) {
+ return --t * t * t * t * t + 1;
+ }),
+ (Curve.quintInOut = function (t) {
+ return (t *= 2) < 1 ? 0.5 * t * t * t * t * t : 0.5 * ((t -= 2) * t * t * t * t + 2);
+ }),
+ (Curve.backInOut = function (t) {
+ var e = 2.5949095;
+ return (t *= 2) < 1 ? t * t * ((e + 1) * t - e) * 0.5 : 0.5 * ((t -= 2) * t * ((e + 1) * t + e) + 2);
+ }),
+ (Curve.backIn = function (t) {
+ return t * t * (2.70158 * t - 1.70158);
+ }),
+ (Curve.backOut = function (t) {
+ return --t * t * (2.70158 * t + 1.70158) + 1;
+ }),
+ (Curve.circInOut = function (t) {
+ return (t *= 2) < 1 ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
+ }),
+ (Curve.circIn = function (t) {
+ return 1 - Math.sqrt(1 - t * t);
+ }),
+ (Curve.circOut = function (t) {
+ return Math.sqrt(1 - --t * t);
+ }),
+ (Curve.elasticOut = function (t) {
+ return Math.sin((-13 * (t + 1) * Math.PI) / 2) * Math.pow(2, -10 * t) + 1;
+ }),
+ (Curve.elasticIn = function (t) {
+ return Math.sin((13 * t * Math.PI) / 2) * Math.pow(2, 10 * (t - 1));
+ }),
+ (Curve.elasticInOut = function (t) {
+ return t < 0.5 ? 0.5 * Math.sin(((13 * Math.PI) / 2) * 2 * t) * Math.pow(2, 10 * (2 * t - 1)) : 0.5 * Math.sin(((-13 * Math.PI) / 2) * (2 * t - 1 + 1)) * Math.pow(2, -10 * (2 * t - 1)) + 1;
+ }),
+ Curve
+ );
+ })();
+ var zt = (function (n) {
+ var t, e;
+
+ function Halo(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).view = new v.a()),
+ (i.halo = H.getEntityCloneBlend("/powBoost", "effects_tex", 0.95, 1)),
+ i.view.addChild(i.halo),
+ (i.view.z = -3),
+ (i.view.ry = Math.PI),
+ t.addChild(i.view),
+ i.reset(),
+ i
+ );
+ }
+ (e = n), ((t = Halo).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Halo.prototype;
+ return (
+ (i.reset = function () {
+ (this.scaleStart = 0), (this.scaleEnd = 1), (this.maxDistance = 500), (this.rotationSpeed = -0.03);
+ }),
+ (i.update = function (t) {
+ this.updateHaloScale(), this.updateViewScale(), this.rotationSpeed && (this.halo.rotation.z += t * this.rotationSpeed);
+ }),
+ (i.updateHaloScale = function (t) {
+ var e = this.entity.game.stats.z + 20 - this.entity.body.z,
+ i = 1.5 + 0.5 * Math.sin(0.03 * e);
+ this.halo.scale.set(i);
+ }),
+ (i.updateViewScale = function () {
+ var t = this.entity.game.stats.z - 10 - this.entity.body.z,
+ e = 1 - V.clamp(t / this.maxDistance),
+ i = St.backOut(e),
+ n = this.scaleStart + (this.scaleEnd - this.scaleStart) * i;
+ this.view.scale.set(n);
+ }),
+ Halo
+ );
+ })(J.a);
+
+ function Pickup_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ var Tt = (function (e) {
+ function Pickup() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ ghost: !0,
+ }),
+ t.add(st),
+ t.add(dt, {
+ rotationSpeed: -0.03,
+ }),
+ t.add(zt, {
+ type: "rays",
+ }),
+ (t.body.width = 12),
+ (t.body.height = 12),
+ (t.body.depth = 12),
+ t
+ );
+ }
+ Pickup_inheritsLoose(Pickup, e);
+ var t = Pickup.prototype;
+ return (
+ (t.init = function (t, e) {
+ this.addChild(this.model);
+ }),
+ (t.onCollect = function (t) {
+ !!this.game.hero[this.type] && this.game.hero[this.type].turnOn(),
+ "key" === this.type && (this.game.stats.keys += 1),
+ "jetpack" !== this.type && this.game.sfx.play("pickup_powerup"),
+ this.game.hero.popPickup && this.game.hero.popPickup.play();
+ }),
+ Pickup
+ );
+ })(v.a),
+ Pt = (function (e) {
+ function PickupJetpack() {
+ var t;
+ return ((t = e.call(this) || this).type = "jetpack"), (t.model = H.getEntityCloneOpaque("/powerups_jetpack", "props_tex")), t.model.scale.set(1.5), t;
+ }
+ return Pickup_inheritsLoose(PickupJetpack, e), PickupJetpack;
+ })(Tt),
+ Mt = (function (e) {
+ function PickupPogo() {
+ var t;
+ return ((t = e.call(this) || this).type = "pogo"), (t.model = H.getEntityCloneOpaque("/powerups_rocketPogo", "props_tex")), t.model.scale.set(1.75), t;
+ }
+ return Pickup_inheritsLoose(PickupPogo, e), PickupPogo;
+ })(Tt),
+ Et = (function (e) {
+ function PickupMagnet() {
+ var t;
+ return ((t = e.call(this) || this).type = "magnet"), (t.model = H.getEntityCloneOpaque("/powerups_coinMagnet", "props_tex")), t.model.scale.set(1.5), t;
+ }
+ return Pickup_inheritsLoose(PickupMagnet, e), PickupMagnet;
+ })(Tt),
+ Ot = (function (e) {
+ function PickupSneakers() {
+ var t;
+ return ((t = e.call(this) || this).type = "sneakers"), (t.model = H.getEntityCloneOpaque("/powerups_superSneakers", "props_tex")), t.model.scale.set(1.5), t;
+ }
+ return Pickup_inheritsLoose(PickupSneakers, e), PickupSneakers;
+ })(Tt),
+ Rt = (function (e) {
+ function PickupMultiplier() {
+ var t;
+ return ((t = e.call(this) || this).type = "multiplier"), (t.model = H.getEntityCloneOpaque("/powerups_2xMultiplier", "props_tex")), t.model.scale.set(1.5), t;
+ }
+ return Pickup_inheritsLoose(PickupMultiplier, e), PickupMultiplier;
+ })(Tt),
+ It = (function (e) {
+ function PickupLetter() {
+ var t;
+ return ((t = e.call(this) || this).type = "letter"), (t.model = H.getEntityCloneOpaque("/letters/A", "props_tex")), t.model.scale.set(1.5), t;
+ }
+ return Pickup_inheritsLoose(PickupLetter, e), PickupLetter;
+ })(Tt),
+ Lt = (function (n) {
+ function PickupMysteryBox() {
+ var t;
+ ((t = n.call(this) || this).type = "mysteryBox"), (t.model = new v.a()), (t.base = H.getEntityCloneOpaque("/mysteryBox_base/mysteryBox_base_default", "props_tex")), t.model.addChild(t.base);
+ var e = H.getEntity("/containers/mysteryBox_base/mysteryBox_lid"),
+ i = H.findEntity("mysteryBox_lid_default", e);
+ return (t.lid = H.getEntityCloneOpaque(i, "props_tex")), (t.lid.x = 0.8), (t.lid.z = -0.8), t.model.addChild(t.lid), t;
+ }
+ return Pickup_inheritsLoose(PickupMysteryBox, n), PickupMysteryBox;
+ })(Tt),
+ jt = (function (e) {
+ function PickupKey() {
+ var t;
+ return ((t = e.call(this) || this).type = "key"), (t.model = H.getEntityCloneOpaque("/currency_key", "props_tex")), t.model.scale.set(1.5), t;
+ }
+ return Pickup_inheritsLoose(PickupKey, e), PickupKey;
+ })(Tt),
+ Ft = {
+ jetpack: Pt,
+ pogo: Mt,
+ magnet: Et,
+ sneakers: Ot,
+ multiplier: Rt,
+ letter: It,
+ key: jt,
+ mysteryBox: Lt,
+ },
+ At = [Rt, jt, Lt],
+ Dt = [Rt, Pt, Et, Ot],
+ Gt = {
+ Jetpack: Pt,
+ PogoStick: Mt,
+ CoinMagnet: Et,
+ SuperSneakers: Ot,
+ CoinMultiplier: Rt,
+ };
+ (Tt.match = function (t) {
+ return !!t.name.match(/PickupSpawn/);
+ }),
+ (Tt.factory = function (t, e, i) {
+ if (!t.envTube) {
+ var n = t.z - e.components.Transform.position.z,
+ o = null,
+ s = ue.get(e, "components.PickupSpawnPoint.__spawnPointMode", ""),
+ a = ue.get(e, "components.PickupSpawnPoint.__forceSpawnPickupType", "");
+ if ("WillForcePickupType" === s) o = Gt[a];
+ else {
+ if (!t.game.route.canSpawn("pickup", n)) return;
+ var r = ue.get(e, "components.PickupSpawnPoint._spawnPointDifficulty", "Hard");
+ if (
+ L.range(0, 1) >=
+ {
+ Hard: 0.1,
+ Medium: 0.5,
+ Easy: 0.8,
+ }[r]
+ )
+ return;
+ o = "Easy" === r ? L.item(At) : L.item(Dt);
+ }
+ if (o && o !== Lt && o !== jt && (o !== Pt || t.game.route.canSpawn("jetpack", n))) {
+ var h = t.game.pool.get(o),
+ d = e.components.Transform.position.x,
+ l = e.components.Transform.position.y;
+ (h.body.z = n),
+ (h.body.x = null !== i.offsetX ? i.offsetX : d),
+ (h.body.y = l),
+ i.flip && (h.body.x *= -1),
+ h.init(t, e),
+ t.game.addChild(h),
+ t.game.route.setSpawn("pickup", n - 2700),
+ o === Pt && t.game.route.setSpawn("jetpack", n - 4e3);
+ }
+ }
+ }),
+ (Tt.spawn = function (t, e) {
+ var i = e || Object.keys(Ft),
+ n = L.pick.apply(L, i),
+ o = Ft[n],
+ s = t.pool.get(o);
+ return s.init(), t.addChild(s), s;
+ });
+ var Bt = {},
+ Nt = Bt;
+ B.ground
+ ? ((Bt.newTrack = function () {
+ return H.getEntityClone("/track");
+ }),
+ (Bt.newTrackShadowStart = function () {
+ return H.getEntityClone("/track_shadow_start");
+ }),
+ (Bt.newTrackShadowMid = function () {
+ return H.getEntityClone("/track_shadow_mid");
+ }),
+ (Bt.newTrackShadowEnd = function () {
+ return H.getEntityClone("/track_shadow_end");
+ }),
+ (Bt.newTrackShadowShortStart = function () {
+ return H.getEntityClone("/track_shadow_short_start");
+ }),
+ (Bt.newTrackShadowShortEnd = function () {
+ return H.getEntityClone("/track_shadow_short_end");
+ }),
+ (Bt.newGround = function () {
+ return H.getEntityClone("/ground");
+ }),
+ (Bt.newGroundShadowStart = function () {
+ return H.getEntityClone("/ground_shadow_start");
+ }),
+ (Bt.newGroundShadowMid = function () {
+ return H.getEntityClone("/ground_shadow_mid");
+ }),
+ (Bt.newGroundShadowEnd = function () {
+ return H.getEntityClone("/ground_shadow_mid");
+ }),
+ (Bt.newGroundShadowShortStart = function () {
+ return H.getEntityClone("/ground_shadow_short_start");
+ }),
+ (Bt.newGroundShadowShortEnd = function () {
+ return H.getEntityClone("/ground_shadow_short_end");
+ }),
+ (Bt.newGates = function () {
+ return H.getEntityClone("track_gates");
+ }),
+ (Bt.newGatesShadow = function () {
+ return H.getEntityClone("track_gates_shadows");
+ }))
+ : ((Bt.newTrack = function () {
+ return new v.a();
+ }),
+ (Bt.newTrackShadowStart = function () {
+ return new v.a();
+ }),
+ (Bt.newTrackShadowMid = function () {
+ return new v.a();
+ }),
+ (Bt.newTrackShadowEnd = function () {
+ return new v.a();
+ }),
+ (Bt.newTrackShadowShortStart = function () {
+ return new v.a();
+ }),
+ (Bt.newTrackShadowShortEnd = function () {
+ return new v.a();
+ }),
+ (Bt.newGround = function () {
+ return new v.a();
+ }),
+ (Bt.newGroundShadowStart = function () {
+ return new v.a();
+ }),
+ (Bt.newGroundShadowMid = function () {
+ return new v.a();
+ }),
+ (Bt.newGroundShadowEnd = function () {
+ return new v.a();
+ }),
+ (Bt.newGroundShadowShortStart = function () {
+ return new v.a();
+ }),
+ (Bt.newGroundShadowShortEnd = function () {
+ return new v.a();
+ }),
+ (Bt.newGates = function () {
+ return new v.a();
+ }),
+ (Bt.newGatesShadow = function () {
+ return new v.a();
+ })),
+ (Bt.spawn = function (t, e) {
+ void 0 === e && (e = {}), e.z || (e.z = t.z), e.l || (e.l = Bt.newTrack), e.m || (e.m = e.l), e.r || (e.r = e.m);
+ var i = t.game.pool.get(e.l);
+ t.game.addChild(i), (i.x = -B.laneWidth), (i.y = 0), (i.z = e.z), (i.ry = Math.PI);
+ var n = t.game.pool.get(e.m);
+ t.game.addChild(n), (n.x = 0), (n.y = 0), (n.z = e.z), (n.ry = Math.PI);
+ var o = t.game.pool.get(e.r);
+ t.game.addChild(o), (o.x = B.laneWidth), (o.y = 0), (o.z = e.z), (o.ry = Math.PI);
+ }),
+ (Bt.spawnGates = function (t, e) {
+ if ((void 0 === e && (e = {}), !t.name.match("tutorial"))) {
+ e.z || (e.z = t.z);
+ var i = t.game.pool.get(Bt.newGates);
+ t.game.addChild(i), (i.x = 0), (i.y = 0), (i.z = e.z), (i.ry = Math.PI);
+ }
+ }),
+ (Bt.mount = function (t) {
+ if ("intro" === t.name) {
+ for (var e = 0; e < 1; e++)
+ if (!t.floors[e]) {
+ var i = 2 * B.blockSize,
+ n = Bt.newTrack,
+ o = Bt.newTrack,
+ s = Bt.newTrack;
+ Bt.spawn(t, {
+ z: i,
+ l: n,
+ m: o,
+ r: s,
+ });
+ }
+ } else if (t.name.match("default_short_1_track")) {
+ for (var a = t.blocks / 2, r = 0; r < a; r++)
+ if (!t.floors[r]) {
+ var h = 0 < r,
+ d = t.z - r * B.blockSize * 2,
+ l = h ? Bt.newGround : Bt.newTrack,
+ c = Bt.newTrack,
+ u = h ? Bt.newGround : Bt.newTrack;
+ Bt.spawn(t, {
+ z: d,
+ l: l,
+ m: c,
+ r: u,
+ }),
+ (t.floors[r] = !0);
+ }
+ } else if (t.name.match("default_1_track")) {
+ for (var p = t.blocks / 2, m = 0; m < p; m++)
+ if (!t.floors[m]) {
+ var f = t.name.match("_mid"),
+ g = t.z - m * B.blockSize * 2,
+ y = f ? Bt.newGround : Bt.newTrack,
+ v = Bt.newTrack,
+ _ = f ? Bt.newGround : Bt.newTrack;
+ Bt.spawn(t, {
+ z: g,
+ l: y,
+ m: v,
+ r: _,
+ }),
+ (t.floors[m] = !0);
+ }
+ } else if (t.name.match("default_short_2_tracks")) {
+ for (var b = t.blocks / 2, w = 0; w < b; w++)
+ if (!t.floors[w]) {
+ var k = t.name.match("_mid_") || t.name.match("_end"),
+ x = t.z - w * B.blockSize * 2,
+ C = Bt.newTrack,
+ S = k ? Bt.newGround : Bt.newTrack,
+ z = Bt.newTrack;
+ Bt.spawn(t, {
+ z: x,
+ l: C,
+ m: S,
+ r: z,
+ }),
+ (t.floors[w] = !0);
+ }
+ } else if (t.name.match("default_2_tracks")) {
+ for (var T = t.blocks / 2, P = 0; P < T; P++)
+ if (!t.floors[P]) {
+ var M = !t.name.match("_end"),
+ E = t.z - P * B.blockSize * 2,
+ O = Bt.newTrack,
+ R = M ? Bt.newGround : Bt.newTrack,
+ I = Bt.newTrack;
+ Bt.spawn(t, {
+ z: E,
+ l: O,
+ m: R,
+ r: I,
+ }),
+ (t.floors[P] = !0);
+ }
+ } else if ("default_tutorial" === t.name);
+ else if (!t.hasGround)
+ for (var L = t.blocks / 2, j = 0; j < L; j++)
+ if (!t.floors[j]) {
+ var F = t.z - j * B.blockSize * 2,
+ A = Bt.newTrack,
+ D = Bt.newTrack,
+ G = Bt.newTrack;
+ Bt.spawn(t, {
+ z: F,
+ l: A,
+ m: D,
+ r: G,
+ }),
+ (t.floors[j] = !0);
+ }
+ });
+ var Xt = {},
+ Yt = Xt;
+
+ function Gates_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ B.fillers
+ ? ((Xt.newLow01Left = function () {
+ return H.getEntityClone("/low_01_left");
+ }),
+ (Xt.newLow02Left = function () {
+ return H.getEntityClone("/low_02_left");
+ }),
+ (Xt.newMed01Left = function () {
+ return H.getEntityClone("/med_01_left");
+ }),
+ (Xt.newMed02Left = function () {
+ return H.getEntityClone("/med_02_left");
+ }),
+ (Xt.newMed03Left = function () {
+ return H.getEntityClone("/med_03_left");
+ }),
+ (Xt.newHigh01Left = function () {
+ return H.getEntityClone("/high_01_left");
+ }),
+ (Xt.newHigh02Left = function () {
+ return H.getEntityClone("/high_02_left");
+ }),
+ (Xt.newHigh03Left = function () {
+ return H.getEntityClone("/high_03_left");
+ }),
+ (Xt.newLow01Right = function () {
+ return H.getEntityClone("/low_01_right", "", !1, R);
+ }),
+ (Xt.newLow02Right = function () {
+ return H.getEntityClone("/low_02_right", "", !1, R);
+ }),
+ (Xt.newMed01Right = function () {
+ return H.getEntityClone("/med_01_right");
+ }),
+ (Xt.newMed02Right = function () {
+ return H.getEntityClone("/med_02_right");
+ }),
+ (Xt.newMed03Right = function () {
+ return H.getEntityClone("/med_03_right");
+ }),
+ (Xt.newHigh01Right = function () {
+ return H.getEntityClone("/high_01_right");
+ }),
+ (Xt.newHigh02Right = function () {
+ return H.getEntityClone("/high_02_right");
+ }),
+ (Xt.newHigh03Right = function () {
+ return H.getEntityClone("/high_03_right");
+ }))
+ : ((Xt.newLow01Left = function () {
+ return new v.a();
+ }),
+ (Xt.newLow02Left = function () {
+ return new v.a();
+ }),
+ (Xt.newMed01Left = function () {
+ return new v.a();
+ }),
+ (Xt.newMed02Left = function () {
+ return new v.a();
+ }),
+ (Xt.newMed03Left = function () {
+ return new v.a();
+ }),
+ (Xt.newHigh01Left = function () {
+ return new v.a();
+ }),
+ (Xt.newHigh02Left = function () {
+ return new v.a();
+ }),
+ (Xt.newHigh03Left = function () {
+ return new v.a();
+ }),
+ (Xt.newLow01Right = function () {
+ return new v.a();
+ }),
+ (Xt.newLow02Right = function () {
+ return new v.a();
+ }),
+ (Xt.newMed01Right = function () {
+ return new v.a();
+ }),
+ (Xt.newMed02Right = function () {
+ return new v.a();
+ }),
+ (Xt.newMed03Right = function () {
+ return new v.a();
+ }),
+ (Xt.newHigh01Right = function () {
+ return new v.a();
+ }),
+ (Xt.newHigh02Right = function () {
+ return new v.a();
+ }),
+ (Xt.newHigh03Right = function () {
+ return new v.a();
+ })),
+ (Xt.spawn = function (t, e) {
+ void 0 === e && (e = {}), e.z || (e.z = t.z), e.l || (e.l = Xt.newLow01Left), e.r || (e.r = Xt.newLow01Right);
+ var i = t.game.pool.get(e.l);
+ t.game.addChild(i), (i.x = 0), (i.y = 0), (i.z = e.z), (i.ry = Math.PI);
+ var n = t.game.pool.get(e.r);
+ t.game.addChild(n), (n.x = 0), (n.y = 0), (n.z = e.z), (n.ry = Math.PI);
+ }),
+ (Xt.mount = function (t) {
+ if (t.name.match("default_short_1_track")) {
+ for (var e = t.blocks / 2, i = 0; i < e; i++)
+ if (!t.fillers[i]) {
+ var n = t.z - i * B.blockSize * 2,
+ o = Xt.newMed02Left,
+ s = Xt.newMed02Right;
+ Xt.spawn(t, {
+ z: n,
+ l: o,
+ r: s,
+ });
+ }
+ } else if (t.name.match("default_short_2_tracks")) {
+ for (var a = t.blocks / 2, r = 0; r < a; r++)
+ if (!t.fillers[r]) {
+ var h = t.z - r * B.blockSize * 2,
+ d = Xt.newLow02Left,
+ l = Xt.newHigh02Right;
+ Xt.spawn(t, {
+ z: h,
+ l: d,
+ r: l,
+ });
+ }
+ } else if (t.name.match("default_2_tracks")) {
+ for (var c = t.blocks / 2, u = 0; u < c; u++)
+ if (!t.fillers[u]) {
+ var p = t.z - u * B.blockSize * 2,
+ m = Xt.newLow01Left,
+ f = Xt.newHigh01Right;
+ Xt.spawn(t, {
+ z: p,
+ l: m,
+ r: f,
+ });
+ }
+ } else
+ for (var g = t.blocks / 2, y = L.item(["Low", "Med", "High"]), v = "Low" == y ? ["01", "02"] : ["01", "02", "03"], _ = 0; _ < g; _++)
+ if (!t.fillers[_]) {
+ var b = L.item(v),
+ w = Xt["new" + y + b + "Left"],
+ k = Xt["new" + y + b + "Right"],
+ x = t.z - _ * B.blockSize * 2;
+ Xt.spawn(t, {
+ z: x,
+ l: w,
+ r: k,
+ }),
+ "Low" === y && "1103_seoul" === B.env && (t.floors[_] = !0);
+ }
+ });
+ var Ht = (function (e) {
+ function Gates() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ noView: !0,
+ trigger: !0,
+ }),
+ (t.body.width = 80),
+ (t.body.height = 50),
+ (t.body.depth = 120),
+ (t.lowCamera = !0),
+ t
+ );
+ }
+ return (
+ Gates_inheritsLoose(Gates, e),
+ (Gates.prototype.init = function (t, e) {
+ (this.body.x = 0),
+ (this.body.bottom = 0),
+ (this.body.z = t.z - e.components.Transform.position.z - 2 * B.blockSize),
+ this.model && ((this.model.ry = Math.PI), (this.model.y = 0.5 * -this.body.height), (this.model.z = 1.45 * this.body.depth), this.addChild(this.model));
+ var i = t.game.pool.get(Ut);
+ (i.body.width = this.body.width), (i.body.height = 16), (i.body.depth = 0.9 * this.body.depth), (i.body.x = 0), (i.body.bottom = 37), (i.body.z = this.body.z), t.game.addChild(i);
+ var n = t.game.pool.get(Ut);
+ (n.body.width = 20), (n.body.height = i.body.bottom), (n.body.depth = 0.9 * this.body.depth), (n.body.bottom = 0), (n.body.right = 1.5 * -B.laneWidth), (n.body.z = this.body.z), t.game.addChild(n);
+ var o = t.game.pool.get(Ut);
+ (o.body.width = 20), (o.body.height = i.body.bottom), (o.body.depth = 0.9 * this.body.depth), (o.body.bottom = 0), (o.body.x = 0), (o.body.z = this.body.z), t.game.addChild(o);
+ var s = t.game.pool.get(Ut);
+ (s.body.width = 20),
+ (s.body.height = i.body.bottom),
+ (s.body.depth = 0.9 * this.body.depth),
+ (s.body.bottom = 0),
+ (s.body.left = 1.5 * B.laneWidth),
+ (s.body.z = this.body.z),
+ t.game.addChild(s),
+ (this.colL = n),
+ (this.colR = s),
+ (this.colM = o),
+ (this.ceiling = i);
+ var a = t.game.pool.get(Gates.newEnvironment);
+ (a.ry = Math.PI),
+ (a.z = t.z),
+ t.game.addChild(a),
+ t.setFillersByPosition(t.z, t.z - 4 * B.blockSize),
+ Nt.spawnGates(t),
+ 4 < t.blocks &&
+ (Nt.spawn(t, {
+ z: t.z - 4 * B.blockSize,
+ }),
+ Yt.spawn(t, {
+ z: t.z - 4 * B.blockSize,
+ l: Yt.newHigh01Left,
+ r: Yt.newHigh01Right,
+ }));
+ }),
+ Gates
+ );
+ })(v.a);
+ Ht.newEnvironment = function () {
+ return H.getEntityClone("/gates_base");
+ };
+ var Ut = (function (e) {
+ function GatePart() {
+ var t;
+ return (t = e.call(this) || this).add(it), t;
+ }
+ return Gates_inheritsLoose(GatePart, e), (GatePart.prototype.reset = function () {}), GatePart;
+ })(v.a),
+ Vt = (function (i) {
+ function GatesSides() {
+ var t;
+ return ((t = i.call(this) || this).model = H.getEntityClone("/gates_sides")), (t.model.ry = Math.PI), (t.model.y = 0.5 * -t.body.height), (t.model.sx = 0.9), (t.model.x = -1), t;
+ }
+ return (
+ Gates_inheritsLoose(GatesSides, i),
+ (GatesSides.prototype.init = function (t, e) {
+ i.prototype.init.call(this, t, e),
+ (this.colM.body.width = 20),
+ (this.colM.body.x = 0),
+ (this.colL.body.width = 20),
+ (this.colL.body.right = 1.5 * -B.laneWidth),
+ (this.colR.body.width = 20),
+ (this.colR.body.left = 1.5 * B.laneWidth);
+ }),
+ GatesSides
+ );
+ })(Ht),
+ qt = {
+ gates_mid_group_place: (function (i) {
+ function GatesMid() {
+ var t;
+ return ((t = i.call(this) || this).model = H.getEntityClone("/gates_mid")), (t.model.ry = Math.PI), (t.model.y = 0.5 * -t.body.height), t.addChild(t.model), t;
+ }
+ return (
+ Gates_inheritsLoose(GatesMid, i),
+ (GatesMid.prototype.init = function (t, e) {
+ i.prototype.init.call(this, t, e),
+ (this.colM.body.width = 0),
+ (this.colM.body.x = 999),
+ (this.colL.body.width = 60),
+ (this.colL.body.right = 0.5 * -B.laneWidth),
+ (this.colR.body.width = 60),
+ (this.colR.body.left = 0.5 * B.laneWidth);
+ }),
+ GatesMid
+ );
+ })(Ht),
+ gates_left_group_place: (function (i) {
+ function GatesLeft() {
+ var t;
+ return ((t = i.call(this) || this).model = H.getEntityClone("/gates_left")), (t.model.ry = Math.PI), (t.model.y = 0.5 * -t.body.height), t.addChild(t.model), t;
+ }
+ return (
+ Gates_inheritsLoose(GatesLeft, i),
+ (GatesLeft.prototype.init = function (t, e) {
+ i.prototype.init.call(this, t, e),
+ (this.colM.body.width = 0),
+ (this.colM.body.x = 999),
+ (this.colL.body.width = 60),
+ (this.colL.body.right = 1.5 * -B.laneWidth),
+ (this.colR.body.width = 60),
+ (this.colR.body.left = 0.5 * -B.laneWidth);
+ }),
+ GatesLeft
+ );
+ })(Ht),
+ gates_right_group_place: (function (i) {
+ function GatesRight() {
+ var t;
+ return ((t = i.call(this) || this).model = H.getEntityClone("/gates_right")), (t.model.ry = Math.PI), (t.model.y = 0.5 * -t.body.height), t.addChild(t.model), t;
+ }
+ return (
+ Gates_inheritsLoose(GatesRight, i),
+ (GatesRight.prototype.init = function (t, e) {
+ i.prototype.init.call(this, t, e),
+ (this.colM.body.width = 0),
+ (this.colM.body.x = 999),
+ (this.colL.body.width = 60),
+ (this.colL.body.right = 0.5 * B.laneWidth),
+ (this.colR.body.width = 60),
+ (this.colR.body.left = 1.5 * B.laneWidth);
+ }),
+ GatesRight
+ );
+ })(Ht),
+ gates_sides_group_place: Vt,
+ };
+
+ function StationPlatform_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ Ht.factory = function (t, e) {
+ var i = qt[e.name],
+ n = t.game.pool.get(i);
+ n.init(t, e), t.game.addChild(n);
+ };
+ var Wt = (function (e) {
+ function StationPlatform() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !0,
+ noView: !0,
+ }),
+ (t.body.width = 80),
+ (t.body.height = 2),
+ (t.body.depth = 2 * B.blockSize),
+ (t.model = H.getEntityClone("station_platforms")),
+ (t.model.ry = Math.PI),
+ (t.model.z = B.blockSize),
+ t.addChild(t.model),
+ t
+ );
+ }
+ return (
+ StationPlatform_inheritsLoose(StationPlatform, e),
+ (StationPlatform.prototype.init = function (t, e, i) {
+ (this.body.back = i), (this.body.x = 0);
+ var n = t.game.pool.get(Zt);
+ n.reset(), (n.body.width = 20), (n.body.height = 9), (n.body.depth = this.body.depth), (n.body.x = -B.laneWidth), (n.body.bottom = 0), (n.body.z = this.body.z), t.game.addChild(n);
+ var o = t.game.pool.get(Zt);
+ o.reset(), (o.body.width = 20), (o.body.height = 9), (o.body.depth = this.body.depth), (o.body.x = B.laneWidth), (o.body.bottom = 0), (o.body.z = this.body.z), t.game.addChild(o);
+ }),
+ StationPlatform
+ );
+ })(v.a),
+ Zt = (function (e) {
+ function StationPart() {
+ var t;
+ return (t = e.call(this) || this).add(it), t;
+ }
+ return (
+ StationPlatform_inheritsLoose(StationPart, e),
+ (StationPart.prototype.reset = function () {
+ this.body.box.size.reset(), this.body.box.center.reset();
+ }),
+ StationPart
+ );
+ })(v.a);
+
+ function StationEnvironment_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ Wt.factory = function (t, e, i) {
+ var n = e.components.Transform.position.z,
+ o = t.game.pool.get(Wt);
+ o.init(t, e, t.z - n), t.game.addChild(o);
+ var s = t.game.pool.get(Wt);
+ s.init(t, e, t.z - n - o.body.depth), t.game.addChild(s);
+ };
+ var Kt = (function (e) {
+ function StationEnvironment() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !1,
+ }),
+ (t.body.width = 80),
+ (t.body.height = 4),
+ (t.body.depth = 4 * B.blockSize),
+ t
+ );
+ }
+ return (
+ StationEnvironment_inheritsLoose(StationEnvironment, e),
+ (StationEnvironment.prototype.init = function (t, e, i) {
+ void 0 === i && (i = !0);
+ var n = e.components.Environment,
+ o = n ? n._blockCount : 4,
+ s = e.components.Transform.position.z,
+ a = t.z - s;
+ t.name.match("short") || (a += 4 * B.blockSize), (this.body.depth = B.blockSize * o), (this.body.x = 0), (this.body.top = 86), (this.body.back = a);
+ var r = t.game.pool.get(Jt);
+ (r.body.z = a), t.game.addChild(r);
+ for (var h = 0.5 * (o - 2), d = 0; d < h; d++) {
+ var l = t.game.pool.get(Qt);
+ (l.body.z = a - B.blockSize - l.body.depth * d), t.game.addChild(l);
+ }
+ var c = t.game.pool.get($t);
+ if (((c.body.z = a - (o - 1) * B.blockSize), t.game.addChild(c), t.setFillersByPosition(this.body.back, this.body.front), i))
+ for (var u = 0.5 * o, p = 0; p < u; p++) {
+ var m = t.game.pool.get(Wt);
+ m.init(t, e, a - m.body.depth * p), t.game.addChild(m);
+ }
+ for (var f = 0.5 * o, g = 0; g < f; g++) {
+ var y = a - g * (2 * B.blockSize);
+ 0 === g
+ ? Nt.spawn(t, {
+ z: y,
+ l: Nt.newGroundShadowStart,
+ m: Nt.newTrackShadowStart,
+ r: Nt.newGroundShadowStart,
+ })
+ : g < f - 1
+ ? Nt.spawn(t, {
+ z: y,
+ l: Nt.newGroundShadowMid,
+ m: Nt.newTrackShadowMid,
+ r: Nt.newGroundShadowMid,
+ })
+ : Nt.spawn(t, {
+ z: y,
+ l: Nt.newGroundShadowEnd,
+ m: Nt.newTrackShadowEnd,
+ r: Nt.newGroundShadowEnd,
+ });
+ }
+ t.setFillersByPosition(this.body.back, this.body.front), t.setFloorsByPosition(this.body.back, this.body.front);
+ }),
+ StationEnvironment
+ );
+ })(v.a),
+ Jt = (function (e) {
+ function StationStart() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !0,
+ noView: !0,
+ }),
+ (t.body.width = 80),
+ (t.body.height = 0),
+ (t.body.depth = B.blockSize),
+ (t.body.bottom = 0),
+ (t.model = H.getEntityClone("/station_start")),
+ (t.model.ry = Math.PI),
+ (t.model.y = 0.5 * -t.body.height),
+ t.addChild(t.model),
+ t
+ );
+ }
+ return StationEnvironment_inheritsLoose(StationStart, e), StationStart;
+ })(v.a),
+ Qt = (function (e) {
+ function StationMid() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !0,
+ noView: !0,
+ }),
+ (t.body.width = 80),
+ (t.body.height = 0),
+ (t.body.depth = 2 * B.blockSize),
+ (t.body.bottom = 0),
+ (t.model = H.getEntityClone("/station_mid")),
+ (t.model.ry = Math.PI),
+ (t.model.y = 0.5 * -t.body.height),
+ t.addChild(t.model),
+ t
+ );
+ }
+ return StationEnvironment_inheritsLoose(StationMid, e), StationMid;
+ })(v.a),
+ $t = (function (e) {
+ function StationEnd() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !0,
+ noView: !0,
+ }),
+ (t.body.width = 80),
+ (t.body.height = 0),
+ (t.body.depth = B.blockSize),
+ (t.body.bottom = 0),
+ (t.model = H.getEntityClone("/station_end")),
+ (t.model.ry = Math.PI),
+ (t.model.y = 0.5 * -t.body.height),
+ t.addChild(t.model),
+ t
+ );
+ }
+ return StationEnvironment_inheritsLoose(StationEnd, e), StationEnd;
+ })(v.a);
+ Kt.match = function (t) {
+ return !!t.components.Environment && 0 <= t.components.Environment._environmentKind._type.split(",").indexOf("Station");
+ };
+ var te = (function (e) {
+ var t, i;
+
+ function StartBag() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !0,
+ }),
+ (t.body.width = 4),
+ (t.body.height = 4),
+ (t.body.depth = 4),
+ (t.model = H.getEntityCloneOpaque("/startScreen_bag/startScreen_bag_base", "props_tex")),
+ (t.model.ry = Math.PI),
+ (t.model.y = -1.3),
+ t.addChild(t.model),
+ t
+ );
+ }
+ return (
+ (i = e),
+ ((t = StartBag).prototype = Object.create(i.prototype)),
+ ((t.prototype.constructor = t).__proto__ = i),
+ (StartBag.prototype.init = function (t, e) {
+ (this.body.x = e.components.Transform.position.x), (this.body.bottom = 0), (this.body.z = t.z - e.components.Transform.position.z);
+ }),
+ StartBag
+ );
+ })(v.a);
+
+ function Obstacle_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ var ee = (function (e) {
+ function Obstacle() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ ghost: !0,
+ }),
+ (t.body.width = 18),
+ (t.body.height = 14),
+ (t.body.depth = 1),
+ (t.model = null),
+ t
+ );
+ }
+ return (
+ Obstacle_inheritsLoose(Obstacle, e),
+ (Obstacle.prototype.init = function (t, e) {
+ (this.model.ry = Math.PI), (this.model.z = -4), this.addChild(this.model);
+ }),
+ Obstacle
+ );
+ })(v.a),
+ ie = [
+ (function (i) {
+ function ObstacleDumpster() {
+ var t;
+ return ((t = i.call(this) || this).body.soft = !1), (t.model = H.getEntityClone("dumpster")), t;
+ }
+ return (
+ Obstacle_inheritsLoose(ObstacleDumpster, i),
+ (ObstacleDumpster.prototype.init = function (t, e) {
+ i.prototype.init.call(this, t, e), (this.body.height = 14), (this.model.y = 0.5 * -this.body.height);
+ }),
+ ObstacleDumpster
+ );
+ })(ee),
+ (function (i) {
+ function ObstacleBush() {
+ var t;
+ return ((t = i.call(this) || this).body.soft = !0), (t.model = H.getEntityClone("bush_1")), t;
+ }
+ return (
+ Obstacle_inheritsLoose(ObstacleBush, i),
+ (ObstacleBush.prototype.init = function (t, e) {
+ i.prototype.init.call(this, t, e), (this.body.height = 12), (this.model.y = 0.5 * -this.body.height);
+ }),
+ ObstacleBush
+ );
+ })(ee),
+ ];
+ (ee.match = function (t) {
+ return t.name.match(/obstacle_group/);
+ }),
+ (ee.factory = function (t, e, i) {
+ var n = L.pick.apply(L, ie),
+ o = t.game.pool.get(n),
+ s = e.components.Transform.position.x,
+ a = e.components.Transform.position.z;
+ (o.body.z = t.z - a), (o.body.x = s), (o.body.bottom = 0), i.offsetX && (o.body.x = i.offsetX), i.flip && (o.body.x *= -1), o.init(t, e), t.game.addChild(o);
+ });
+ var ne = (function (e) {
+ var t, i;
+
+ function Pillar() {
+ var t;
+ return (t = e.call(this) || this).add(it), (t.body.width = 9), (t.body.height = 80), (t.body.depth = 9), (t.model = H.getEntityClone("pillar")), (t.model.ry = Math.PI), (t.model.y = 0.5 * -t.body.height), t.addChild(t.model), t;
+ }
+ return (
+ (i = e),
+ ((t = Pillar).prototype = Object.create(i.prototype)),
+ ((t.prototype.constructor = t).__proto__ = i),
+ (Pillar.prototype.init = function (t, e) {
+ this.addChild(this.model);
+ }),
+ Pillar
+ );
+ })(v.a);
+
+ function PillarsEnvironment_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ (ne.factory = function (t, e, i) {
+ var n = t.game.pool.get(ne),
+ o = e.components.Transform.position.x,
+ s = e.components.Transform.position.z;
+ (n.body.z = t.z - s), (n.body.x = o), (n.body.bottom = 0), i.offsetX && (n.body.x = i.offsetX), i.flip && (n.body.x *= -1), n.init(t, e), t.game.addChild(n);
+ }),
+ (ne.match = function (t) {
+ return t.name.match(/pillar_group_place/);
+ });
+ var oe = (function (e) {
+ function PillarsEnvironment() {
+ var t;
+ return (t = e.call(this) || this).add(it), (t.body.width = 80), (t.body.height = 20), (t.body.depth = B.blockSize), (t.body.top = 90), t;
+ }
+ return (
+ PillarsEnvironment_inheritsLoose(PillarsEnvironment, e),
+ (PillarsEnvironment.prototype.init = function (t, e) {
+ var i = e.components.Transform.position.z,
+ n = e.components.Environment._blockCount;
+ (this.body.x = 0), (this.body.depth = B.blockSize * n), (this.body.back = t.z - i);
+ var o = t.game.pool.get(se);
+ (o.body.back = this.body.back),
+ t.game.addChild(o),
+ Nt.spawn(t, {
+ z: o.body.back,
+ l: Nt.newTrackShadowShortStart,
+ m: Nt.newGroundShadowShortStart,
+ r: Nt.newTrackShadowShortStart,
+ });
+ for (var s = 0; s < n - 2; s++) {
+ var a = t.game.pool.get(ae);
+ (a.body.back = o.body.back - B.blockSize * (s + 1)),
+ t.game.addChild(a),
+ Nt.spawn(t, {
+ z: a.body.back,
+ l: Nt.newTrackShadowMid,
+ m: Nt.newGroundShadowMid,
+ r: Nt.newTrackShadowMid,
+ });
+ }
+ var r = t.game.pool.get(re);
+ (r.body.back = o.body.back - B.blockSize * (n - 1)),
+ t.game.addChild(r),
+ Nt.spawn(t, {
+ z: r.body.back,
+ l: Nt.newTrackShadowShortEnd,
+ m: Nt.newGroundShadowShortEnd,
+ r: Nt.newTrackShadowShortEnd,
+ });
+ }),
+ PillarsEnvironment
+ );
+ })(v.a),
+ se = (function (e) {
+ function PillarsEnvironmentStart() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !0,
+ noView: !0,
+ }),
+ (t.body.width = 80),
+ (t.body.height = 1),
+ (t.body.depth = B.blockSize),
+ (t.body.bottom = 0),
+ (t.model = H.getEntityClone("pillars_start")),
+ (t.model.ry = Math.PI),
+ (t.model.z = 0.5 * t.body.depth),
+ (t.model.y = 0.5 * -t.body.height),
+ t.addChild(t.model),
+ t
+ );
+ }
+ return PillarsEnvironment_inheritsLoose(PillarsEnvironmentStart, e), PillarsEnvironmentStart;
+ })(v.a),
+ ae = (function (e) {
+ function PillarsEnvironmentMid() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !0,
+ noView: !0,
+ }),
+ (t.body.width = 80),
+ (t.body.height = 1),
+ (t.body.depth = B.blockSize),
+ (t.body.bottom = 0),
+ (t.model = H.getEntityClone("pillars_mid")),
+ (t.model.ry = Math.PI),
+ (t.model.z = 0.5 * t.body.depth),
+ (t.model.y = 0.5 * -t.body.height),
+ t.addChild(t.model),
+ t
+ );
+ }
+ return PillarsEnvironment_inheritsLoose(PillarsEnvironmentMid, e), PillarsEnvironmentMid;
+ })(v.a),
+ re = (function (e) {
+ function PillarsEnvironmentEnd() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !0,
+ noView: !0,
+ }),
+ (t.body.width = 80),
+ (t.body.height = 1),
+ (t.body.depth = B.blockSize),
+ (t.body.bottom = 0),
+ (t.model = H.getEntityClone("pillars_end")),
+ (t.model.ry = Math.PI),
+ (t.model.z = 0.5 * t.body.depth),
+ (t.model.y = 0.5 * -t.body.height),
+ t.addChild(t.model),
+ t
+ );
+ }
+ return PillarsEnvironment_inheritsLoose(PillarsEnvironmentEnd, e), PillarsEnvironmentEnd;
+ })(v.a);
+
+ function TubeEnvironment_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ oe.match = function (t) {
+ return !!t.components.Environment && 0 <= t.components.Environment._environmentKind._type.split(",").indexOf("Pillars");
+ };
+ var he = (function (e) {
+ function TubeEnvironment() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !1,
+ }),
+ (t.body.width = 80),
+ (t.body.height = 16),
+ (t.body.depth = B.blockSize),
+ (t.body.top = 88),
+ t
+ );
+ }
+ return (
+ TubeEnvironment_inheritsLoose(TubeEnvironment, e),
+ (TubeEnvironment.prototype.init = function (t, e) {
+ var i = e.components.Transform.position.z;
+ t.game.route.hasTube = !0;
+ var n = t.blocks;
+ e.components.Environment && (n = e.components.Environment._blockCount), (this.body.x = 0), (this.body.depth = B.blockSize * n), (this.body.back = t.z - i);
+ for (var o = 0.5 * n, s = 0; s < o; s++) {
+ var a = t.game.pool.get(de);
+ (a.body.back = this.body.back - 2 * B.blockSize * s), t.game.addChild(a);
+ var r = a.body.back;
+ 0 === s
+ ? Nt.spawn(t, {
+ z: r,
+ l: Nt.newTrackShadowStart,
+ })
+ : s < o - 1
+ ? Nt.spawn(t, {
+ z: r,
+ l: Nt.newTrackShadowMid,
+ })
+ : Nt.spawn(t, {
+ z: r,
+ l: Nt.newTrackShadowEnd,
+ });
+ }
+ }),
+ TubeEnvironment
+ );
+ })(v.a),
+ de = (function (e) {
+ function TubeEnvironmentBlock() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !0,
+ noView: !0,
+ }),
+ (t.body.width = 80),
+ (t.body.height = 0),
+ (t.body.depth = 2 * B.blockSize),
+ (t.body.bottom = 0),
+ (t.model = H.getEntityClone("tube")),
+ (t.model.ry = Math.PI),
+ (t.model.z = 0.5 * t.body.depth),
+ (t.model.y = 0.5 * -t.body.height),
+ (t.model.view3d.state.culling = !1),
+ t.addChild(t.model),
+ "1103_seoul" === B.env &&
+ ((t.model001 = H.getEntityClone("tube001")),
+ (t.model001.ry = t.model.ry),
+ (t.model001.z = t.model.z),
+ (t.model001.y = t.model.y),
+ (t.model001.view3d.state.blend = !0),
+ (t.model001.view3d.material.opacity = 0.7),
+ (t.model001.view3d.state.culling = !1),
+ t.addChild(t.model001),
+ (t.model002 = H.getEntityClone("tube002")),
+ (t.model002.ry = t.model.ry),
+ (t.model002.z = t.model.z),
+ (t.model002.y = t.model.y),
+ (t.model002.view3d.state.culling = !1),
+ t.addChild(t.model002)),
+ t
+ );
+ }
+ return TubeEnvironment_inheritsLoose(TubeEnvironmentBlock, e), TubeEnvironmentBlock;
+ })(v.a);
+ (he.match = function (t) {
+ return !!t.components.Environment && 0 <= t.components.Environment._environmentKind._type.split(",").indexOf("Tube");
+ }),
+ (he.factory = function (t, e, i) {
+ t.game.route.setSpawnDistance("tube", 1e3);
+ var n = t.game.pool.get(he);
+ return n.init(t, e, i), t.game.addChild(n), n;
+ });
+ var le = (function (e) {
+ var t, i;
+
+ function Trigger() {
+ var t;
+ return ((t = e.call(this) || this).tutorialTrigger = !0), t.add(it), (t.body.width = 60), (t.body.height = 30), (t.body.depth = 1), (t.body.trigger = !0), (t.view = H.box(t.body.box)), t;
+ }
+ (i = e), ((t = Trigger).prototype = Object.create(i.prototype)), ((t.prototype.constructor = t).__proto__ = i);
+ var n = Trigger.prototype;
+ return (
+ (n.reset = function () {}),
+ (n.init = function (t, e) {
+ this.type = e.name.split("_").pop();
+ }),
+ Trigger
+ );
+ })(v.a);
+ (le.match = function (t) {
+ return t.name.match(/Trigger_/);
+ }),
+ (le.factory = function (t, e, i) {
+ var n = t.game.pool.get(le),
+ o = e.components.Transform.position.x,
+ s = e.components.Transform.position.z;
+ (n.body.z = t.z - s), (n.body.x = o), (n.body.bottom = 0), i.offsetX && (n.body.x = i.offsetX), i.flip && (n.body.x *= -1), n.init(t, e), t.game.addChild(n);
+ });
+ var ce = (function (e) {
+ var t, i;
+
+ function Checkpoint() {
+ var t;
+ return ((t = e.call(this) || this).checkpoint = !0), t.add(it), (t.body.width = 2), (t.body.height = 20), (t.body.depth = 2), (t.body.deco = !0), (t.view = H.box(t.body.box)), t;
+ }
+ (i = e), ((t = Checkpoint).prototype = Object.create(i.prototype)), ((t.prototype.constructor = t).__proto__ = i);
+ var n = Checkpoint.prototype;
+ return (n.reset = function () {}), (n.init = function (t, e) {}), Checkpoint;
+ })(v.a);
+ (ce.match = function (t) {
+ return t.name.match(/checkpoint_/);
+ }),
+ (ce.factory = function (t, e, i) {
+ var n = t.game.pool.get(ce),
+ o = e.components.Transform.position.x,
+ s = e.components.Transform.position.z;
+ return (n.body.z = t.z - s), (n.body.x = o), (n.body.bottom = 0), i.offsetX && (n.body.x = i.offsetX), i.flip && (n.body.x *= -1), n.init(t, e), t.game.addChild(n), n;
+ });
+ var ue = (function () {
+ function Node() {}
+ return (
+ (Node.getEntityClass = function (t) {
+ return t.name.match(/train_ramp/)
+ ? kt
+ : t.name.match(/trains_(\d)_/)
+ ? mt
+ : t.name.match(/train_sub_(\d)_/)
+ ? mt
+ : t.name.match(/lightSignal/)
+ ? Ct
+ : t.name.match(/blocker/)
+ ? _t
+ : pt.match(t)
+ ? pt
+ : Tt.match(t)
+ ? Tt
+ : t.name.match(/gates_(.*?)_group_place/)
+ ? Ht
+ : t.name.match(/bag_place/)
+ ? te
+ : ee.match(t)
+ ? ee
+ : ne.match(t)
+ ? ne
+ : Kt.match(t)
+ ? Kt
+ : oe.match(t)
+ ? oe
+ : he.match(t)
+ ? he
+ : le.match(t)
+ ? le
+ : ce.match(t)
+ ? ce
+ : null;
+ }),
+ (Node.comp = function (t, e) {
+ return t.components[e];
+ }),
+ (Node.get = function (t, e, i) {
+ if ((void 0 === i && (i = null), !t)) return i;
+ "string" == typeof e && (e = e.split("."));
+ var n = e.shift();
+ return e.length ? this.get(t[n], e, i) : void 0 !== t[n] ? t[n] : i;
+ }),
+ (Node.environment = function (t) {
+ if (t.components.Environment) return t;
+ for (var e = t.children.length; e--; ) {
+ var i = this.environment(t.children[e]);
+ if (i) return i;
+ }
+ return null;
+ }),
+ (Node.environmentType = function (t) {
+ return t.components.Environment ? t.components.Environment._environmentKind._type.split(",") : null;
+ }),
+ (Node.environmentKinds = function (t) {
+ var e = t.components.RouteChunk._limitedAllowedEnvironmentKinds,
+ i = Random.item(e)._type.split(",");
+ this.environment = i || [];
+ }),
+ Node
+ );
+ })();
+ var pe = (function (e) {
+ var t, i;
+
+ function Cube() {
+ var t;
+ return (t = e.call(this) || this).add(it), t;
+ }
+ return (
+ (i = e),
+ ((t = Cube).prototype = Object.create(i.prototype)),
+ ((t.prototype.constructor = t).__proto__ = i),
+ (Cube.prototype.reset = function () {
+ (this.body.deco = !1), this.body.box.size.reset(), this.body.box.center.reset();
+ }),
+ Cube
+ );
+ })(v.a);
+ var me = (function (e) {
+ var t, i;
+
+ function Logo() {
+ var t;
+ return ((t = e.call(this) || this).model = H.getEntityCloneBlend("/train_start", "train_start", 0.999)), (t.model.ry = Math.PI), t.addChild(t.model), t;
+ }
+ return (i = e), ((t = Logo).prototype = Object.create(i.prototype)), ((t.prototype.constructor = t).__proto__ = i), Logo;
+ })(v.a),
+ fe = null,
+ ge = (function () {
+ function Chunk() {
+ this.reset();
+ }
+ var t = Chunk.prototype;
+ return (
+ (t.reset = function () {
+ (this.node = null), (this.section = "");
+ }),
+ (t.init = function (t, e, i, n) {
+ (this.game = t),
+ (this.node = i),
+ (this.name = this.node.name),
+ (this.entities = []),
+ (this.blocks = ue.get(i, "components.RouteChunk._blockCount", 0)),
+ (this.length = this.blocks * B.blockSize),
+ (this.z = -e),
+ (this.start = e),
+ (this.middle = this.start + 0.5 * this.length),
+ (this.end = this.start + this.length),
+ (this.offset = 0),
+ (this.index = n),
+ (this.fillers = {}),
+ (this.floors = {}),
+ this.game.environment.setup(this),
+ this.mount(this.node, this, {}),
+ this.game.environment.mount(this),
+ B.blocks && this.addChunkDebugMarks(),
+ "intro" === this.name && this.mountIntro();
+ }),
+ (t.mountIntro = function () {
+ fe || (fe = new me()), (fe.x = -20), (fe.y = 0), (fe.z = 30), this.game.addChild(fe), Nt.mount(this);
+ }),
+ (t.defineEnvironment = function () {
+ if (((this.envNode = ue.environment(this.node)), (this.environment = this.envNode ? ue.environmentType(this.envNode) : null), !this.environment))
+ if (this.node.name.match(/tunnel/)) this.environment = ["Gates", "All"];
+ else if (this.node.name.match(/epic/)) this.environment = ["Epic", "All"];
+ else if (this.node.components.RouteChunk) {
+ var t = this.node.components.RouteChunk._limitedAllowedEnvironmentKinds,
+ e = t.length ? L.item(t)._type.split(",") : ["Fillers", "All"];
+ this.environment = e || [];
+ } else this.environment = [];
+ (this.envTube = !1), (this.envStation = !1), (this.envEpic = !1), (this.envGates = !1), (this.envEmpty = !1);
+ var i = this.lastTube;
+ B.forceTube || (0 <= this.environment.indexOf("Tube") && this.z < i)
+ ? ((this.envTube = !0), (this.lastTube = this.z))
+ : 0 <= this.environment.indexOf("Station")
+ ? (this.envStation = !0)
+ : 0 <= this.environment.indexOf("Epic")
+ ? (this.envEpic = !0)
+ : 0 <= this.environment.indexOf("Gates")
+ ? (this.envGates = !0)
+ : 0 <= this.environment.indexOf("Empty") && (this.envEmpty = !0);
+ }),
+ (t.mount = function (t, e) {
+ if ("intro" !== this.name || !t.name.match("lightSignal") || B.loadAll)
+ if ((void 0 === (e = Object.assign({}, e || {})).flip && (e.flip = 0), void 0 === e.offsetX && (e.offsetX = null), ue.comp(t, "Randomizer"))) {
+ var i = L.pick.apply(L, t.children);
+ this.mount(i, e);
+ } else {
+ if (ue.comp(t, "RandomizeOffset")) {
+ var n = t.components.RandomizeOffset.randomOffsets.left,
+ o = t.components.RandomizeOffset.randomOffsets.mid,
+ s = t.components.RandomizeOffset.randomOffsets.right,
+ a = [];
+ n && a.push(-20), o && a.push(0), s && a.push(20), a.length && (e.offsetX = L.pick.apply(L, a));
+ }
+ ue.comp(t, "Mirror") && (e.flip = L.pick(0, 1));
+ var r = ue.getEntityClass(t);
+ if (r) {
+ var h = null;
+ if (
+ (r.factory ? (h = r.factory(this, t, e)) : ((h = this.game.pool.get(r)).init(this, t, e), this.game.addChild(h)),
+ h && h.checkpoint && (this.checkpoints || (this.checkpoints = []), this.checkpoints.push(h)),
+ h && ue.comp(t, "Environment"))
+ ) {
+ for (var d = -h.body.back - this.start, l = -h.body.front - this.start, c = 2 * B.blockSize, u = Math.round(d / c), p = Math.round(l / c), m = u; m < p; m++) this.fillers[m] = !0;
+ for (var f = u; f < p; f++) this.floors[f] = !0;
+ }
+ }
+ if (t.children) for (var g = t.children.length; g--; ) this.mount(t.children[g], e);
+ }
+ }),
+ (t.setFillersByPosition = function (t, e, i) {
+ void 0 === i && (i = !0);
+ for (var n = -t - this.start, o = -e - this.start, s = 2 * B.blockSize, a = Math.round(n / s), r = Math.round(o / s), h = a; h < r; h++) this.fillers[h] = !0;
+ }),
+ (t.setFloorsByPosition = function (t, e, i) {
+ void 0 === i && (i = !0);
+ for (var n = -t - this.start, o = -e - this.start, s = 2 * B.blockSize, a = Math.round(n / s), r = Math.round(o / s), h = a; h < r; h++) this.floors[h] = !0;
+ }),
+ (t.addChunkDebugMarks = function () {
+ for (var t = this.blocks; t--; ) {
+ var e = this.game.pool.get(pe);
+ (e.body.deco = !0), (e.body.width = 80), (e.body.height = t ? 2 : 20), (e.body.depth = 0.1), (e.body.x = 0), (e.body.bottom = 0), (e.body.z = -this.start - t * B.blockSize), this.game.addChild(e);
+ }
+ }),
+ (t.clean = function () {
+ for (var t = this.entities.length; t--; ) this.game.removeChild(this.entities[t]);
+ this.entities.length = 0;
+ }),
+ (t.triggerEnter = function () {
+ for (var t = this.entities.length; t--; ) {
+ var e = this.entities[t];
+ e.triggerEnter && e.triggerEnter();
+ }
+ }),
+ (t.triggerExit = function () {}),
+ (t.getLastCheckpointByPosition = function (t) {
+ if (!this.checkpoints) return null;
+ for (var e = null, i = this.checkpoints.length; i--; ) {
+ var n = this.checkpoints[i];
+ n.body.z > t && (e = n);
+ }
+ return e || this.checkpoints[0];
+ }),
+ Chunk
+ );
+ })(),
+ ye = i(127),
+ ve = null,
+ _e = null,
+ be = null,
+ we = (function () {
+ function Data() {}
+ return (
+ (Data.init = function (t) {
+ be = t;
+ }),
+ (Data.sectionMap = function () {
+ if (_e) return _e;
+ return (
+ (_e = {}),
+ (function extract(t) {
+ if (void 0 !== t.name) _e[t.name] = t;
+ else for (var e in t) extract(t[e]);
+ })(ye),
+ _e
+ );
+ }),
+ (Data.section = function (t) {
+ t = (t = t.replace("routeSection_", "")).replace("route_section_", "");
+ var e = this.sectionMap(),
+ i = e[t] || e["route_section_" + t] || e["routeSection_" + t];
+ if (!i) throw "Section data not found: " + t;
+ return i;
+ }),
+ (Data.sectionClone = function (t) {
+ var e = this.sectionMap();
+ if (!e[t]) throw "Section data not found: " + t;
+ var i = e[t];
+ return {
+ name: i.name,
+ start: i.start.slice(0),
+ mid: i.start.slice(0),
+ end: i.start.slice(0),
+ };
+ }),
+ (Data.chunkMap = function (t) {
+ console.log("chunkMap " + t);
+ if (ve && !t) return ve;
+ ve = {};
+ var e = {};
+ for (var i in be) i.match("chunks_") && (e[i] = be[i].data);
+ return (
+ (function extract(t, e) {
+ console.log(be);
+ if (!t || !e--) return;
+ if ("intro" === t.name) ve[t.name] = t;
+ else if (t.components && t.components.RouteChunk) {
+ var i = t.components.RouteChunk._reportedName || t.name;
+ ve[i] = t;
+ } else if (t.children) for (var n in t.children) extract(t.children[n], e);
+ else for (var o in t) extract(t[o], e);
+ })(e, 5),
+ ve
+ );
+ }),
+ (Data.chunk = function (t) {
+ t = (t = t.replace("routeChunk_", "")).replace("route_chunk_", "");
+ var e = this.chunkMap(),
+ i = e[t] || e["routeChunk_" + t] || e["route_chunk_" + t] || e["default_" + t];
+ if (!i) throw "Chunk data not found: " + t;
+ return (i.__name = t), i;
+ }),
+ (Data.refreshCache = function () {
+ ve = this.chunkMap(!0);
+ }),
+ Data
+ );
+ })();
+ var ke = (function (n) {
+ var t, e;
+
+ function LevelSystem(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).entities = []),
+ (i.chunks = []),
+ (i.currentChunk = null),
+ (i.game = t.game),
+ i.game.onReset.add(
+ (function (t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ })(i)
+ ),
+ (i.sequence = []),
+ (i.queued = []),
+ (i.onEnterChunk = new et.a("onEnterChunk", 1)),
+ (i.onExitChunk = new et.a("onExitChunk", 1)),
+ (i.onEnterTutorial = new et.a("onEnterTutorial")),
+ (i.onExitTutorial = new et.a("onExitTutorial")),
+ (i.countRemoveObsolete = 2),
+ (i.countUpdate = 0),
+ i
+ );
+ }
+ (e = n), ((t = LevelSystem).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = LevelSystem.prototype;
+ return (
+ (i.reset = function () {
+ (this.chunks = []), (this.sequence = []), (this.queued = []), (this.nextPosition = 0);
+ var t = this.entities.slice(0);
+ (this.currentChunk = this.placeNextChunk("intro")), this.game.forceUpdate(), this.removeAllEntities(t);
+ }),
+ (i.entityAddedToGame = function (t) {
+ !t._CLASS_ID || t.player || t.follower || 0 <= this.entities.indexOf(t) || this._addEntity(t);
+ }),
+ (i.entityRemovedFromGame = function (t) {
+ !t._CLASS_ID || t.player || t.follower || t.particle || this.entities.indexOf(t) < 0 || this._removeEntity(t);
+ }),
+ (i._addEntity = function (t) {
+ t.player || t.follower || this.entities.push(t);
+ }),
+ (i._removeEntity = function (t, e) {
+ t.player || t.follower || t.particle || (void 0 === e && (e = this.entities.indexOf(t)), (t.z = 99999), t.body && (t.body.z = t.z), this.entities.splice(e, 1), this.game.removeChild(t), this.game.pool["return"](t));
+ }),
+ (i.postupdate = function () {
+ this.game.state === pn.RUNNING && (0 < this.countRemoveObsolete-- || (this.removeObsoleteEntities(), (this.countRemoveObsolete = 5)));
+ }),
+ (i.preupdate = function () {
+ if ((this.game.state === pn.RUNNING || this.queued.length) && !(0 < this.countUpdate--)) {
+ this.countRemoveObsolete = 5;
+ var t = this.chunks[this.game.stats.chunkIndex];
+ t || this.game.crash("No chunk found at current index:", this.game.stats.chunkIndex),
+ t !== this.currentChunk &&
+ (this.currentChunk && (this.isTutorial() && this.onExitTutorial.dispatch(), this.onExitChunk.dispatch(this.currentChunk.name)),
+ (this.currentChunk = t),
+ this.onEnterChunk.dispatch(this.currentChunk.name),
+ this.isTutorial() && this.onEnterTutorial.dispatch()),
+ this.game.stats.setCurrentChunk(t),
+ this.game.stats.distance > t.end && (this.game.stats.chunkIndex += 1),
+ this.placeChunks();
+ }
+ }),
+ (i.placeChunks = function () {
+ console.log("placeChunks");
+ if (this.queued && this.queued.length) {
+ for (var t = this.queued.length; t--; ) this.placeNextChunk(this.queued[t]);
+ this.queued.length = 0;
+ }
+ for (var e = 20, i = this.game.stats.distance + B.visibleMaxDistance; this.nextPosition < i; ) e-- || this.game.crash("Too many chunks placed at same time"), this.placeNextChunk(this.name);
+ }),
+ (i.nextInSequence = function () {
+ this.sequence.length || (this.sequence = this.game.route.getSequence());
+ var t = this.sequence.shift(),
+ e = "string" == typeof t ? t : L.item(e);
+ return we.chunk(e);
+ }),
+ (i.queueNextChunk = function (t) {
+ var e = t ? we.chunk(t) : this.nextInSequence();
+ this.queued.unshift(e.__name);
+ }),
+ (i.placeNextChunk = function (t) {
+ var e = new ge(),
+ i = t ? we.chunk(t) : this.nextInSequence();
+ if (!i) throw new Error("Chunk not found");
+ return e.init(this.game, this.nextPosition, i, this.chunks.length), this.chunks.push(e), (this.nextPosition += e.length), e;
+ }),
+ (i.removeObsoleteEntities = function () {
+ if (!this.isTutorial())
+ for (var t = this.entities.length; t--; ) {
+ var e = this.entities[t],
+ i = e.body ? e.body.front : e.z,
+ n = this.game.stats.z - B.visibleMinDistance;
+ (!e.active || n < i) && this._removeEntity(e, t);
+ }
+ }),
+ (i.removeAllEntities = function (t) {
+ t || (t = this.entities);
+ for (var e = t.length; e--; ) this._removeEntity(t[e], e);
+ }),
+ (i.reshuffle = function (t) {
+ void 0 === t && (t = !1),
+ this.game.route.resetSpawns(),
+ (this.currentChunk = null),
+ this.game.physics.reset(),
+ this.removeAllEntities(this.entities),
+ (this.nextPosition = this.game.stats.distance - 10),
+ (this.currentChunk = this.placeNextChunk("default_fallback")),
+ (this.currentChunk = this.placeNextChunk("default_fallback")),
+ t && this.game.update(1);
+ }),
+ (i.isTutorial = function () {
+ return !(!this.currentChunk || "routeChunk_default_tutorial" !== this.currentChunk.name) && this.game.stats.distance < this.currentChunk.end - 300;
+ }),
+ (i.setSafeLanding = function (t) {
+ for (; this.nextPosition <= t; ) this.placeNextChunk();
+ var e = this.nextPosition;
+ return this.placeNextChunk("jetpack_landing"), e;
+ }),
+ (i.removeChunksAhead = function (t) {
+ for (var e = this.chunks.length; e--; ) {
+ var i = this.chunks[e];
+ i.start > t && (this.chunks.splice(e, 1), (this.nextPosition = i.start));
+ }
+ }),
+ (i.removeEntitiesAhead = function (t) {
+ for (var e = this.entities.length; e--; ) {
+ var i = this.entities[e];
+ t < -(i.body ? i.body.back : i.z) && this._removeEntity(i, e);
+ }
+ }),
+ LevelSystem
+ );
+ })(f.a);
+ var xe = (function (n) {
+ var t, e;
+
+ function PhysicsSystem(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).collision = new $()),
+ t.game.onReset.add(
+ (function (t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ })(i)
+ ),
+ i.reset(),
+ i
+ );
+ }
+ (e = n), ((t = PhysicsSystem).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = PhysicsSystem.prototype;
+ return (
+ (i.reset = function () {
+ (this.stats = {}), (this.entities = []), (this._hasReset = !0);
+ }),
+ (i.entityAddedToGame = function (t) {
+ !t.body || t.body.deco || t.player || 0 <= this.entities.indexOf(t) || this.entities.push(t);
+ }),
+ (i.entityRemovedFromGame = function (t) {
+ if (t.body && !t.body.deco && !t.player) {
+ var e = this.entities.indexOf(t);
+ e < 0 || this.entities.splice(e, 1);
+ }
+ }),
+ (i.postupdate = function (t) {
+ var e = this.game.hero;
+ if (this.game.state === pn.RUNNING || e.player.dead) {
+ void 0 === t && (t = this.game.delta), e.player.dead || ((e.body.groundBefore = e.body.ground), (e.body.ground = 0));
+ var i = Math.ceil(t),
+ n = Math.ceil(Math.abs(e.body.velocity.z)),
+ o = B.fixedPhysicsSteps || V.clamp(i + n, 1, 40),
+ s = t / o;
+ B.debug && ((this.stats.delta = t), (this.stats.steps = o), (this.stats.stepsDelta = s), (this.stats.bodies = this.entities.length), (this.stats.collidables = 0));
+ for (var a = o; a-- && !this._hasReset; ) {
+ e.body.move(s);
+ for (var r = this.entities.length; r--; ) {
+ var h = this.entities[r];
+ if (h && h.active && h !== e) {
+ if ((h.body.movable && h.body.move(s), this._hasReset)) break;
+ if (!(h.body.back < e.body.z - 10 || h.body.front > e.body.z + 5)) {
+ if (this.game.state !== pn.RUNNING) break;
+ if (e.player.dead) break;
+ if ((B.debug && (this.stats.collidables += 1), e.body.sensor && !h.body.ghost && !h.body.trigger)) {
+ var d = e.body.sensor.hitTest(h.body.box);
+ d && this.resolveGroundSensorHit(e, h, d);
+ }
+ var l = e.body.box.hitTest(h.body.box);
+ if ((l && !h.body.trigger && this.resolveHit(e, h, l), h.body.trigger)) {
+ var c = e.body.colliding.indexOf(h.body);
+ !l && 0 <= c && (e.body.colliding.splice(c, 1), e.body.triggerExit(h.body)), l && c < 0 && (e.body.colliding.push(h.body), e.body.triggerEnter(h.body));
+ }
+ }
+ }
+ }
+ }
+ e.body.ground < e.body.groundBefore && (e.body.groundChangeTolerance = 8), (this._hasReset = !1);
+ }
+ }),
+ (i.resolve = function (t) {
+ if (!this.isHeroDead())
+ for (var e = this.entities.length; e--; ) {
+ var i = this.entities[e];
+ if (i && i.active && !(i.body.back < t.body.z - 10 || i.body.front > t.body.z + 5)) {
+ if ((B.debug && (this.stats.collidables += 1), t.body.sensor && !i.body.ghost && !i.body.trigger)) {
+ var n = t.body.sensor.hitTest(i.body.box);
+ n && this.resolveGroundSensorHit(t, i, n);
+ }
+ var o = t.body.box.hitTest(i.body.box);
+ if ((o && !i.body.trigger && this.resolveHit(t, i, o), i.body.trigger)) {
+ var s = t.body.colliding.indexOf(i.body);
+ !o && 0 <= s && (t.body.colliding.splice(s, 1), t.body.triggerExit(i.body)), o && s < 0 && (t.body.colliding.push(i.body), t.body.triggerEnter(i.body));
+ }
+ }
+ }
+ }),
+ (i.resolveHit = function (t, e, i) {
+ if (!this.isHeroDead())
+ if (e.collectible) e.collectible.collect();
+ else if (!t.body.ghost) {
+ var n = t.body,
+ o = e.body;
+ if ((this.collision.reset(), (this.collision.act = n), (this.collision.pas = o), this.collision.hit.copy(i), e.ramp)) if (n.right >= o.left && n.left <= o.right) return;
+ var s = o.movable ? o.origin : o.box;
+ n.y > o.top && i.height <= 6 && -1 < n.velocity.y
+ ? ((n.bottom = o.top + 0.1), (this.collision.flags = this.collision.flags | $.BOTTOM), 2 < i.height && (this.collision.flags = this.collision.flags | $.SLOPE), n.origin.copy(n.box))
+ : n.origin.bottom > s.top
+ ? ((n.bottom = o.top + 0.1), (this.collision.flags = this.collision.flags | $.BOTTOM), n.origin.copy(n.box))
+ : n.origin.left >= s.right
+ ? ((n.box.left = o.box.right + 0.1), (this.collision.flags = this.collision.flags | $.LEFT), n.origin.copy(n.box))
+ : n.origin.right <= s.left
+ ? ((n.box.right = o.box.left - 0.1), (this.collision.flags = this.collision.flags | $.RIGHT), n.origin.copy(n.box))
+ : n.origin.front >= s.back
+ ? ((n.box.front = o.box.back + 0.1), (this.collision.flags = this.collision.flags | $.FRONT), n.origin.copy(n.box))
+ : n.origin.top < s.bottom && ((n.box.top = o.box.bottom - 0.1), (this.collision.flags = this.collision.flags | $.TOP), n.origin.copy(n.box)),
+ this.collision.flags && n.collisionEnter(o, this.collision);
+ }
+ }),
+ (i.resolveGroundSensorHit = function (t, e, i) {
+ if (!this.isHeroDead())
+ if (t.body.ghost) t.body.ground = 0;
+ else {
+ var n = t.body,
+ o = e.body,
+ s = n.ground;
+ if (e.ramp) {
+ var a = o.box.size.y,
+ r = o.box.size.z;
+ s = a * ((o.back - n.front) / r) + 0.11;
+ } else s = o.top + 0.11;
+ s >= n.ground && (n.ground = s);
+ }
+ }),
+ (i.canUpdate = function () {
+ return this.game.state === pn.RUNNING;
+ }),
+ (i.isHeroDead = function () {
+ return this.game.hero.player.dead;
+ }),
+ PhysicsSystem
+ );
+ })(f.a),
+ Ce = (function () {
+ function Graph() {}
+ return (
+ (Graph.rect = function (t) {
+ return t.image ? this.rectImg(t) : this.rectColor(t);
+ }),
+ (Graph.rectColor = function (t) {
+ void 0 === t && (t = {});
+ var e = Object.assign(
+ {
+ name: "rectColor",
+ w: 120,
+ h: 120,
+ x: 0,
+ y: 0,
+ round: 0,
+ alpha: 1,
+ color: 3246014,
+ },
+ t
+ ),
+ i = new c.Graphics();
+ i.beginFill(e.color, e.alpha);
+ var n = -e.w / 2 + e.x,
+ o = -e.h / 2 + e.y;
+ return e.round ? i.drawRoundedRect(n, o, e.w, e.h, e.round) : i.drawRect(n, o, e.w, e.h), i.endFill(), i;
+ }),
+ (Graph.rectImg = function (t) {
+ void 0 === t && (t = {});
+ var e = Object.assign(
+ {
+ name: "rectImg",
+ w: 120,
+ h: 120,
+ x: 0,
+ y: 0,
+ l: 15,
+ t: 15,
+ r: 25,
+ b: 25,
+ image: "box_border_grey.png",
+ },
+ t
+ ),
+ i = c.Texture.from(e.image),
+ n = new c.NineSlicePlane(i, e.l, e.t, e.r, e.b);
+ return (n.width = e.w), (n.height = e.h), (n.x = 0.5 * -e.w + e.x), (n.y = 0.5 * -e.h + e.y), n;
+ }),
+ (Graph.rectComp = function () {
+ for (var t = new c.Container(), e = arguments.length, i = new Array(e), n = 0; n < e; n++) i[n] = arguments[n];
+ for (var o = 0, s = i; o < s.length; o++) {
+ var a = s[o],
+ r = this.rect(a);
+ (t[a.name] = r), t.addChild(r);
+ }
+ return t;
+ }),
+ (Graph.roundRectBorder = function (t) {
+ void 0 === t && (t = {});
+ var e = Object.assign(
+ {
+ w: 120,
+ h: 120,
+ round: 5,
+ color: 3246014,
+ alpha: 1,
+ borderWidth: 12,
+ borderColor: 16777215,
+ },
+ t
+ ),
+ i = Object.assign(
+ {
+ name: "fill",
+ },
+ e
+ ),
+ n = {
+ name: "border",
+ w: e.w + e.borderWidth,
+ h: e.h + e.borderWidth,
+ round: e.round + 0.5 * e.borderWidth,
+ color: e.borderColor,
+ alpha: e.alpha,
+ };
+ return this.rectComp(n, i);
+ }),
+ (Graph.rectShadow = function (t) {
+ void 0 === t && (t = {});
+ var e = Object.assign(
+ {
+ w: 120,
+ h: 120,
+ round: 0,
+ color: 3246014,
+ alpha: 1,
+ shadowDistance: 8,
+ shadowColor: 0,
+ shadowAngle: 0.25 * Math.PI,
+ shadowAlpha: 1,
+ },
+ t
+ ),
+ i = Object.assign({}, e, {
+ name: "fill",
+ }),
+ n = Object.assign({}, e, {
+ name: "shadow",
+ color: e.shadowColor,
+ alpha: e.shadowAlpha,
+ x: Math.sin(e.shadowAngle) * e.shadowDistance,
+ y: Math.cos(e.shadowAngle) * e.shadowDistance,
+ });
+ return this.rectComp(n, i);
+ }),
+ (Graph.rectBorder = function (t) {
+ void 0 === t && (t = {});
+ var e = Object.assign(
+ {
+ w: 120,
+ h: 120,
+ round: 5,
+ color: 3246014,
+ alpha: 1,
+ borderWidth: 8,
+ borderColor: 0,
+ borderAlpha: 1,
+ },
+ t
+ ),
+ i = Object.assign({}, e, {
+ name: "fill",
+ }),
+ n = Object.assign({}, e, {
+ name: "border",
+ w: e.w + 2 * e.borderWidth,
+ h: e.h + 2 * e.borderWidth,
+ color: e.borderColor,
+ alpha: e.borderAlpha,
+ round: e.round + 0.5 * e.borderWidth,
+ });
+ return this.rectComp(n, i);
+ }),
+ (Graph.clear = function (t) {
+ if ((t.clear && t.clear(), t.children)) for (var e in t.children) this.clear(t.children[e]);
+ }),
+ (Graph.resize = function (t, e, i) {
+ if ((t.width && ((t.width = e), (t.height = i)), t.children)) for (var n in t.children) this.resize(t.children[n]);
+ }),
+ Graph
+ );
+ })();
+
+ function ItemTimer_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+
+ function ItemTimer_createClass(t, e, i) {
+ return e && ItemTimer_defineProperties(t.prototype, e), i && ItemTimer_defineProperties(t, i), t;
+ }
+
+ function ItemTimer_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ var Se = (function (n) {
+ function ItemTimer(t, e) {
+ var i;
+ return (
+ ((i = n.call(this) || this).id = e),
+ (i.game = t),
+ (i.iconBase = c.Sprite.from("base_item.png")),
+ i.iconBase.anchor.set(0.5),
+ i.addChild(i.iconBase),
+ (i.icon = c.Sprite.from("icon_item_" + e + ".png")),
+ i.icon.anchor.set(0.5),
+ i.addChild(i.icon),
+ (i.bar = new ze(200, 30, 16777215, 10867241)),
+ i.addChild(i.bar),
+ (i.bar.x = i.iconBase.width / 2 + i.bar.w / 2 + 6),
+ (i.base = Ce.roundRectBorder({
+ w: i.bar.w + 34,
+ h: i.bar.h + 16,
+ round: 5,
+ color: 16777215,
+ alpha: 1,
+ borderWidth: 3,
+ borderColor: 10066329,
+ })),
+ i.addChildAt(i.base, 0),
+ (i.base.x = i.bar.x - 4),
+ (i.visible = !1),
+ i
+ );
+ }
+ ItemTimer_inheritsLoose(ItemTimer, n);
+ var t = ItemTimer.prototype;
+ return (
+ (t.show = function () {
+ this.visible || (this.visible = !0);
+ }),
+ (t.hide = function () {
+ this.visible && ((this.visible = !1), this.parent && this.parent.removeChild(this));
+ }),
+ ItemTimer_createClass(ItemTimer, [
+ {
+ key: "w",
+ get: function () {
+ return this.iconBase.width;
+ },
+ },
+ {
+ key: "h",
+ get: function () {
+ return this.iconBase.height;
+ },
+ },
+ {
+ key: "ratio",
+ get: function () {
+ return this.bar.ratio;
+ },
+ set: function (t) {
+ this.bar.ratio = t;
+ },
+ },
+ ]),
+ ItemTimer
+ );
+ })(c.Container),
+ ze = (function (r) {
+ function ProgressBar(t, e, i, n) {
+ var o;
+ void 0 === i && (i = 0), void 0 === n && (n = 16142336);
+ var s = ((o = r.call(this) || this).w = t),
+ a = (o.h = e);
+ return (
+ (o.barBg = new c.Graphics()),
+ o.barBg.beginFill(i, 0.75),
+ o.barBg.drawRect(0, 0, s, a),
+ o.barBg.position.set(-s / 2, -a / 2),
+ o.addChild(o.barBg),
+ (o.masked = new c.Container()),
+ o.addChild(o.masked),
+ (s -= 8),
+ (a -= 8),
+ (o.barFill = new Te(s, a)),
+ (o.barFill.x = -s / 2),
+ o.masked.addChild(o.barFill),
+ (o.barRed = new Te(s, a, 16711680)),
+ (o.barRed.x = -s / 2),
+ o.masked.addChild(o.barRed),
+ (o.barMask = new c.Graphics()),
+ o.barMask.beginFill(255),
+ o.barMask.drawRect(0, 0, s, a),
+ o.barMask.position.set(-s / 2, -a / 2),
+ o.addChild(o.barMask),
+ (o.masked.mask = o.barMask),
+ (o._ratio = 1),
+ o.update(),
+ o
+ );
+ }
+ return (
+ ItemTimer_inheritsLoose(ProgressBar, r),
+ (ProgressBar.prototype.update = function () {
+ (this.barMask.scale.x = this._ratio), (this.barRed.alpha = 1 - this._ratio);
+ }),
+ ItemTimer_createClass(ProgressBar, [
+ {
+ key: "ratio",
+ get: function () {
+ return this._ratio;
+ },
+ set: function (t) {
+ (this._ratio = V.clamp(t)), this.update();
+ },
+ },
+ ]),
+ ProgressBar
+ );
+ })(c.Container),
+ Te = (function (r) {
+ function Bar(t, e, i) {
+ var n;
+ ((n = r.call(this) || this).w = t), (n.h = e);
+ for (var o = Math.ceil(n.w / 11), s = 0; s < o; s++) {
+ var a = c.Sprite.from("item_duration_bar.png");
+ n.addChild(a), (a.x = 11 * s), (a.anchor.y = 0.5), (a.width = 8), (a.height = n.h), i && (a.tint = i);
+ }
+ return n;
+ }
+ return ItemTimer_inheritsLoose(Bar, r), Bar;
+ })(c.Container);
+
+ function HUDSystem_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+
+ function HUDSystem_assertThisInitialized(t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ }
+
+ function HUDSystem_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ var Pe = (function (n) {
+ function HudSystem(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).view = new c.Container()),
+ (i.game = t.game),
+ i.game.onReset.add(HUDSystem_assertThisInitialized(i)),
+ i.game.onRun.add(HUDSystem_assertThisInitialized(i)),
+ i.game.onPause.add(HUDSystem_assertThisInitialized(i)),
+ i.game.onResume.add(HUDSystem_assertThisInitialized(i)),
+ i.game.onGameover.add(HUDSystem_assertThisInitialized(i)),
+ i.game.onRevive.add(HUDSystem_assertThisInitialized(i)),
+ (i.countUpdate = 1),
+ i
+ );
+ }
+ HUDSystem_inheritsLoose(HudSystem, n);
+ var t = HudSystem.prototype;
+ return (
+ (t.build = function () {
+ this._built ||
+ ((this._built = !0),
+ (this.distance = new Me("base_long.png")),
+ this.view.addChild(this.distance),
+ (this.coins = new Me("base_long.png", "icon_coin_large.png")),
+ this.view.addChild(this.coins),
+ (this.multiplier = new Ee(this.game)),
+ this.view.addChild(this.multiplier),
+ (this.countdown = new c.Text("0", {
+ fill: "white",
+ align: "center",
+ fontSize: 80,
+ fontFamily: "Titan One",
+ stroke: "black",
+ strokeThickness: 5,
+ })),
+ this.countdown.anchor.set(0.5),
+ this.view.addChild(this.countdown),
+ (this.countdown.visible = !1),
+ (this.timers = new c.Container()),
+ this.view.addChild(this.timers),
+ this.resize());
+ }),
+ (t.update = function (t) {
+ if (this.game.state === pn.RUNNING && this._built && !(0 < this.countUpdate--)) {
+ this.countUpdate = 2;
+ var e = this.game.stats;
+ this.distance.getText() <= e.score && this.distance.setText(e.score, 6), this.coins.setText(e.coins), (this.multiplier.text = "x" + e.multiplier), this.multiplier.update(t);
+ }
+ }),
+ (t.reset = function () {
+ (this.view.visible = !1), this.message && (this.message.text = "");
+ }),
+ (t.run = function () {
+ this.build(), this.distance.setText(this.game.stats.score, 6), (this.view.visible = !0), this.game.stage.addChild(this.view), this.message && (this.message.text = "");
+ }),
+ (t.pause = function () {
+ this.clearCountdown();
+ }),
+ (t.resume = function () {
+ this.clearCountdown(), (this.view.visible = !0);
+ }),
+ (t.gameover = function () {
+ this.view.visible = !1;
+ }),
+ (t.revive = function () {
+ this.view.visible = !0;
+ }),
+ (t.resize = function (t, e, i) {
+ (this.sw = t || this.sw),
+ (this.sh = e || this.sh),
+ (this.sr = i || this.sr),
+ (this.s = this.sh / (667 * this.sr)),
+ (this.w = this.sw / this.s),
+ (this.h = this.sh / this.s),
+ this.view.scale.set(this.s),
+ this._built &&
+ ((this.distance.x = this.w - 110),
+ (this.distance.y = 60),
+ (this.coins.x = this.w - 170),
+ (this.coins.y = 160),
+ (this.countdown.x = this.w / 2),
+ (this.countdown.y = this.h / 2),
+ (this.multiplier.x = this.distance.x - 170),
+ (this.multiplier.y = this.distance.y),
+ this.message && ((this.message.x = this.w / 2), (this.message.y = 120)),
+ this.stats && ((this.stats.x = 10), (this.stats.y = 200)),
+ this.timers && ((this.timers.x = 0), (this.timers.y = this.h)));
+ }),
+ (t.addMessage = function (t) {
+ this.message && (0 <= this.msgs.indexOf(t) || (this.msgs.push(t), (this.message.text = this.msgs.join("\n"))));
+ }),
+ (t.clearMessage = function (t) {
+ if (this.message)
+ if (void 0 !== t) {
+ var e = this.msgs.indexOf(t);
+ e < 0 || (this.msgs.splice(e, 1), (this.message.text = this.msgs.join("\n")));
+ } else this.msgs.length = 0;
+ }),
+ (t.runCountdown = function (t, i) {
+ this.clearCountdown(),
+ (this.view.visible = !0),
+ this.view.addChild(this.countdown),
+ (this.countdown.visible = !0),
+ function _runStep(t) {
+ if (0 == t) return i(), void (this.countdown.visible = !1);
+ var e = "Starting in\n" + t;
+ (this.countdown.text = e), (this.countdown.visible = !0), (this._timeout = setTimeout(_runStep.bind(this), 900, t - 1));
+ }.call(this, t);
+ }),
+ (t.clearCountdown = function () {
+ this._timeout && clearTimeout(this._timeout), this.countdown && (this.countdown.visible = !1);
+ }),
+ (t.addItemTimer = function (t) {
+ this.timers[t] || (this.timers[t] = new Se(this.game, t));
+ var e = this.timers[t];
+ return this.timers.addChild(e), e.show(), this.organizeTimers(), e;
+ }),
+ (t.removeItemTimer = function (t) {
+ var e = this.timers[t];
+ e && (e.hide(), this.organizeTimers());
+ }),
+ (t.updateItemTimer = function (t, e) {
+ var i = this.timers[t];
+ i && (i.ratio = e);
+ }),
+ (t.organizeTimers = function () {
+ for (var t = this.timers.children.length; t--; ) {
+ var e = this.timers.children[t];
+ (e.x = e.w / 2 + 20), (e.y = -t * (e.h + 20) - e.h / 2 - 20);
+ }
+ (this.timers.x = 0), (this.timers.y = this.h);
+ }),
+ HudSystem
+ );
+ })(f.a),
+ Me = (function (s) {
+ function Label(t, e) {
+ var i;
+ ((i = s.call(this) || this).numChars = 6),
+ (i.spacing = 30),
+ (i._txt = -1),
+ t && ((i.base = c.Sprite.from(t)), i.base.anchor.set(0, 0.5), (i.base.alpha = 0.5), i.addChild(i.base)),
+ e && ((i.icon = c.Sprite.from(e)), i.icon.anchor.set(0.5), i.addChild(i.icon), (i.icon.x = i.numChars * i.spacing * 0.5 + 35), i.icon.scale.set(0.75)),
+ (i.text = new c.Container()),
+ i.addChild(i.text);
+ for (var n = 0; n < i.numChars; n++) {
+ var o = new c.Text("0", {
+ fill: "white",
+ align: "center",
+ fontSize: 50,
+ fontFamily: "Lilita One",
+ });
+ o.anchor.set(0.5), i.text.addChild(o);
+ }
+ return i;
+ }
+ HUDSystem_inheritsLoose(Label, s);
+ var t = Label.prototype;
+ return (
+ (t.setText = function (t, e) {
+ if (t !== this._txt) {
+ for (var i = (this._txt = t) + "", n = e || i.length; i.length < this.numChars; ) {
+ i = (i.length < e ? "0" : " ") + i;
+ }
+ for (var o = this.numChars; o--; ) {
+ var s = this.text.children[o],
+ a = i[o];
+ o < i.length && (s.text = a), (s.visible = " " !== a), (s.x = o * this.spacing);
+ }
+ (this.text.x = -(this.numChars - 1) * this.spacing * 0.5), (this.base.x = this.numChars * this.spacing * 0.5 - n * this.spacing - 20);
+ }
+ }),
+ (t.getText = function () {
+ return this._txt;
+ }),
+ Label
+ );
+ })(c.Container),
+ Ee = (function (s) {
+ function MultiplierLabel(t) {
+ var e;
+ (e = s.call(this) || this).game = t;
+ var i = c.Sprite.from("base_short.png");
+ i.anchor.set(0.5), (i.alpha = 0.5), (e.base = i), e.addChild(i);
+ var n = new c.Text("0", {
+ align: "center",
+ fill: 16702212,
+ fontSize: 50,
+ fontFamily: "Lilita One",
+ });
+ n.anchor.set(0.5), e.addChild(n), (e.label = n);
+ var o = new c.Text("0", {
+ align: "center",
+ fill: 7829367,
+ fontSize: 50,
+ fontFamily: "Lilita One",
+ });
+ return o.anchor.set(0.5), e.addChild(o), (e.labelOverlay = o), e;
+ }
+ var t, e, i;
+ return (
+ HUDSystem_inheritsLoose(MultiplierLabel, s),
+ (MultiplierLabel.prototype.update = function (t) {
+ var e = this.game.hero.multiplier.isOn();
+ this.labelOverlay.alpha = e ? 0.5 + 0.4 * Math.sin(0.1 * this.game.time) : 0;
+ }),
+ (t = MultiplierLabel),
+ (e = [
+ {
+ key: "text",
+ get: function () {
+ return this.label.text;
+ },
+ set: function (t) {
+ this.label.text !== t && ((this.label.text = t), (this.labelOverlay.text = t));
+ },
+ },
+ ]) && HUDSystem_defineProperties(t.prototype, e),
+ i && HUDSystem_defineProperties(t, i),
+ MultiplierLabel
+ );
+ })(c.Container);
+
+ function StatsSystem_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var Oe = {
+ x: 0,
+ y: 0,
+ z: 0,
+ distance: 0,
+ distanceDelta: 0,
+ score: 0,
+ coins: 0,
+ keys: 0,
+ chunkIndex: 0,
+ chunkName: "",
+ chunkStart: 0,
+ chunkEnd: 0,
+ chunkLength: 0,
+ block: 0,
+ hoverboards: 1,
+ revivals: 1,
+ multiplier: 1,
+ route: "",
+ time: 0,
+ delta: 0,
+ },
+ Re = (function (n) {
+ var t, e;
+
+ function StatsSystem(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ (i = n.call(this, t, e) || this),
+ t.game.onReset.add(
+ (function (t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ })(i)
+ ),
+ (i.game = t.game),
+ (i.data = {}),
+ i.reset(),
+ i
+ );
+ }
+ (e = n), ((t = StatsSystem).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ o,
+ s,
+ a = StatsSystem.prototype;
+ return (
+ (a.reset = function () {
+ Object.assign(this.data, Oe), (this.data.revivals = this.game.app.config.revivals || B.revivals || 0);
+ }),
+ (a.preupdate = function () {
+ (this.x = this.game.hero.transform.position.x), (this.y = this.game.hero.transform.position.y - 5.5), (this.z = this.game.hero.transform.position.z);
+ }),
+ (a.setCurrentChunk = function (t) {
+ (this.data.chunkName = t.name), (this.data.chunkStart = t.start), (this.data.chunkEnd = t.end), (this.data.chunkLength = t.length);
+ }),
+ (a.toString = function () {
+ var t = ["level", "route", "chunk"],
+ e = "";
+ for (var i in t) {
+ var n = t[i];
+ "z" !== n && "distance" !== n && "distanceDelta" !== n && (e += n + ": " + this[n] + "\n");
+ }
+ return e;
+ }),
+ (i = StatsSystem),
+ (o = [
+ {
+ key: "multiplier",
+ get: function () {
+ return this.data.multiplier;
+ },
+ set: function (t) {
+ this.data.multiplier = t;
+ },
+ },
+ {
+ key: "x",
+ get: function () {
+ return this.data.x;
+ },
+ set: function (t) {
+ this.data.x = t;
+ },
+ },
+ {
+ key: "y",
+ get: function () {
+ return this.data.y;
+ },
+ set: function (t) {
+ this.data.y = t;
+ },
+ },
+ {
+ key: "z",
+ get: function () {
+ return this.data.z;
+ },
+ set: function (t) {
+ (this.data.z = t),
+ (this.data.distanceDelta = -t - this.data.distance),
+ (this.data.distance = -t),
+ (this.data.block = (this.data.distance / B.blockSize) | 0),
+ (this.data.score += this.data.distanceDelta * this.data.multiplier);
+ },
+ },
+ {
+ key: "distance",
+ get: function () {
+ return this.data.distance;
+ },
+ set: function (t) {
+ (this.data.z = -t),
+ (this.data.distanceDelta = t - this.data.distance),
+ (this.data.distance = t),
+ (this.data.block = (this.data.distance / B.blockSize) | 0),
+ (this.data.score += this.data.distanceDelta * this.data.multiplier);
+ },
+ },
+ {
+ key: "distanceDelta",
+ get: function () {
+ return this.data.distanceDelta;
+ },
+ },
+ {
+ key: "score",
+ get: function () {
+ return Math.floor(0.1 * this.data.score);
+ },
+ },
+ {
+ key: "coins",
+ get: function () {
+ return this.data.coins;
+ },
+ set: function (t) {
+ this.data.coins = t;
+ },
+ },
+ {
+ key: "keys",
+ get: function () {
+ return this.data.keys;
+ },
+ set: function (t) {
+ this.data.keys = t;
+ },
+ },
+ {
+ key: "chunkIndex",
+ get: function () {
+ return this.data.chunkIndex;
+ },
+ set: function (t) {
+ this.data.chunkIndex = t;
+ },
+ },
+ {
+ key: "hoverboards",
+ get: function () {
+ return this.data.hoverboards;
+ },
+ set: function (t) {
+ this.data.hoverboards = t;
+ },
+ },
+ {
+ key: "speed",
+ get: function () {
+ if (B.speed) return B.speed;
+ var t = this.data.time,
+ e = 240;
+ t < 180 && (e = 110 + 130 * (t / 180));
+ return e / 60;
+ },
+ },
+ {
+ key: "level",
+ get: function () {
+ return Math.floor(this.data.time / 20);
+ },
+ },
+ {
+ key: "levelName",
+ get: function () {
+ switch (this.level) {
+ case 0:
+ return "easy";
+ case 1:
+ return "normal";
+ case 2:
+ return "hard";
+ default:
+ return "expert";
+ }
+ },
+ },
+ {
+ key: "time",
+ get: function () {
+ return this.data.time;
+ },
+ set: function (t) {
+ this.data.time = t;
+ },
+ },
+ {
+ key: "delta",
+ get: function () {
+ return this.data.delta;
+ },
+ set: function (t) {
+ this.data.delta = t;
+ },
+ },
+ {
+ key: "route",
+ set: function (t) {
+ this.data.route = t;
+ },
+ get: function () {
+ return this.data.route;
+ },
+ },
+ {
+ key: "chunk",
+ get: function () {
+ return this.data.chunkName;
+ },
+ },
+ {
+ key: "revivals",
+ get: function () {
+ return this.data.revivals;
+ },
+ set: function (t) {
+ this.data.revivals = t;
+ },
+ },
+ {
+ key: "profile",
+ get: function () {
+ return this._profile || (this._profile = {}), Object.assign(this._profile, this.data), (this._profile.speed = this.speed), (this._profile.level = this.level), (this._profile.levelName = this.levelName), this._profile;
+ },
+ },
+ ]) && StatsSystem_defineProperties(i.prototype, o),
+ s && StatsSystem_defineProperties(i, s),
+ StatsSystem
+ );
+ })(f.a);
+
+ function PoolSystem_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var Ie = (function (n) {
+ var t, e;
+
+ function PoolSystem(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).toRemove = []), i;
+ }
+ (e = n), ((t = PoolSystem).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = PoolSystem.prototype;
+ return (
+ (i.prepopulate = function (t, e) {
+ Le.getPool(t).prepopulate(e);
+ }),
+ (i.get = function (t, e) {
+ var i = Le.get(t);
+ return i.onEntityDestroyed.add(this), i._init.run(e || {}), i;
+ }),
+ (i.factory = function (t, e) {
+ var i = Le.get(_class);
+ return i.onEntityDestroyed.add(this), i._init.run(data || {}), i;
+ }),
+ (i.entityDestroyed = function (t) {
+ var e = this;
+ t.onEntityDestroyed.remove(this),
+ setTimeout(function () {
+ e["return"](t);
+ }, 200);
+ }),
+ (i["return"] = function (t) {
+ t._reset.run(), t.resetSignals(), this.toRemove.push(t);
+ }),
+ (i.postupdate = function () {
+ for (var t = 0; t < this.toRemove.length; t++) {
+ var e = this.toRemove[t];
+ Le["return"](e);
+ }
+ this.toRemove.length = 0;
+ }),
+ (i.empty = function () {
+ this.postupdate();
+ }),
+ PoolSystem
+ );
+ })(f.a),
+ Le = (function () {
+ function Pool(t) {
+ t instanceof Object
+ ? (this._create = function () {
+ return new t();
+ })
+ : (this._create = function () {
+ return t();
+ }),
+ (this.classType = t),
+ (this.pool = []),
+ (this.totalCreated = 0),
+ (this.debug = !1);
+ }
+ var t,
+ e,
+ i,
+ n = Pool.prototype;
+ return (
+ (n.prepopulate = function (t) {
+ for (var e = 0; e < t; e++) this.pool.push(this._create());
+ }),
+ (n.get = function () {
+ var t = this.pool.pop();
+ return t || (this.totalCreated++, this.debug, (t = this._create())), t;
+ }),
+ (n["return"] = function (t) {
+ -1 === this.pool.indexOf(t) && this.pool.push(t), this.debug;
+ }),
+ (Pool.getPool = function (t) {
+ var e = this.getClassId(t);
+ return Pool.pools[e] || (Pool.pools[e] = new Pool(t)), Pool.pools[e];
+ }),
+ (Pool.get = function (t) {
+ var e = this.getPool(t).get();
+ return (e._CLASS_ID = this.getClassId(t)), e;
+ }),
+ (Pool["return"] = function (t) {
+ Pool.pools[t._CLASS_ID]["return"](t);
+ }),
+ (Pool.getClassId = function (t) {
+ return t._CLASS_ID || (t._CLASS_ID = Pool.idGenerator++), t._CLASS_ID;
+ }),
+ (t = Pool),
+ (e = [
+ {
+ key: "total",
+ get: function () {
+ return this.pool.length;
+ },
+ },
+ ]) && PoolSystem_defineProperties(t.prototype, e),
+ i && PoolSystem_defineProperties(t, i),
+ Pool
+ );
+ })();
+ (Le.pools = []), (Le.idGenerator = 1);
+ var je = i(94);
+
+ function ControllerSystem_assertThisInitialized(t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ }
+ var Fe = (function (n) {
+ var t, e;
+
+ function ControllerSystem(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).keyboard = new je.a()),
+ i.keyboard.onKeyPress("left", i.pressLeft.bind(ControllerSystem_assertThisInitialized(i))),
+ i.keyboard.onKeyPress("up", i.pressUp.bind(ControllerSystem_assertThisInitialized(i))),
+ i.keyboard.onKeyPress("right", i.pressRight.bind(ControllerSystem_assertThisInitialized(i))),
+ i.keyboard.onKeyPress("down", i.pressDown.bind(ControllerSystem_assertThisInitialized(i))),
+ i.keyboard.onKeyPress("space", i.pressAction.bind(ControllerSystem_assertThisInitialized(i))),
+ (i.view = new c.Graphics()),
+ (i.view.alpha = 0),
+ i.view.beginFill(16763904),
+ i.view.drawRect(0, 0, 4, 4),
+ i.view.endFill(),
+ i.view.addListener("pointerdown", i.onPointerDown, ControllerSystem_assertThisInitialized(i)),
+ i.view.addListener("pointermove", i.onPointerMove, ControllerSystem_assertThisInitialized(i)),
+ i.view.addListener("pointerup", i.onPointerUp, ControllerSystem_assertThisInitialized(i)),
+ t.game.onReset.add(ControllerSystem_assertThisInitialized(i)),
+ t.game.onRun.add(ControllerSystem_assertThisInitialized(i)),
+ t.game.onPause.add(ControllerSystem_assertThisInitialized(i)),
+ t.game.onResume.add(ControllerSystem_assertThisInitialized(i)),
+ t.game.onGameover.add(ControllerSystem_assertThisInitialized(i)),
+ t.game.onRevive.add(ControllerSystem_assertThisInitialized(i)),
+ (i.vertical = 0),
+ (i.horizontal = 0),
+ (i.action = 0),
+ (i.pressing = !1),
+ (i.pressStartX = 0),
+ (i.pressStartY = 0),
+ (i.pressCount = 0),
+ (i.onSwipeHorizontal = new et.a("onSwipeHorizontal", 1)),
+ (i.onSwipeVertical = new et.a("onSwipeVertical", 1)),
+ (i.onDoubleTap = new et.a("onDoubleTap")),
+ i
+ );
+ }
+ (e = n), ((t = ControllerSystem).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = ControllerSystem.prototype;
+ return (
+ (i.onPointerDown = function (t) {
+ var e = t.data.global;
+ 0 < this.pressCount && (this.action = 1), (this.pressCount = 50), (this.pressStartX = e.x), (this.pressStartY = e.y), (this.pressing = !0);
+ }),
+ (i.onPointerMove = function (t) {
+ if (this.pressing) {
+ var e = t.data.global,
+ i = e.x - this.pressStartX;
+ if (60 < Math.abs(i)) return (this.pressing = !1), (this.pressCount = 0), void (this.horizontal = V.sign(i));
+ var n = e.y - this.pressStartY;
+ return 60 < Math.abs(n) ? ((this.pressing = !1), (this.pressCount = 0), void (this.vertical = -V.sign(n))) : void 0;
+ }
+ }),
+ (i.onPointerUp = function (t) {
+ this.pressing = !1;
+ }),
+ (i.onPointerCancel = function (t) {
+ this.pressing = !1;
+ }),
+ (i.pressUp = function () {
+ this.vertical = 1;
+ }),
+ (i.pressDown = function () {
+ this.vertical = -1;
+ }),
+ (i.pressLeft = function () {
+ this.horizontal = -1;
+ }),
+ (i.pressRight = function () {
+ this.horizontal = 1;
+ }),
+ (i.pressAction = function () {
+ this.action = 1;
+ }),
+ (i.update = function () {
+ 0 < this.pressCount && (this.pressCount -= 1),
+ this.game.state === pn.RUNNING &&
+ (1 === this.vertical
+ ? this.onSwipeVertical.dispatch(this.vertical)
+ : -1 === this.vertical
+ ? this.onSwipeVertical.dispatch(this.vertical)
+ : this.horizontal
+ ? this.onSwipeHorizontal.dispatch(this.horizontal)
+ : this.action && this.onDoubleTap.dispatch(),
+ (this.vertical = 0),
+ (this.horizontal = 0),
+ (this.action = 0));
+ }),
+ (i.reset = function () {
+ this.hide();
+ }),
+ (i.show = function () {
+ (this.view.visible = !0), (this.view.interactive = !0), this.view.visible && this.game.stage.addChild(this.view), this.keyboard.start();
+ }),
+ (i.hide = function () {
+ (this.view.visible = !1), (this.view.interactive = !1), this.keyboard.stop();
+ }),
+ (i.run = function () {
+ this.show();
+ }),
+ (i.revive = function () {
+ this.show();
+ }),
+ (i.pause = function () {
+ this.hide();
+ }),
+ (i.resume = function () {
+ this.show();
+ }),
+ (i.gameover = function () {
+ this.hide();
+ }),
+ (i.resize = function (t, e) {
+ (this.view.x = 0), (this.view.y = 0), (this.view.width = t), (this.view.height = e);
+ }),
+ ControllerSystem
+ );
+ })(f.a);
+
+ function FreeCamera_assertThisInitialized(t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ }
+ var Ae = (function (n) {
+ var t, e;
+
+ function FreeCamera(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).axis = new q()),
+ (i.keyboard = new je.a()),
+ (i.keyboard._keyCodes[81] = {
+ label: "q",
+ state: 0,
+ preventBubble: !0,
+ }),
+ (i.keyboard._keyCodes[69] = {
+ label: "e",
+ state: 0,
+ preventBubble: !0,
+ }),
+ i.keyboard.onKeyPress("a", i.pressLeft.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.onKeyPress("d", i.pressRight.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.onKeyPress("w", i.pressFront.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.onKeyPress("s", i.pressBack.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.onKeyPress("q", i.pressUp.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.onKeyPress("e", i.pressDown.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.onKeyRelease("a", i.releaseLeft.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.onKeyRelease("d", i.releaseRight.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.onKeyRelease("w", i.releaseFront.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.onKeyRelease("s", i.releaseBack.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.onKeyRelease("q", i.releaseUp.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.onKeyRelease("e", i.releaseDown.bind(FreeCamera_assertThisInitialized(i))),
+ i.keyboard.stop(),
+ (i.onMouseMoveBind = i.onMouseMove.bind(FreeCamera_assertThisInitialized(i))),
+ (i.useDelta = !0),
+ i
+ );
+ }
+ (e = n), ((t = FreeCamera).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = FreeCamera.prototype;
+ return (
+ (i.added = function () {
+ (this._oldParent = this.entity.parent),
+ this.entity.parent && this.entity.parent.removeChild(this.entity),
+ (this._rig = this.entity.game.view3d.camera.camera),
+ (this._rig.x = this.entity.game.camera.rig.mainX),
+ (this._rig.y = this.entity.game.camera.rig.mainY),
+ (this._rig.z = this.entity.game.camera.rig.mainZ),
+ (this._rig.rx = this.entity.game.camera.rig.mainRotX),
+ (this._rig.ry = this.entity.game.camera.rig.mainRotY),
+ this.keyboard.start(),
+ (this.mouseX = 0),
+ (this.mouseY = 0),
+ (this.lastMouseX = null),
+ (this.lastMouseY = null),
+ (this.deltaX = 0),
+ (this.deltaY = 0),
+ (this.speed = 0),
+ this.axis.reset(),
+ (this._updateProjection = this.entity.camera.updateProjection),
+ (this.entity.camera.updateProjection = FreeCamera_updateProjection),
+ window.addEventListener("mousemove", this.onMouseMoveBind);
+ }),
+ (i.removed = function () {
+ this._oldParent && this._oldParent.addChild(this.entity), (this.entity.camera.updateProjection = this._updateProjection), this.keyboard.stop(), window.removeEventListener("mousemove", this.onMouseMoveBind), (this._rig = null);
+ }),
+ (i.onMouseMove = function (t) {
+ (this.mouseX = t.clientX - window.innerWidth / 2), (this.mouseY = t.clientY - window.innerHeight / 2), null === this.lastMouseX && (this.lastMouseX = this.mouseX), null === this.lastMouseY && (this.lastMouseY = this.mouseY);
+ }),
+ (i.update = function () {
+ if (this._rig) {
+ null !== this.lastMouseX && ((this.deltaX = this.mouseX - this.lastMouseX), (this.deltaY = this.mouseY - this.lastMouseY), (this.lastMouseX = this.mouseX), (this.lastMouseY = this.mouseY)),
+ 0 !== this.axis.z || 0 !== this.axis.x ? ((this.speed += 0.02), 5 < this.speed && (this.speed = 5)) : (this.speed = 0.5);
+ this.useDelta ? ((this._rig.ry -= 0.01 * this.deltaX), (this._rig.rx -= 0.01 * this.deltaY)) : ((this._rig.ry = 0.01 * -this.mouseX), (this._rig.rx = 0.01 * -this.mouseY)),
+ (this._rig.z += Math.cos(this._rig.ry) * (this.axis.z * this.speed)),
+ (this._rig.x += Math.sin(this._rig.ry) * (this.axis.z * this.speed)),
+ (this._rig.z += Math.cos(this._rig.ry + V.PI_HALF) * (this.axis.x * this.speed)),
+ (this._rig.x += Math.sin(this._rig.ry + V.PI_HALF) * (this.axis.x * this.speed)),
+ (this._rig.y -= Math.sin(this._rig.rx) * (this.axis.z * this.speed)),
+ (this._rig.y += Math.sin(this._rig.rx + V.PI_HALF) * (this.axis.y * this.speed));
+ }
+ }),
+ (i.pressFront = function () {
+ this.axis.z = -1;
+ }),
+ (i.pressBack = function () {
+ this.axis.z = 1;
+ }),
+ (i.pressLeft = function () {
+ this.axis.x = -1;
+ }),
+ (i.pressRight = function () {
+ this.axis.x = 1;
+ }),
+ (i.pressUp = function () {
+ this.axis.y = 1;
+ }),
+ (i.pressDown = function () {
+ this.axis.y = -1;
+ }),
+ (i.releaseFront = function () {
+ -1 === this.axis.z && (this.axis.z = 0);
+ }),
+ (i.releaseBack = function () {
+ 1 === this.axis.z && (this.axis.z = 0);
+ }),
+ (i.releaseLeft = function () {
+ -1 === this.axis.x && (this.axis.x = 0);
+ }),
+ (i.releaseRight = function () {
+ 1 === this.axis.x && (this.axis.x = 0);
+ }),
+ (i.releaseUp = function () {
+ 1 === this.axis.y && (this.axis.y = 0);
+ }),
+ (i.releaseDown = function () {
+ -1 === this.axis.y && (this.axis.y = 0);
+ }),
+ FreeCamera
+ );
+ })(J.a),
+ De = U.quat.create(),
+ Ge = U.vec3.create();
+
+ function FreeCamera_updateProjection(t, e) {
+ void 0 === this.x && (this.x = 0),
+ void 0 === this.y && (this.y = 0),
+ void 0 === this.z && (this.z = 0),
+ void 0 === this.rx && (this.rx = 0),
+ void 0 === this.ry && (this.ry = 0),
+ void 0 === this.rz && (this.rz = 0),
+ U.quat.identity(De),
+ U.quat.rotateZ(De, De, this.rz),
+ U.quat.rotateY(De, De, this.ry),
+ U.quat.rotateX(De, De, this.rx),
+ (Ge[0] = this.x),
+ (Ge[1] = this.y),
+ (Ge[2] = this.z),
+ U.mat4.fromRotationTranslation(this.view, De, Ge),
+ U.mat4.perspective(this.projection, this.fov * (Math.PI / 180), t / e, this.near, this.far),
+ U.mat4.invert(this.view, this.view),
+ this.dirty++;
+ }
+
+ function DebugSystem_assertThisInitialized(t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ }
+ var Be = (function (n) {
+ var t, e;
+
+ function DebugSystem(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).game = t.game),
+ i.game.onReset.add(DebugSystem_assertThisInitialized(i)),
+ (i.running = !1),
+ window.addEventListener("keydown", i.onKeyDown.bind(DebugSystem_assertThisInitialized(i))),
+ (i.view = new c.Container()),
+ (i.title = new c.Text("DEBUG MODE", {
+ fill: "red",
+ align: "center",
+ fontSize: 18,
+ fontFamily: "Arial Black",
+ })),
+ i.view.addChild(i.title),
+ i.title.anchor.set(0.5),
+ (i.title.y = 12),
+ (i.stats = new c.Text("", {
+ fill: "white",
+ fontSize: 18,
+ fontFamily: "Arial",
+ stroke: !0,
+ strokeThickness: 4,
+ lineJoin: "round",
+ })),
+ i.view.addChild(i.stats),
+ (i.stats.x = 10),
+ (i.stats.y = 200),
+ (i.view.visible = B.debug),
+ setInterval(function () {
+ return i._update(0);
+ }, 100),
+ i
+ );
+ }
+ (e = n), ((t = DebugSystem).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = DebugSystem.prototype;
+ return (
+ (i.reset = function () {
+ this.game.stage.addChild(this.view);
+ }),
+ (i._update = function (t) {
+ if (this.game && !this.game.app.crashed) {
+ var e = [
+ DebugSystem_str("ENGINE", this.game.profile),
+ DebugSystem_str("STATS", this.game.stats.profile),
+ DebugSystem_str("CAMERA", this.game.camera.profile),
+ DebugSystem_str("PHYSICS", this.game.physics.stats),
+ DebugSystem_str("ROUTE", this.game.route.profile),
+ ];
+ (this.stats.text = e.join("\n")), (this.title.x = this.game.w / 2);
+ }
+ }),
+ (i.onKeyDown = function (t) {
+ "z" === t.key && this.toggle(),
+ this.running ||
+ ("t" === t.key && this.game.level.reshuffle(),
+ "m" === t.key && this.game.hero.magnet.turnOn(),
+ "j" === t.key && this.game.hero.jetpack.turnOn(),
+ "q" === t.key && this.game.hero.pogo.turnOn(),
+ "s" === t.key && this.game.hero.sneakers.turnOn(),
+ "e" === t.key && this.game.hero.multiplier.turnOn());
+ }),
+ (i.toggle = function () {
+ this.running ? this.finish() : this.begin();
+ }),
+ (i.begin = function () {
+ this.running || ((this.running = !0), (this.game.timeScale = 0), this.game.view3d.camera.add(Ae));
+ }),
+ (i.finish = function () {
+ this.running && ((this.running = !1), this.game.view3d.camera.remove(Ae), (this.game.timeScale = this.game.config.timeScale));
+ }),
+ (i.resize = function (t, e) {}),
+ DebugSystem
+ );
+ })(f.a);
+
+ function DebugSystem_str(t, e, i) {
+ i || (i = Object.keys(e));
+ var n = "";
+ for (var o in i) {
+ var s = i[o],
+ a = e[s];
+ "number" == typeof a && a % 1 != 0 && (a = a.toFixed(3)), (n += s + ": " + a + "\n");
+ }
+ return t.toUpperCase() + "\n" + n;
+ }
+ var Ne = (function (n) {
+ var t, e;
+
+ function FramebufferSystem(t) {
+ var e;
+ (e = n.call(this, t) || this).renderer = t;
+ var i = c.utils.hex2rgb(9753343);
+ return (e.r = i[0]), (e.g = i[1]), (e.b = i[2]), (e.a = 1), e;
+ }
+ return (
+ (e = n),
+ ((t = FramebufferSystem).prototype = Object.create(e.prototype)),
+ ((t.prototype.constructor = t).__proto__ = e),
+ (FramebufferSystem.prototype.prerender = function () {
+ var t = this.renderer.gl;
+ t.clearColor(this.r, this.g, this.b, this.a), t.clear(t.COLOR_BUFFER_BIT | t.DEPTH_BUFFER_BIT);
+ }),
+ FramebufferSystem
+ );
+ })(c.System);
+ var Xe = (function (n) {
+ var t, e;
+
+ function Smoke(t, e) {
+ var i;
+ return (
+ void 0 === t && (t = 5),
+ void 0 === e && (e = !0),
+ ((i = n.call(this) || this).speed = t),
+ (i.view = i.getView(e)),
+ (i.view2 = i.getView(e)),
+ (i.view2.y = -73),
+ (i.view2.scale.x = 1),
+ (i.view2.scale.y = 2),
+ (i.view2.scale.z = 2),
+ i
+ );
+ }
+ (e = n), ((t = Smoke).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Smoke.prototype;
+ return (
+ (i.getView = function (t) {
+ var e = H.getEntityClone("jetpackCloud", "jetpackSmoke", !1, G);
+ return (
+ (e.view3d.state.blend = !0),
+ (e.view3d.state.culling = !1),
+ (e.view3d.material.map.baseTexture.wrapMode = c.WRAP_MODES.REPEAT),
+ this.addChild(e),
+ (e.ry = 0.5 * -Math.PI),
+ (e.rx = 0.5 * Math.PI),
+ e.scale.set(0.25),
+ (e.y = -12),
+ (e.active = !1),
+ (e.view3d.state.depthTest = t),
+ e
+ );
+ }),
+ (i.update = function (t) {
+ this.view.active && ((this.view.view3d.material.map.orig.x -= t * this.speed), (this.view2.view3d.material.map.orig.x -= t * this.speed));
+ }),
+ (i.turnOn = function () {
+ (this.view.active = !0), (this.view2.active = !0);
+ }),
+ (i.turnOff = function () {
+ var t = this;
+ (this.view.active = !1),
+ (this.view2.active = !1),
+ this.parent && this.parent.removeChild(this),
+ setTimeout(function () {
+ (t.view.active = !1), (t.view2.active = !1), t.parent && t.parent.removeChild(t);
+ }, 100);
+ }),
+ Smoke
+ );
+ })(v.a);
+
+ function Jetpack_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var Ye = (function (n) {
+ var t, e;
+
+ function Jetpack(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).distance = 0), (i.distanceTotal = 1), (i.speed = 0), (i.ceiling = 100), (i.coinDistance = 30), i;
+ }
+ (e = n), ((t = Jetpack).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ o,
+ s,
+ a = Jetpack.prototype;
+ return (
+ (a.show = function () {
+ this.view || (this.view = H.getEntityCloneOpaque("/powerups_jetpack", "props_tex", !1)), (this.view.ry = Math.PI), (this.view.y = 1), (this.view.z = 0.5), this.view.scale.set(0.6);
+ var t = this.entity.anim.scenes[2];
+ H.findEntity("LowerSpine_jnt", t.pixiTree, 10).addChild(this.view),
+ this.entity.game.sfx.play("special_jetpack_start"),
+ this.entity.game.sfx.play("special_jetpack", {
+ loop: !0,
+ }),
+ this.entity.game.hud.addItemTimer("jetpack"),
+ this.jetpackSmokeOn();
+ }),
+ (a.hide = function () {
+ this.entity.game.hud.removeItemTimer("jetpack"), this.jetpackSmokeOff(), this.entity.game.sfx.stop("special_jetpack"), this.view.parent && this.view.parent.removeChild(this.view);
+ }),
+ (a.update = function (t) {
+ if (this.distance) {
+ this.timer && (this.timer.ratio = this.ratio);
+ var e = V.lerp(this.entity.body.velocity.z, this.speed, 0.1 * t);
+ (this.entity.body.velocity.z = e), (this.distance -= this.entity.game.stats.distanceDelta), this.entity.game.hud.updateItemTimer("jetpack", this.ratio);
+ var i = this.entity.game.stats.y + B.cameraPosY,
+ n = this.entity.game.stats.z + B.cameraPosZ;
+ if (((this.entity.game.hero.player.cameraY = i), this.takeOffTime < this.takeOffDuration)) {
+ (this.takeOffTime += this.entity.game.deltaSecs), this.takeOffTime > this.takeOffDuration && (this.takeOffTime = this.takeOffDuration);
+ var o = this.takeOffTime / this.takeOffDuration;
+ St.quartInOut(o);
+ (this.entity.body.y = V.lerp(this.takeOffStartY, this.takeOffEndY, o)), (this.rig.mainY = V.lerp(this.rigStartY, i, St.sineOut(o))), (this.rig.mainZ = V.lerp(this.rigStartZ, n, St.expoOut(o)));
+ } else (this.rig.mainY = i), (this.rig.mainZ = n);
+ (this.rig.mainX = this.entity.game.stats.x * B.cameraModX),
+ (this.rig.mainRotX = B.cameraRotX + this.entity.game.hero.player.cameraRotX),
+ (this.entity.player.cameraTargetY = this.entity.body.bottom),
+ this.smokeLeft && this.smokeLeft.update(t),
+ this.smokeRight && this.smokeRight.update(t),
+ this.distance <= 0 && this.turnOff();
+ }
+ }),
+ (a.turnOn = function () {
+ this.entity.player.dizzyEnd(),
+ this.entity.sneakers.turnOff(),
+ this.entity.pogo.turnOff(),
+ this.entity.hoverboard.pause(),
+ this.entity.jump.lock(),
+ this.entity.roll.lock(),
+ this.entity.state.set("empty"),
+ (this.entity.body.velocity.y = 0),
+ (this.entity.body.ghost = !0),
+ (this.speed = 2 * -this.entity.game.stats.speed - 1);
+ var t = -this.entity.body.z,
+ e = t + 1e3 + 200 * Math.abs(this.speed),
+ i = this.entity.game.level.setSafeLanding(e);
+ (this.distanceTotal = i - t),
+ (this.distance = this.distanceTotal),
+ (this.takeOffStartY = this.entity.body.y),
+ (this.takeOffEndY = 100),
+ (this.takeOffTime = 0),
+ (this.takeOffDuration = 2),
+ (this.rig = this.entity.game.camera.takeControl()),
+ (this.rigStartY = this.rig.mainY),
+ (this.rigStartZ = this.rig.mainZ),
+ this.spawnCoins(this.entity.game, this.takeOffEndY, this.distance),
+ this.show();
+ }),
+ (a.turnOff = function () {
+ this.distance &&
+ (this.hide(),
+ (this.entity.body.ghost = !1),
+ (this.entity.body.ceiling = 999),
+ (this.entity.body.velocity.y = 0),
+ this.entity.jump.unlock(),
+ this.entity.roll.unlock(),
+ this.entity.game.camera.releaseControl(),
+ (this.distance = 0),
+ this.entity.restoreSize(),
+ this.entity.hoverboard.resume());
+ }),
+ (a.isOn = function () {
+ return !!this.distance;
+ }),
+ (a.spawnCoins = function (t, e, i) {
+ for (var n = 350 * t.stats.speed, o = i - n, s = o / this.coinDistance, a = o / s, r = 0, h = 0, d = 5, l = 0; l < s; l++) {
+ var c = t.pool.get(pt);
+ d ? (d -= 1) : ((r = r ? L.pick(0, r) : L.pick(-1, 0, 1)), (d = 5)), h < r ? (h += 0.5) : r < h && (h -= 0.5), (c.body.x = B.laneWidth * h), (c.body.y = e), (c.body.z = t.stats.z - a * l - n), c.init(), t.addChild(c);
+ }
+ }),
+ (a.jetpackSmokeOn = function () {
+ this.smokeLeft ||
+ ((this.smokeLeft = new Xe(3, !0)),
+ (this.smokeLeft.x = 0.9 + this.entity.model.x),
+ (this.smokeLeft.y = 1.7),
+ (this.smokeLeft.z = 0.5),
+ (this.smokeLeft.scale.x = 0.5),
+ (this.smokeLeft.scale.y = 2),
+ (this.smokeLeft.rotation.x = -V.PI_HALF),
+ (this.smokeRight = new Xe(3, !0)),
+ (this.smokeRight.x = -0.9 + this.entity.model.x),
+ (this.smokeRight.y = this.smokeLeft.y),
+ (this.smokeRight.z = this.smokeLeft.z),
+ (this.smokeRight.scale.x = -this.smokeLeft.scale.x),
+ (this.smokeRight.scale.y = this.smokeLeft.scale.y),
+ (this.smokeRight.rotation.x = this.smokeLeft.rotation.x)),
+ this.entity.addChild(this.smokeLeft),
+ this.entity.addChild(this.smokeRight),
+ this.smokeLeft.turnOn(),
+ this.smokeRight.turnOn();
+ }),
+ (a.jetpackSmokeOff = function () {
+ this.smokeLeft && (this.smokeLeft.turnOff(), this.smokeRight.turnOff());
+ }),
+ (i = Jetpack),
+ (o = [
+ {
+ key: "ratio",
+ get: function () {
+ return this.distance / this.distanceTotal;
+ },
+ },
+ ]) && Jetpack_defineProperties(i.prototype, o),
+ s && Jetpack_defineProperties(i, s),
+ Jetpack
+ );
+ })(J.a);
+ var He = (function (n) {
+ var t, e;
+
+ function Pogo(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).count = 0),
+ (i.onTurnOn = new et.a("onPogoTurnOn")),
+ (i.onTurnOff = new et.a("onPogoTurnOff")),
+ (i.onHangtime = new et.a("onPogoHangtime")),
+ (i.settings = {
+ jumpHeight: 150,
+ jumpDistance: 300,
+ characterChangeTrackLength: 60,
+ finalJumpSpeed: 0,
+ rows: 14,
+ startRowPosition: 1,
+ endRowPosition: 1,
+ fadeInPosition: 0.1,
+ hangtimePosition: 0.6,
+ smoothCameraXDuration: 0.05,
+ }),
+ i
+ );
+ }
+ (e = n), ((t = Pogo).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Pogo.prototype;
+ return (
+ (i.show = function () {
+ this.view || (this.view = H.getEntityCloneOpaque("/powerups_rocketPogo", "props_tex", !1));
+ var t = this.entity.anim.scenes[4];
+ H.findEntity("attachPoint1", t.pixiTree, 10).addChild(this.view), this.pogoSmokeOn();
+ }),
+ (i.hide = function () {
+ this.pogoSmokeOff(), this.view.parent && this.view.parent.removeChild(this.view);
+ }),
+ (i.turnOn = function () {
+ this.show(),
+ (this.hangtime = !1),
+ this.entity.sneakers.turnOff(),
+ this.entity.jetpack.turnOff(),
+ this.entity.player.dizzyEnd(),
+ this.entity.hoverboard.pause(),
+ this.entity.roll.cancel(),
+ this.onTurnOn.dispatch(),
+ this.entity.jump.lock(),
+ (this.camera = this.entity.game.camera.takeControl()),
+ (this.entity.body.ghost = !0),
+ this.entity.anim.play(["pogostick_kicking"], {
+ loop: !1,
+ }),
+ (this.position = this.entity.body.center.clone()),
+ (this.positionEnd = this.position.z - this.settings.jumpDistance),
+ (this.count = 1),
+ this.spawnCoins(this.entity.game, this.entity.game.hero.body),
+ (this.cameraStartY = this.camera.mainY),
+ this.entity.roll.onStart.add(this);
+ }),
+ (i.update = function (t) {
+ if (this.count) {
+ var e = this.entity.body.z,
+ i = this.entity.game.stats.speed;
+ if (e > this.positionEnd) {
+ var n = e - i * t,
+ o = -(n - this.position.z) / this.settings.jumpDistance,
+ s = (this.jumpCurveEvaluate(o), this.settings.jumpHeight, this.position.y + 1 * this.jumpCurveEvaluate(o) * this.settings.jumpHeight);
+ (s = V.lerp(this.position.y, s, o / this.settings.fadeInPosition)),
+ (this.entity.body.bottom = s),
+ o > this.settings.hangtimePosition &&
+ !this.hangtime &&
+ ((this.hangtime = !0),
+ this.onHangtime.dispatch(),
+ this.pogoSmokeOff(),
+ this.entity.anim.play(["pogostick_Hangtime_flying", "pogostick_Hangtime_kick", "pogostick_Hangtime_front_flip1"], {
+ loop: !1,
+ }));
+ var a = 0.8 * St.sineIn(o),
+ r = this.entity.game.stats.x * B.cameraModX,
+ h = this.entity.game.stats.y + B.cameraPosY * a,
+ d = this.entity.game.stats.z + B.cameraPosZ,
+ l = St.expoOut(o);
+ (this.entity.player.cameraY = h), (this.camera.mainX = r), (this.camera.mainY = V.lerp(this.cameraStartY, h, l)), (this.camera.mainZ = d);
+ var c = this.camera.mainY - this.entity.game.stats.y,
+ u = this.camera.mainZ - this.entity.game.stats.z + 50;
+ (this.camera.mainRotX = Math.atan2(u, c) - 0.5 * Math.PI), (this.entity.player.cameraTargetY = s), (this.entity.player.cameraY = s), (this.entity.body.velocity.y = 0);
+ } else this.turnOff();
+ this.smoke && this.smoke.update(t);
+ }
+ }),
+ (i.turnOff = function () {
+ this.count &&
+ (this.entity.roll.onStart.remove(this), this.onTurnOff.dispatch(), (this.entity.body.ghost = !1), this.entity.jump.unlock(), this.entity.game.camera.releaseControl(), this.entity.hoverboard.resume(), (this.count = 0));
+ }),
+ (i.onRollStart = function () {
+ this.entity.game.sfx.stop("special_jetpack"), this.turnOff();
+ }),
+ (i.jumpCurveEvaluate = function (t) {
+ return St.quartOut(t);
+ }),
+ (i.cameraCurveEvaluate = function (t) {
+ return St.expoOut(t);
+ }),
+ (i.cameraAimFollowCurveEvaluate = function (t) {
+ return St.quadOut(t);
+ }),
+ (i.isOn = function () {
+ return !!this.count;
+ }),
+ (i.spawnCoins = function (t, e) {
+ for (var i = this.entity.body.y, n = i + this.settings.jumpHeight, o = this.entity.body.z, s = o - this.settings.jumpDistance, a = i, r = o, h = this.settings.rows + 1, d = 0; d <= h; d++)
+ if (!(d < 1)) {
+ var l = d / h,
+ c = this.jumpCurveEvaluate(l);
+ (a = V.lerp(i, n, c)), (r = V.lerp(o, s, l)), d < h ? this.spawnCoinsRow(a, r) : this.spawnPowerup(a, r);
+ }
+ }),
+ (i.spawnCoinsRow = function (t, e) {
+ for (var i = 3; i--; ) {
+ var n = this.entity.game.pool.get(pt);
+ (n.body.x = (i - 1) * B.laneWidth), (n.body.bottom = t), (n.body.z = e), n.init(), this.entity.game.addChild(n);
+ }
+ }),
+ (i.spawnPowerup = function (t, e) {
+ var i = Tt.spawn(this.entity.game, ["sneakers", "jetpack", "magnet", "multiplier"]);
+ (i.body.x = L.pick(-1, 0, 1) * B.laneWidth), (i.body.bottom = t), (i.body.z = e);
+ }),
+ (i.pogoSmokeOn = function () {
+ this.smoke || ((this.smoke = new Xe(5)), (this.smoke.scale.x = 0.5), (this.smoke.scale.y = 1.1), (this.smoke.y = -3)),
+ this.view.addChild(this.smoke),
+ this.smoke.turnOn(),
+ this.entity.game.sfx.play("special_jetpack", {
+ loop: !0,
+ });
+ }),
+ (i.pogoSmokeOff = function () {
+ this.smoke && (this.smoke.turnOff(), this.entity.game.sfx.stop("special_jetpack"));
+ }),
+ Pogo
+ );
+ })(J.a);
+
+ function Sneakers_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var Ue = (function (n) {
+ var t, e;
+
+ function Sneakers(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ (i = n.call(this, t, e) || this),
+ t.body.onCollisionEnter.add(
+ (function (t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ })(i)
+ ),
+ (i.mod = 0),
+ i
+ );
+ }
+ (e = n), ((t = Sneakers).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ o,
+ s,
+ a = Sneakers.prototype;
+ return (
+ (a.show = function () {
+ this.left ||
+ ((this.left = H.getEntityCloneOpaque("/powerups_superSneakers", "props_tex", !1)),
+ (this.left.rx = 0.5 * Math.PI),
+ (this.left.ry = 0.5 * Math.PI),
+ (this.left.y -= 0.5),
+ (this.left.z += 0.5),
+ this.left.scale.set(0.5),
+ (this.right = H.getEntityCloneOpaque("/powerups_superSneakers", "props_tex", !1)),
+ (this.right.rx = 0.5 * -Math.PI),
+ (this.right.ry = 0.5 * Math.PI),
+ (this.right.y += 0.5),
+ (this.right.z -= 0.5),
+ this.right.scale.set(0.5));
+ var t = this.entity.anim.scenes[1],
+ e = H.findEntity("L_Toes_jnt", t.pixiTree, 10),
+ i = H.findEntity("R_Toes_jnt", t.pixiTree, 10);
+ e.addChild(this.left), i.addChild(this.right), this.entity.game.hud.addItemTimer("sneakers");
+ }),
+ (a.hide = function () {
+ this.left.parent && this.left.parent.removeChild(this.left), this.right.parent && this.right.parent.removeChild(this.right), this.entity.game.hud.removeItemTimer("sneakers");
+ }),
+ (a.update = function (t) {
+ if (this.time && (!this._activated && this.entity.body.landed && this._activate(), this._activated)) {
+ (this.time -= this.entity.game.deltaSecs), this.jumpUpdate(t), this.entity.game.hud.updateItemTimer("sneakers", this.ratio);
+ var e = 0.5 * (this.entity.body.bottom - this.entity.player.cameraY);
+ this.hitTop && (e *= 0.5),
+ (this.mod = e),
+ (this.rig.mainX = this.entity.game.stats.x * B.cameraModX),
+ (this.rig.mainY = this.entity.game.hero.player.cameraY + B.cameraPosY + this.mod),
+ (this.rig.mainZ = this.entity.game.stats.z + B.cameraPosZ),
+ (this.rig.mainRotX = B.cameraRotX),
+ (this.rig.mainRotY = 0);
+ var i = this.entity.game.level.currentChunk,
+ n = 80 < this.entity.body.y;
+ if (!n && i && i.envTube) {
+ 70 < this.rig.mainY && (this.rig.mainY = 70);
+ }
+ if (!n && i && i.envPillars) {
+ 60 < this.rig.mainY && (this.rig.mainY = 60);
+ }
+ this.time <= 0 && (this.entity.body.landed && !this.ascending ? this.turnOff() : (this.time = 0.01));
+ }
+ }),
+ (a.turnOn = function () {
+ (this.mod = 0),
+ this.entity.pogo.turnOff(),
+ this.entity.jetpack.turnOff(),
+ this.entity.hoverboard.cancel(),
+ (this.hitTop = 0),
+ (this.duration = 10),
+ (this.time = this.duration),
+ (this.gravity = B.gravity),
+ this.show(),
+ this.entity.game.controller.onSwipeVertical.add(this);
+ }),
+ (a.turnOff = function () {
+ this.time &&
+ (this.entity.jump.unlock(),
+ (this.time = 0),
+ (this.mod = 0),
+ this.entity.game.controller.onSwipeVertical.remove(this),
+ this.entity.game.camera.releaseControl(),
+ this.hide(),
+ this.entity.state.set("empty"),
+ (this._activated = !1));
+ }),
+ (a._activate = function () {
+ this.entity.jump.lock(), (this._activated = !0), this.entity.state.set("empty"), (this.rig = this.entity.game.camera.takeControl());
+ }),
+ (a.isOn = function () {
+ return !!this.time;
+ }),
+ (a.onSwipeVertical = function (t) {
+ 1 == t && this.jump();
+ }),
+ (a.jump = function (t, e) {
+ void 0 === t && (t = 40),
+ void 0 === e && (e = !1),
+ this.time &&
+ ((!e && this.locked) ||
+ (!e && this.isJumping) ||
+ ((e || this.entity.body.canJump) &&
+ (this.entity.roll && this.entity.roll.cancel(),
+ this.entity.body.resetGroundChangeTolerance(),
+ (this.isJumping = !0),
+ (this.entity.body.y += 1),
+ (this.entity.body.velocity.y = 0),
+ (this.jumpHeight = 40),
+ (this.jumpLength = 150),
+ (this.startPosY = this.entity.body.y),
+ (this.startPosZ = this.entity.body.z),
+ (this.ascending = !0),
+ this.entity.game.sfx.play("hero_sneakers_jump"))));
+ }),
+ (a.jumpUpdate = function (t) {
+ if (this.isJumping && this.ascending) {
+ var e = (-(this.entity.body.z - this.startPosZ) / this.jumpLength) * 2,
+ i = e <= 1 ? e : 1;
+ 1 <= i && (this.ascending = !1);
+ var n = this.startPosY + this.jumpHeight * St.expoOut(i) - this.entity.body.y;
+ (this.entity.body.velocity.y = t ? n / t : 0), (this.ascending && !this.hitTop) || (this.entity.body.velocity.y = 0);
+ } else this.entity.body.velocity.y -= this.gravity * t;
+ this.entity.body.bottom <= this.entity.body.ground + 0.01 && this.entity.body.velocity.y <= 0 && ((this.entity.body.bottom = this.entity.body.ground), this.isJumping && this.jumpEnd());
+ }),
+ (a.jumpEnd = function () {
+ (this.hitTop = 0), (this.isJumping = !1), (this.ascending = !1), (this.entity.body.velocity.y = 0);
+ }),
+ (a.jumpCancel = function () {
+ this.jumpEnd();
+ }),
+ (a.onCollisionEnter = function (t) {
+ t.flags & $.TOP && ((this.entity.body.velocity.y = 0), (this.hitTop = t.hit.bottom - 10));
+ }),
+ (i = Sneakers),
+ (o = [
+ {
+ key: "ratio",
+ get: function () {
+ return this.time / this.duration;
+ },
+ },
+ ]) && Sneakers_defineProperties(i.prototype, o),
+ s && Sneakers_defineProperties(i, s),
+ Sneakers
+ );
+ })(J.a);
+
+ function Magnet_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var Ve = (function (n) {
+ var t, e;
+
+ function Magnet(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).count = 0), (i.duration = 10), i;
+ }
+ (e = n), ((t = Magnet).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ o,
+ s,
+ a = Magnet.prototype;
+ return (
+ (a.createView = function () {
+ this.view || ((this.view = H.getEntityCloneOpaque("/powerups_coinMagnet", "props_tex", !1)), this.view.scale.set(0.5), (this.view.x = -2), (this.view.rz = 0.5 * Math.PI));
+ }),
+ (a.update = function (t) {
+ this.count && ((this.count -= this.entity.game.stats.delta), this.entity.game.hud.updateItemTimer("magnet", this.ratio), this.count <= 0 && this.turnOff());
+ }),
+ (a.turnOn = function () {
+ this.createView(), this.entity.game.hud.addMessage("POWERUP: COIN MAGNET"), this.entity.game.hud.addItemTimer("magnet"), (this.count = this.duration);
+ var t = this.entity.anim.scenes[1];
+ H.findEntity("R_Hand_jnt", t.pixiTree, 10).addChild(this.view),
+ (this.timer = this.entity.game.sfx.play("special_magnet", {
+ loop: !0,
+ }));
+ }),
+ (a.turnOff = function () {
+ this.count &&
+ (this.entity.game.hud.clearMessage("POWERUP: COIN MAGNET"),
+ this.entity.game.hud.removeItemTimer("magnet"),
+ (this.count = 0),
+ this.view.parent && this.view.parent.removeChild(this.view),
+ this.entity.game.sfx.stop("special_magnet"));
+ }),
+ (a.isOn = function () {
+ return !!this.count;
+ }),
+ (i = Magnet),
+ (o = [
+ {
+ key: "ratio",
+ get: function () {
+ return this.count / this.duration;
+ },
+ },
+ ]) && Magnet_defineProperties(i.prototype, o),
+ s && Magnet_defineProperties(i, s),
+ Magnet
+ );
+ })(J.a);
+
+ function Particles_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+
+ function Particles_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ var qe = {
+ EntityClass: null,
+ container: null,
+ rate: 5,
+ spawns: 1,
+ life: 30,
+ color: null,
+ x: 0,
+ y: 0,
+ z: 0,
+ xMod: [0, 0],
+ yMod: [0, 0],
+ zMod: [0, 0],
+ velocityX: 0,
+ velocityY: 0,
+ velocityZ: 0,
+ velocityXMod: [0, 0],
+ velocityYMod: [0, 0],
+ velocityZMod: [0, 0],
+ forceX: 0,
+ forceY: 0,
+ forceZ: 0,
+ forceXMod: [0, 0],
+ forceYMod: [0, 0],
+ forceZMod: [0, 0],
+ scaleX: 1,
+ scaleY: 1,
+ scaleZ: 1,
+ scaleXMod: [0, 0],
+ scaleYMod: [0, 0],
+ scaleZMod: [0, 0],
+ growX: 0,
+ growY: 0,
+ growZ: 0,
+ growXMod: [0, 0],
+ growYMod: [0, 0],
+ growZMod: [0, 0],
+ },
+ We = (function (n) {
+ function Particles(t, e) {
+ var i;
+ return void 0 === e && (e = {}), (e = Object.assign({}, qe, e)), (i = n.call(this, t, e) || this).setup(e), (i._time = 0), (i.rateCount = 0), (i.list = []), (i.idle = !0), (i.delta = 0), i;
+ }
+ Particles_inheritsLoose(Particles, n);
+ var t,
+ e,
+ i,
+ o = Particles.prototype;
+ return (
+ (o.setup = function (t) {
+ (this.data = Object.assign({}, qe, t)), this.reset();
+ }),
+ (o.reset = function () {
+ this.list = [];
+ }),
+ (o._update = function (t) {
+ this.delta = t;
+ }),
+ (o.update = function (t) {
+ if (!this.idle) {
+ t || (t = this.delta), (this.delta = t);
+ for (var e = this.list.length; e--; ) {
+ var i = this.list[e].particle;
+ i.updateParticle(t), i.data.life <= 0 && this.removeParticle(e);
+ }
+ (this.idle = !this.list.length && !this._time),
+ this._time <= 0 || ((this._time -= t), this._time < 0 && (this._time = 0), (this.rateCount -= t), this.rateCount <= 0 && (this.spawn(this.data.spawns), (this.rateCount = this.data.rate)));
+ }
+ }),
+ (o.run = function (t) {
+ void 0 === t && (t = 9999999), (this._time = t), (this.rateCount = 0), (this.idle = !1);
+ }),
+ (o.stop = function () {
+ this._time = 0;
+ }),
+ (o.clear = function () {
+ this.stop();
+ for (var t = this.list.length; t--; ) this.removeParticle(t);
+ }),
+ (o.removeParticle = function (t) {
+ var e = this.list[t];
+ e && (this.list.splice(t, 1), e.parent && (e.parent.removeChild(e), this.entity.game.pool["return"](e)));
+ }),
+ (o.spawn = function (t, e) {
+ void 0 === t && (t = 1), e || (e = this.data), (this.idle = !1);
+ var i = e.EntityClass,
+ n = this.entity.game.pool.get(i);
+ n.particle || n.add(Ze), n.particle.spawn(e), (e.container || this.entity.game).addChild(n), this.list.push(n), (n.particle.active = !0), 1 < t && this.spawn(t - 1, e);
+ }),
+ (t = Particles),
+ (e = [
+ {
+ key: "time",
+ get: function () {
+ return this._time;
+ },
+ set: function (t) {
+ (this.idle = t <= 0), (this._time = t);
+ },
+ },
+ ]) && Particles_defineProperties(t.prototype, e),
+ i && Particles_defineProperties(t, i),
+ Particles
+ );
+ })(J.a),
+ Ze = (function (n) {
+ function Particle(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).data = Object.assign({}, qe)), i;
+ }
+ Particles_inheritsLoose(Particle, n);
+ var t = Particle.prototype;
+ return (
+ (t.spawn = function (t) {
+ Object.assign(this.data, qe, t),
+ (this.entity.x = this.data.x + L.range(this.data.xMod[0], this.data.xMod[1])),
+ (this.entity.y = this.data.y + L.range(this.data.yMod[0], this.data.yMod[1])),
+ (this.entity.z = this.data.z + L.range(this.data.zMod[0], this.data.zMod[1])),
+ (this.entity.scale.x = this.data.scaleX + L.range(this.data.scaleXMod[0], this.data.scaleXMod[1])),
+ (this.entity.scale.y = this.data.scaleY + L.range(this.data.scaleYMod[0], this.data.scaleYMod[1])),
+ (this.entity.scale.z = this.data.scaleZ + L.range(this.data.scaleZMod[0], this.data.scaleZMod[1])),
+ (this.data.growX = this.data.growX + L.range(this.data.growXMod[0], this.data.growXMod[1])),
+ (this.data.growY = this.data.growY + L.range(this.data.growYMod[0], this.data.growYMod[1])),
+ (this.data.growZ = this.data.growZ + L.range(this.data.growZMod[0], this.data.growZMod[1])),
+ (this.data.velocityX += L.range(this.data.velocityXMod[0], this.data.velocityXMod[1])),
+ (this.data.velocityY += L.range(this.data.velocityYMod[0], this.data.velocityYMod[1])),
+ (this.data.velocityZ += L.range(this.data.velocityZMod[0], this.data.velocityZMod[1])),
+ (this.data.forceX += L.range(this.data.forceXMod[0], this.data.forceXMod[1])),
+ (this.data.forceY += L.range(this.data.forceYMod[0], this.data.forceYMod[1])),
+ (this.data.forceZ += L.range(this.data.forceZMod[0], this.data.forceZMod[1]));
+ }),
+ (t.updateParticle = function (t) {
+ (this.data.life -= t),
+ this.data.life < 0 && (this.data.life = 0),
+ (this.entity.x += this.data.velocityX * t),
+ (this.entity.y += this.data.velocityY * t),
+ (this.entity.z += this.data.velocityZ * t),
+ (this.data.velocityX += this.data.forceX * t),
+ (this.data.velocityY += this.data.forceY * t),
+ (this.data.velocityZ += this.data.forceZ * t),
+ (this.entity.scale.x += this.data.growX * t),
+ (this.entity.scale.y += this.data.growY * t),
+ (this.entity.scale.z += this.data.growZ * t);
+ }),
+ Particle
+ );
+ })(J.a);
+ var Ke = (function (i) {
+ var t, e;
+
+ function ParticleHoverCollision() {
+ var t;
+ ((t = i.call(this) || this).view = H.particle(16, 16, 1, "spraySplash")), t.addChild(t.view);
+ var e = L.pick(16256769, 10287617, 12040194);
+ return H.tint(t.view, e), t;
+ }
+ return (e = i), ((t = ParticleHoverCollision).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e), ParticleHoverCollision;
+ })(v.a);
+ var Je = (function (e) {
+ var t, i;
+
+ function ParticleSpark() {
+ var t;
+ return (
+ ((t = e.call(this) || this).view = H.getEntityCloneBlend("/grindSpark", "effects_tex", 0.8, 1)),
+ (t.view.ry = 0.5 * Math.PI),
+ (t.view.view3d.state.blend = !0),
+ (t.view.view3d.state.depthTest = !0),
+ (t.view.view3d.orderBias = 999),
+ t.addChild(t.view),
+ t.view.scale.set(0.3),
+ H.tint(t.view, 16776960),
+ t
+ );
+ }
+ return (i = e), ((t = ParticleSpark).prototype = Object.create(i.prototype)), ((t.prototype.constructor = t).__proto__ = i), ParticleSpark;
+ })(v.a);
+
+ function Hoverboard_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var Qe = (function (n) {
+ var t, e;
+
+ function Hoverboard(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).count = 0), (i.duration = 30), i;
+ }
+ (e = n), ((t = Hoverboard).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ o,
+ s,
+ a = Hoverboard.prototype;
+ return (
+ (a.show = function () {
+ this.view || (this.view = H.getEntityClone("board_newYork_base")), this.entity.game.hud.addItemTimer("hoverboard"), this.entity.anim.scenes[1].attachPoint1.addChild(this.view), this.entity.state.set("empty");
+ }),
+ (a.hide = function () {
+ this.view.parent && this.view.parent.removeChild(this.view);
+ }),
+ (a.update = function (t) {
+ this.count &&
+ !this.paused &&
+ ((this.view.y = 0.2), (this.view.x = 14), (this.view.z = -7), (this.count -= this.entity.game.stats.delta), this.entity.game.hud.updateItemTimer("hoverboard", this.ratio), this.count <= 0 && this.end());
+ }),
+ (a.updateGrinding = function () {
+ this.entity.grindingSparks || this.createGrindingSparks(),
+ (this.entity.grindingSparks.time = 10),
+ (this.entity.grindingSparks.data.x = this.entity.x - 1),
+ (this.entity.grindingSparks.data.y = this.entity.y - 4.5),
+ (this.entity.grindingSparks.data.z = this.entity.z - 0.5);
+ }),
+ (a.enable = function () {
+ this.entity.game.controller.onDoubleTap.add(this);
+ }),
+ (a.disable = function () {
+ this.entity.game.controller.onDoubleTap.remove(this);
+ }),
+ (a.pause = function () {
+ this.count && (this.paused = !0);
+ }),
+ (a.resume = function () {
+ this.count &&
+ this.paused &&
+ ((this.paused = !1),
+ this.entity.state.set("empty"),
+ this.show(),
+ this.entity.anim.play("h_jump3_bs360grab", {
+ loop: !1,
+ }));
+ }),
+ (a.isOn = function () {
+ return !!this.count && !this.paused;
+ }),
+ (a.explode = function () {
+ this.end(),
+ this.entity.collisionSmoke ||
+ this.entity.add(
+ We,
+ {
+ EntityClass: Ke,
+ container: this.entity.game,
+ rate: 1,
+ life: 60,
+ velocityXMod: [-1.5, 1.5],
+ velocityYMod: [1, 3],
+ velocityZMod: [-1, -2],
+ scaleXMod: [0.8, 1.5],
+ scaleYMod: [0.8, 1.5],
+ scaleZMod: [0.8, 1.5],
+ growXMod: [0.01, 0.03],
+ growYMod: [0.01, 0.03],
+ growZMod: [0.01, 0.03],
+ },
+ "collisionSmoke"
+ ),
+ (this.entity.collisionSmoke.data.x = this.entity.x),
+ (this.entity.collisionSmoke.data.y = this.entity.y),
+ (this.entity.collisionSmoke.data.z = this.entity.z),
+ this.entity.collisionSmoke.spawn(10),
+ this.entity.jump.perform(15, !0),
+ this.entity.player.dizzyEnd();
+ }),
+ (a.onDoubleTap = function () {
+ this.start();
+ }),
+ (a.start = function () {
+ var t = this;
+ this.entity.game.state === pn.RUNNING &&
+ this.entity.game.stats.hoverboards &&
+ (this.entity.pogo.isOn() ||
+ this.entity.jetpack.isOn() ||
+ this.locked ||
+ (this.entity.anim.play("h_skate_on", {
+ loop: !1,
+ enforce: 0.3,
+ sudden: !0,
+ }),
+ setTimeout(function () {
+ t.entity.anim.play("h_landing", {
+ loop: !1,
+ enforce: 0.3,
+ }),
+ t.entity.anim.play("h_run", {
+ loop: !0,
+ });
+ }, 500),
+ this.show(),
+ (this.count = this.duration),
+ (this.paused = !1),
+ (this.entity.game.stats.hoverboards -= 1),
+ this.entity.player.dizzyEnd(),
+ this.entity.state.set("empty"),
+ this.entity.popPickup && this.entity.popPickup.play()));
+ }),
+ (a.cancel = function () {
+ this.count && (this.end(), (this.entity.game.stats.hoverboards += 1));
+ }),
+ (a.end = function () {
+ this.count && (this.hide(), this.entity.game.hud.removeItemTimer("hoverboard"), (this.count = 0), this.entity.state.set("empty"));
+ }),
+ (a.lock = function () {
+ this.locked = !0;
+ }),
+ (a.unlock = function () {
+ this.locked = !1;
+ }),
+ (a.createGrindingSparks = function () {
+ this.entity.grindingSparks ||
+ this.entity.add(
+ We,
+ {
+ EntityClass: Je,
+ container: this.entity.game,
+ rate: 0.5,
+ spawns: 1,
+ life: 20,
+ xMod: [-0.4, 0.4],
+ velocityXMod: [-0.2, 0.2],
+ velocityYMod: [0.03, 0.08],
+ velocityZMod: [-0.1, -0.2],
+ growXMod: [0.1, 0.3],
+ growZMod: [0.3, 0.6],
+ },
+ "grindingSparks"
+ );
+ }),
+ (i = Hoverboard),
+ (o = [
+ {
+ key: "ratio",
+ get: function () {
+ return this.count / this.duration;
+ },
+ },
+ {
+ key: "grinding",
+ get: function () {
+ return !!this.count && !this.paused && this.entity.body.landed && 29 < this.entity.body.ground && this.entity.body.ground < 29.2;
+ },
+ },
+ ]) && Hoverboard_defineProperties(i.prototype, o),
+ s && Hoverboard_defineProperties(i, s),
+ Hoverboard
+ );
+ })(J.a);
+
+ function Multiplier_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var $e = (function (n) {
+ var t, e;
+
+ function Multiplier(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).count = 0), (i.duration = 10), i;
+ }
+ (e = n), ((t = Multiplier).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ o,
+ s,
+ a = Multiplier.prototype;
+ return (
+ (a.update = function (t) {
+ this.count && ((this.count -= this.entity.game.stats.delta), this.entity.game.hud.updateItemTimer("multiplier", this.ratio), this.count <= 0 && this.turnOff());
+ }),
+ (a.turnOn = function () {
+ this.count ? (this.count = this.duration) : ((this.count = this.duration), this.entity.game.hud.addMessage("POWERUP: MULTIPLIER"), this.entity.game.hud.addItemTimer("multiplier"), (this.entity.game.stats.multiplier *= 2));
+ }),
+ (a.turnOff = function () {
+ this.count && (this.entity.game.hud.clearMessage("POWERUP: MULTIPLIER"), this.entity.game.hud.removeItemTimer("multiplier"), (this.entity.game.stats.multiplier /= 2), (this.count = 0));
+ }),
+ (a.isOn = function () {
+ return !!this.count;
+ }),
+ (i = Multiplier),
+ (o = [
+ {
+ key: "ratio",
+ get: function () {
+ return this.count / this.duration;
+ },
+ },
+ ]) && Multiplier_defineProperties(i.prototype, o),
+ s && Multiplier_defineProperties(i, s),
+ Multiplier
+ );
+ })(J.a),
+ ti = i(2);
+
+ function Player_assertThisInitialized(t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ }
+ var ei = (function (n) {
+ var t, e;
+
+ function Player(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ (i = n.call(this, t, e) || this),
+ t.lane.onBumpSideways.add(Player_assertThisInitialized(i)),
+ t.body.onCollisionEnter.add(Player_assertThisInitialized(i)),
+ t.body.onCollisionExit.add(Player_assertThisInitialized(i)),
+ t.body.onTriggerEnter.add(Player_assertThisInitialized(i)),
+ t.body.onTriggerExit.add(Player_assertThisInitialized(i)),
+ i.reset(),
+ i
+ );
+ }
+ (e = n), ((t = Player).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Player.prototype;
+ return (
+ (i.reset = function (t, e, i) {
+ void 0 === t && (t = 0),
+ void 0 === e && (e = 0),
+ void 0 === i && (i = null),
+ this.entity.body.reset(),
+ (this.entity.body.lane = 0),
+ (this.entity.body.x = e),
+ (this.entity.body.z = t),
+ (this.entity.body.lane = i || 0),
+ (this.entity.body.bottom = 0),
+ (this.entity.body.movable = !0),
+ (this.entity.body.glide = 0),
+ (this.entity.body.laning = 0),
+ (this.entity.body.ghost = !1),
+ (this.entity.x = this.entity.body.x),
+ (this.entity.y = this.entity.body.y),
+ (this.entity.z = this.entity.body.z),
+ this.entity.resetModel(),
+ (this.dizzy = 0),
+ (this.jumpLocked = !1),
+ (this.rollLocked = !1),
+ (this.hoverboardLocked = !1),
+ (this.running = !1),
+ (this.cameraY = 0),
+ (this.cameraTargetY = 0),
+ (this.cameraRotX = 0),
+ (this.cameraLow = 0),
+ (this.tunnel = !1),
+ (this.dead = !1),
+ (this.deathCause = ""),
+ (this.catchMode = ""),
+ (this.rewindStartPoint = new ti.P()),
+ (this.rewindEndPoint = null);
+ }),
+ (i.run = function (t) {
+ void 0 === t && (t = 200),
+ this.entity.game.level.onEnterTutorial.contains(this) || (this.entity.game.level.onEnterTutorial.add(this), this.entity.game.level.onExitTutorial.add(this)),
+ (this.entity.body.gravity = this.entity.game.config.gravity),
+ (this.entity.body.velocity.z = -B.speed),
+ (this.entity.body.height = 11),
+ (this.entity.body.bottom = 0),
+ (this.entity.body.movable = !0),
+ (this.running = !0),
+ (this.jumpForce = this.entity.game.config.jump),
+ (this.dizzy = t),
+ this.entity.shadow.turnOn(),
+ this.entity.lane.turnOn(),
+ this.entity.jump.turnOn(),
+ this.entity.roll.turnOn(),
+ this.entity.hoverboard.enable(),
+ this.entity.hoverboard.isOn()
+ ? this.entity.anim.play("h_run", {
+ loop: !0,
+ sudden: !0,
+ })
+ : this.entity.anim.play("run2", {
+ loop: !0,
+ sudden: !0,
+ }),
+ this.entity.game.sfx.stop("special_jetpack");
+ }),
+ (i.stop = function () {
+ (this.running = !1), (this.entity.body.velocity.z = 0);
+ }),
+ (i.update = function (t) {
+ if (
+ (this.rewindEndPoint &&
+ ((this.rewinding = !0),
+ this.entity.body.velocity.reset(),
+ (this.entity.body.ghost = !0),
+ (this.entity.body.x = V.lerp(this.entity.body.x, 0, 0.1 * t)),
+ (this.entity.body.bottom = V.lerp(this.entity.body.bottom, 0, 0.3 * t)),
+ (this.entity.body.z += 4 * t),
+ this.entity.body.z >= this.rewindEndPoint.z - 0.1 &&
+ (this.entity.lane.reset(), (this.entity.body.z = this.rewindEndPoint.z), (this.entity.body.velocity.z = 0), (this.entity.body.ghost = !1), (this.rewinding = !1), this.reset(this.rewindEndPoint.z), this.run())),
+ this.running && !this.dead)
+ ) {
+ if (!this.entity.jetpack.isOn()) {
+ var e = this.entity.game.stats.speed,
+ i = V.lerp(this.entity.body.velocity.z, -e, 0.1 * t);
+ this.entity.body.velocity.z = i;
+ }
+ var n = this.entity.body.ground,
+ o = this.entity.body.bottom;
+ n >= this.cameraTargetY && this.entity.body.landed ? (this.cameraTargetY = n) : o < this.cameraTargetY && (this.cameraTargetY = o);
+ } else this.entity.body.velocity.z = 0;
+ (this.cameraY = V.lerp(this.cameraY, this.cameraTargetY, 0.2 * t)),
+ this.cameraY > this.entity.body.bottom + 3 && (this.cameraY = this.entity.body.bottom + 3),
+ this.dizzy && ((this.dizzy -= t), this.dizzy <= 0 && this.dizzyEnd()),
+ this.bumpCount && ((this.bumpCount -= t), this.bumpCount <= 0 && (this.bumpCount = 0));
+ }),
+ (i.getMode = function () {
+ return this.entity.hoverboard.isOn() ? "hoverboard" : this.entity.sneakers.isOn() ? "sneakers" : "normal";
+ }),
+ (i.dizzyStart = function () {
+ (this.dizzy = 200), this.entity.dizzy.turnOn(), this.entity.game.sfx.play("hero_stumble");
+ }),
+ (i.dizzyEnd = function () {
+ (this.dizzy = 0), this.entity.dizzy.turnOff();
+ }),
+ (i.lockHoverboard = function (t) {
+ this.hoverboardLocked = t;
+ }),
+ (i.goBackToLastCheckPoint = function () {
+ this.entity.anim.play("run3", {
+ loop: !0,
+ }),
+ (this.rewindStartTime = this.entity.game.time),
+ (this.rewindDuration = 600),
+ this.rewindStartPoint.copy(this.entity.body.center);
+ var t = this.entity.game.level.currentChunk.getLastCheckpointByPosition(this.entity.body.z);
+ t && (this.rewindEndPoint = t.body.center);
+ }),
+ (i.stumble = function (t, e) {
+ void 0 === t && (t = "lower"), void 0 === e && (e = !1), (this.bumpCount && e) || (this.entity.game.camera.shake(3), this.dizzy ? this.die(t) : (this.dizzyStart(), (this.bumpCount = 20)));
+ }),
+ (i.crash = function (t) {
+ void 0 === t && (t = "train"), (this.cameraLow = 0), (this.tunnel = !1), this.entity.game.camera.shake(5), this.die(t);
+ }),
+ (i.die = function (t) {
+ var e = this;
+ if (this.entity.hoverboard.isOn())
+ return (
+ this.entity.game.level.reshuffle(),
+ this.entity.hoverboard.explode(),
+ void setTimeout(function () {
+ e.entity.game.exitTunnel(), e.entity.game.sfx.play("hero_hoverboard_crash");
+ }, 1)
+ );
+ (this.entity.body.z += 5),
+ (this.dead = !0),
+ (this.deathCause = t),
+ this.entity.game.sfx.play("hero_death"),
+ this.entity.dizzy.turnOff(),
+ this.entity.jetpack.turnOff(),
+ this.entity.magnet.turnOff(),
+ this.entity.pogo.turnOff(),
+ this.entity.shadow.turnOff(),
+ this.entity.lane.turnOff(),
+ this.entity.jump.turnOff(),
+ this.entity.roll.turnOff(),
+ this.entity.sneakers.turnOff(),
+ this.entity.hoverboard.disable(),
+ this.entity.game.sfx.stop("special_jetpack"),
+ this.entity.game.level.isTutorial()
+ ? setTimeout(function () {
+ e.goBackToLastCheckPoint();
+ }, 700)
+ : setTimeout(function () {
+ e.entity.game.gameover();
+ }, 200);
+ }),
+ (i.onBumpSideways = function (t) {
+ this.stumble("lower");
+ }),
+ (i.onCollisionEnter = function (t) {
+ B.god ||
+ (t.flags & $.FRONT
+ ? ((this.entity.body.velocity.z = 0),
+ this.entity.lane.changing || t.hit.height < 1
+ ? this.stumble("bounce", !0)
+ : t.pas.movable
+ ? this.crash("train")
+ : 6 < t.hit.height
+ ? this.crash("bounce")
+ : t.hit.y > this.entity.body.y
+ ? this.crash("upper")
+ : this.crash("lower"))
+ : t.flags & $.LEFT || t.flags & $.RIGHT
+ ? this.entity.lane.bump(-this.entity.lane.absStep)
+ : t.flags & $.SLOPE && (this.stumble("bounce", !0), (this.entity.body.velocity.z *= 0.5)));
+ }),
+ (i.onCollisionExit = function (t) {}),
+ (i.onTriggerEnter = function (t) {
+ t.entity.lowCamera && !this.entity.jetpack.isOn() ? ((this.cameraLow = -15), (this.tunnel = !0), this.entity.game.enterTunnel()) : t.entity.tutorialTrigger && this.entity.game.tutorial.enterTrigger(t.entity.type);
+ }),
+ (i.onTriggerExit = function (t) {
+ t.entity.lowCamera && ((this.cameraLow = 0), (this.tunnel = !1), this.entity.game.exitTunnel()), t.entity.tutorialTrigger && this.entity.game.tutorial.exitTrigger(t.entity.type);
+ }),
+ (i.onEnterTutorial = function () {}),
+ (i.onExitTutorial = function () {}),
+ Player
+ );
+ })(J.a);
+ var ii = (function (i) {
+ var t, e;
+
+ function Shadow(t, e) {
+ return void 0 === e && (e = {}), i.call(this, t, e) || this;
+ }
+ (e = i), ((t = Shadow).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n = Shadow.prototype;
+ return (
+ (n.createView = function () {
+ this.view || ((this.view = H.plane(8, 8, 0.8, "shadow_mip.png")), (this.view.rx = V.PI_HALF), (this.view.z = 1), this.entity.addChild(this.view));
+ }),
+ (n.update = function (t) {
+ if (this.view && this.view.active) {
+ var e = this.entity.body ? this.entity.body.ground : 0;
+ this.view.y = -this.entity.y + e + 1;
+ }
+ }),
+ (n.turnOn = function () {
+ this.createView(), (this.view.active = !0);
+ }),
+ (n.turnOff = function () {
+ this.view.active = !1;
+ }),
+ (n.isOn = function () {
+ return this.view.active;
+ }),
+ Shadow
+ );
+ })(J.a),
+ ni = i(18),
+ oi = i(129),
+ si = i.n(oi),
+ ai = i(130),
+ ri = i.n(ai);
+ c.Shader;
+ var hi = {
+ character_idle: i(475),
+ character_jetpack: i(476),
+ character_movement: i(477),
+ character_catch: i(478),
+ character_pogo: i(479),
+ character_start: i(480),
+ guard_movement: i(481),
+ guard_catch: i(482),
+ dog_movement: i(483),
+ dog_catch: i(484),
+ };
+
+ function Anim_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var di = (function (n) {
+ var t, e;
+
+ function Anim(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).scene = null), (i.fpsGame = 60), (i.currentAction = null), (i.scenes = {}), (i.clips = {}), (i.actions = {}), i;
+ }
+ (e = n), ((t = Anim).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ o,
+ s,
+ a = Anim.prototype;
+ return (
+ (a.reset = function () {
+ (this.currentAction = null), this.stop();
+ }),
+ (a.addAnim = function (t, e) {
+ if (!this.scenes[t]) {
+ var i = e.offset || 0,
+ n = H.getScene(e.file);
+ if (!n) throw new Error("Scene not found: " + e.file);
+ H.applyTexture(n.pixiTree, e.texture, !1);
+ var o = H.findEntity("Mess", n.pixiTree);
+ for (var s in (o && o.parent && o.parent.removeChild(o),
+ n.initMixer(),
+ ((this.scenes[t] = n).attachPoint1 = H.findEntity("attachPoint1", n.pixiTree)),
+ (n.attachPoint2 = H.findEntity("attachPoint2", n.pixiTree)),
+ (n.attachPoint3 = H.findEntity("attachPoint3", n.pixiTree)),
+ (n.pixiTree.active = !1),
+ e.clips)) {
+ var a = e.fps,
+ r = n.sceneGraph.animations[0],
+ h = e.clips[s],
+ d = h[0] + i,
+ l = h[1] + i,
+ c = ni.g(r, s, d, l, a);
+ (c.__scene = n), (c.__name = s), (this.clips[s] = c);
+ }
+ this.updateActions();
+ }
+ }),
+ (a.updateActions = function () {
+ for (var t in this.clips)
+ if (!this.actions[t]) {
+ var e = this.clips[t],
+ i = e.__scene.mixer.clipAction(e);
+ i.setLoop(ti.s), (i.clampWhenFinished = !0), (i.__scene = e.__scene), (i.__name = t), (this.actions[t] = i);
+ }
+ }),
+ (a.play = function (t, e) {
+ var i = this;
+ if ((void 0 === e && (e = {}), Array.isArray(t) && (t = L.pick.apply(L, t)), !this.actions[t])) throw new Error("Animation not found: " + t);
+ if ((void 0 === e.loop && (e.loop = !1), void 0 === e.sudden && (e.sudden = !1), void 0 === e.crossfade && (e.crossfade = 0.2), void 0 === e.enforce && (e.enforce = 0), this._enforce))
+ this._queued = {
+ name: t,
+ opts: e,
+ };
+ else {
+ e.enforce &&
+ ((this._enforce = e.enforce),
+ setTimeout(function () {
+ (i._enforce = 0), i._queued && (i.play(i._queued.name, i._queued.opts), (i._queued = null));
+ }, 1e3 * this._enforce));
+ var n = this.actions[t];
+ if (n !== this.currentAction) {
+ var o = n.__scene,
+ s = this.currentAction && this.currentAction.__scene === o;
+ return (
+ o.mixer.stopAllAction(),
+ this.currentAction && (this.currentAction.stop(), this.currentAction.reset()),
+ n.stop(),
+ n.reset(),
+ n.setLoop(e.loop ? ti.s : ti.r),
+ this.currentAction && !e.sudden && s && n.crossFadeFrom(this.currentAction, e.crossfade, !0),
+ n.play(),
+ o.mixer.update(0.01),
+ o.syncToPixi(),
+ this.showScene(o),
+ (this.currentAction = n)
+ );
+ }
+ }
+ }),
+ (a.showScene = function (e) {
+ var i = this;
+ (e.pixiTree.active = !0),
+ (this.entity.model || this.entity).addChild(e.pixiTree),
+ setTimeout(function () {
+ for (var t in i.scenes) i.scenes[t].pixiTree.active = !1;
+ e.pixiTree.active = !0;
+ }, 20);
+ }),
+ (a.stop = function () {
+ this.currentAction && (this.currentAction.stop(), this.currentAction.reset(), (this.currentAction = null));
+ }),
+ (a.update = function (t) {
+ if (this.scenes && this.currentAction) {
+ var e = this.currentAction.__scene;
+ e.mixer.update(t / this.fpsGame), e.syncToPixi();
+ }
+ }),
+ (a.sum = function (t) {
+ this.extra = t;
+ var e = this.actions[this.extra];
+ e.setEffectiveWeight(0.75), e.setLoop(!0), e.play();
+ }),
+ (a.subtract = function (t) {
+ this.actions[this.extra].stop(), (this.extra = null);
+ }),
+ (i = Anim),
+ (o = [
+ {
+ key: "currentName",
+ get: function () {
+ return this.currentAction ? this.currentAction.__name : null;
+ },
+ },
+ ]) && Anim_defineProperties(i.prototype, o),
+ s && Anim_defineProperties(i, s),
+ Anim
+ );
+ })(J.a);
+
+ function State_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var li = function () {},
+ ci = (function (n) {
+ var t, e;
+
+ function State(t, e) {
+ var i;
+ return (
+ ((i = n.call(this, t, e) || this).states = {}),
+ (i.currentStateId = "empty"),
+ (i.transitionMap = {}),
+ i.add("empty", {
+ end: li,
+ begin: li,
+ update: li,
+ render: li,
+ }),
+ (i.params = {}),
+ i
+ );
+ }
+ (e = n), ((t = State).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ o,
+ s,
+ a = State.prototype;
+ return (
+ (a.addTransition = function (t, e, i) {
+ return this.transitionMap[t] || (this.transitionMap[t] = {}), (this.transitionMap[t][e] = !0), i && (this.transitionMap[e][t] = !0), this;
+ }),
+ (a.add = function (t, e) {
+ return (
+ ((this.states[t] = e).id = t),
+ (e.entity = this.entity),
+ e.empty || (e.empty = li),
+ e.begin || (e.begin = li),
+ e.update || (e.update = li),
+ e.render || (e.render = li),
+ e.end || (e.end = li),
+ this.transitionMap[t] || (this.transitionMap[t] = {}),
+ this.addTransition("empty", t, !0),
+ this
+ );
+ }),
+ (a.set = function (t) {
+ this.can(t) && (this.states[this.currentStateId].end(), (this.currentStateId = t), this.states[this.currentStateId].begin());
+ }),
+ (a.can = function (t) {
+ if (this.currentStateId === t) return !1;
+ var e = this.transitionMap.all[t],
+ i = this.transitionMap[this.currentStateId].all,
+ n = this.transitionMap[this.currentStateId][t];
+ return e || i || n;
+ }),
+ (a.update = function (t) {
+ if (this.entity.onStateUpdate) {
+ this.entity.onStateUpdate();
+ var e = this.params,
+ i = this.states;
+ for (var n in i)
+ if ("empty" !== n) {
+ var o = i[n],
+ s = !0;
+ for (var a in e)
+ if (void 0 !== o[a] && o[a] !== e[a]) {
+ s = !1;
+ break;
+ }
+ if (s && this.currentStateId !== n) {
+ var r = this.transitionMap.all[n],
+ h = this.transitionMap[this.currentStateId].all,
+ d = this.transitionMap[this.currentStateId][n];
+ if (r || h || d) {
+ this.set(n);
+ break;
+ }
+ }
+ }
+ }
+ this.states[this.currentStateId].update(t);
+ }),
+ (a.render = function (t) {
+ this.states[this.currentStateId].render(t);
+ }),
+ (i = State),
+ (o = [
+ {
+ key: "id",
+ get: function () {
+ return this.currentStateId;
+ },
+ },
+ ]) && State_defineProperties(i.prototype, o),
+ s && State_defineProperties(i, s),
+ State
+ );
+ })(J.a);
+ var ui = (function (i) {
+ var t, e;
+
+ function Dizzy(t, e) {
+ return void 0 === e && (e = {}), i.call(this, t, e) || this;
+ }
+ (e = i), ((t = Dizzy).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n = Dizzy.prototype;
+ return (
+ (n.createView = function () {
+ this.view ||
+ ((this.view = new v.a()),
+ (this.view.y = 4),
+ (this.view.x = 0.5),
+ (this.trail1 = H.getEntityCloneBlend("effects/Dizzytrail", "effects_tex", 0.9, 1)),
+ this.view.addChild(this.trail1),
+ (this.trail2 = H.getEntityCloneBlend("effects/Dizzytrail", "effects_tex", 0.9, 1)),
+ (this.trail2.ry = Math.PI),
+ this.view.addChild(this.trail2),
+ (this.star1 = H.getEntityCloneBlend("effects/Dizzystar", "effects_tex", 0.9, 1)),
+ (this.star1.z = -1.5),
+ this.view.addChild(this.star1),
+ (this.star2 = H.getEntityCloneBlend("effects/Dizzystar", "effects_tex", 0.9, 1)),
+ (this.star2.z = 1.5),
+ this.view.addChild(this.star2),
+ (this.view.active = !1),
+ (this.view.rx = -0.5),
+ this.view.scale.set(1.25));
+ }),
+ (n.reset = function () {
+ this.view && (this.view.active = !1);
+ }),
+ (n.update = function (t) {
+ this.view && this.view.active && (this.view.ry += 0.05 * t);
+ }),
+ (n.turnOn = function () {
+ if ((this.createView(), !this.view.parent)) {
+ var t = this.entity.anim.scenes[1];
+ H.findEntity("Head_jnt", t.pixiTree, 10).addChild(this.view);
+ }
+ this.view.active = !0;
+ }),
+ (n.turnOff = function () {
+ this.view && (this.view.parent && this.view.parent.removeChild(this.view), (this.view.active = !1));
+ }),
+ Dizzy
+ );
+ })(J.a);
+ var pi = (function (n) {
+ var t, e;
+
+ function PopPickup(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).view = H.getEntityCloneBlend("/powBlue", "effects_tex", 0.95, 1)), (i.view.rotation.y = Math.PI), (i.duration = 13), i.reset(), i;
+ }
+ (e = n), ((t = PopPickup).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = PopPickup.prototype;
+ return (
+ (i.reset = function () {
+ this.view.parent && this.entity.removeChild(this.view), (this.view.active = !1), this.view.scale.set(0), (this.count = 0);
+ }),
+ (i.update = function (t) {
+ if (this.count) {
+ this.count -= t;
+ var e = 1 + 20 * (1 - this.count / this.duration);
+ this.view.scale.set(e), this.count <= 0 && this.reset();
+ }
+ }),
+ (i.play = function () {
+ (this.view.rotation.z = V.PI_DOUBLE * Math.random()), (this.count = this.duration), (this.view.active = !0), this.view.scale.set(0.5), this.entity.addChild(this.view);
+ }),
+ PopPickup
+ );
+ })(J.a);
+ var mi = (function (i) {
+ var t, e;
+
+ function ParticleRevive() {
+ var t;
+ ((t = i.call(this) || this).view = H.particle(16, 16, 1, "spraySplash")), t.addChild(t.view);
+ var e = L.pick(1407438, 4308976, 2726108);
+ return H.tint(t.view, e), t;
+ }
+ return (e = i), ((t = ParticleRevive).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e), ParticleRevive;
+ })(v.a);
+ var fi = (function (n) {
+ var t, e;
+
+ function ReviveHalo(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).view = H.getEntityCloneBlend("powRevive", "effects_tex", 0.7, 3)),
+ (i.view.view3d.state.depthTest = !1),
+ (i.view.rotation.y = Math.PI),
+ (i.view.rotation.x = -0.3),
+ t.addChild(i.view),
+ (i.scale = 2),
+ i.view.scale.set(i.scale),
+ (i.view.y = 2),
+ (i.view.active = !1),
+ (i.time = 0),
+ (i.duration = 120),
+ i
+ );
+ }
+ (e = n), ((t = ReviveHalo).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = ReviveHalo.prototype;
+ return (
+ (i.update = function (t) {
+ if (this.time) {
+ (this.time -= t), (this.scale = 0.2 * Math.sin(0.1 * this.time) + 2), this.view.scale.set(this.scale);
+ var e = 0.1 * this.duration,
+ i = 1 - (this.time - e) / (this.duration - e),
+ n = this.time / e,
+ o = this.time > e ? i : n;
+ (this.view.view3d.material.opacity = 0.6 * o), (this.view.rotation.z += 0.01 * t), this.time < 0 && this.stop();
+ }
+ }),
+ (i.play = function () {
+ (this.view.active = !0), (this.time = this.duration);
+ }),
+ (i.stop = function () {
+ (this.time = 0), (this.view.active = !1);
+ }),
+ ReviveHalo
+ );
+ })(J.a),
+ gi = (function () {
+ function Time() {
+ (this.scale = 1), (this.current = 0), (this.delta = 0), (this._schedule = []);
+ }
+ var t = Time.prototype;
+ return (
+ (t.reset = function () {
+ (this.scale = 1), (this.current = 0), (this.delta = 0), (this._schedule = []);
+ }),
+ (t.update = function (t) {
+ (this.delta = t * this.scale), (this.current += this.delta);
+ for (var e = this._schedule.length; e--; ) {
+ var i = this._schedule[e];
+ i.time >= this.current && (i.fn.call(i.context, i.params), this._schedule.splice(e, 1));
+ }
+ }),
+ (t.schedule = function (t, e, i, n) {
+ void 0 === i && (i = null), void 0 === n && (n = null);
+ var o = {
+ fn: t,
+ time: this.current + e,
+ context: i,
+ params: n,
+ };
+ this._schedule.push(o);
+ }),
+ (Time.secs = function () {
+ return new Date().getTime() / 1e3;
+ }),
+ Time
+ );
+ })();
+
+ function Lane_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var yi = (function (i) {
+ var t, e;
+
+ function Lane(t) {
+ var e;
+ return ((e = i.call(this, t) || this).entity = t), (e.onBumpSideways = new et.a("onBumpSideways", 1)), e.reset(), e;
+ }
+ (e = i), ((t = Lane).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n,
+ o,
+ s,
+ a = Lane.prototype;
+ return (
+ (a.reset = function () {
+ (this.lane = 0), (this.last = 0), (this.absStep = 0), (this.changing = !1), (this.changeStartX = 0), (this.changeEndX = 0), (this.changeDuration = 0), (this.changeTime = 0), (this.queuedStep = 0), (this.queuedDuration = 0);
+ }),
+ (a.turnOn = function () {
+ this._isOn || ((this._isOn = !0), this.entity.game.controller.onSwipeHorizontal.add(this));
+ }),
+ (a.turnOff = function () {
+ this._isOn && ((this._isOn = !1), this.entity.game.controller.onSwipeHorizontal.remove(this));
+ }),
+ (a.onSwipeHorizontal = function (t) {
+ this.change(t);
+ }),
+ (a.change = function (t) {
+ if (!this.entity.jetpack.isOn() && !this.entity.pogo.isOn()) {
+ if (1 === this.lane && 0 < t) return void (this.entity.body.x > B.laneWidth - 1 && this.onBumpSideways.dispatch(t));
+ if (-1 === this.lane && t < 0) return void (this.entity.body.x < 1 - B.laneWidth && this.onBumpSideways.dispatch(t));
+ }
+ var e = 0.3 * (1 - this.entity.game.stats.speed / B.maxSpeed) + 0.1,
+ i = Math.round(this.lane + t),
+ n = Math.clamp(i, -1, 1),
+ o = n * B.laneWidth,
+ s = Math.abs(o - this.entity.body.x);
+ if (s > B.laneWidth) return (this.queuedStep = t), void (this.queuedDuration = e);
+ this.entity.state.set("empty"),
+ (this.absStep = t < 0 ? -1 : 1),
+ (this.last = this.lane),
+ (this.lane = n),
+ (this.queuedStep = 0),
+ (this.queuedDuration = 0),
+ (this.changing = !0),
+ (this.changeStartX = this.entity.body.x),
+ (this.changeEndX = o),
+ (this.changeDuration = Math.max((e * s) / B.laneWidth, 0.1)),
+ this.entity.jetpack.isOn() && (this.changeDuration *= 0.7),
+ (this.changeTime = 0),
+ (this._secs = gi.secs()),
+ this.entity.game.sfx.play("hero_dodge");
+ }),
+ (a.update = function (t) {
+ if (this.changing) {
+ (this.changeTime += this.entity.game.deltaSecs), this.changeTime > this.changeDuration && (this.changeTime = this.changeDuration);
+ var e = V.clamp(this.changeTime / this.changeDuration),
+ i = V.lerp(this.changeStartX, this.changeEndX, e);
+ this.entity.body.velocity.x = t ? (i - this.entity.body.x) / t : 0;
+ var n = 0.05 * -(this.changeEndX - this.entity.body.x),
+ o = this.entity.jetpack.isOn() || this.entity.pogo.isOn() || this.entity.hoverboard.isOn();
+ (this.entity.ry = o ? 0 : n), this.changeTime >= this.changeDuration && this.changeEnd();
+ }
+ }),
+ (a.changeEnd = function () {
+ (this.entity.body.x = this.lane * B.laneWidth),
+ (this.changing = !1),
+ (this.entity.ry = 0),
+ (this.entity.body.velocity.x = 0),
+ this.queuedDuration && (this.change(this.queuedStep, this.queuedDuration), (this.queuedStep = 0), (this.queuedDuration = 0));
+ }),
+ (a.changeCancel = function () {
+ (this.changing = !1), (this.queuedStep = 0), (this.queuedDuration = 0), (this.entity.ry = 0), (this.entity.body.velocity.x = 0);
+ }),
+ (a.bump = function (t) {
+ this.changeCancel(), this.change(t, 0.1), this.onBumpSideways.dispatch(t), (this.entity.body.velocity.x = 0);
+ }),
+ (n = Lane),
+ (o = [
+ {
+ key: "lanePos",
+ get: function () {
+ return this.entity.body.x / B.laneWidth;
+ },
+ set: function (t) {
+ (t = Mathf.clamp(t, -1, 1)), (this.entity.body.x = B.laneWidth * t);
+ },
+ },
+ ]) && Lane_defineProperties(n.prototype, o),
+ s && Lane_defineProperties(n, s),
+ Lane
+ );
+ })(J.a);
+ var vi = (function (i) {
+ var t, e;
+
+ function Jump(t) {
+ var e;
+ return (e = i.call(this, t) || this).reset(), e;
+ }
+ (e = i), ((t = Jump).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n = Jump.prototype;
+ return (
+ (n.reset = function () {
+ (this.locked = !1), (this.isJumping = !1), (this.goingUpwards = !1), (this.gravity = B.gravity);
+ }),
+ (n.turnOn = function () {
+ this._isOn || ((this._isOn = !0), this.entity.game.controller.onSwipeVertical.add(this));
+ }),
+ (n.turnOff = function () {
+ this._isOn && ((this._isOn = !1), this.entity.game.controller.onSwipeVertical.remove(this));
+ }),
+ (n.onSwipeVertical = function (t) {
+ 1 == t && this.perform();
+ }),
+ (n.update = function (t) {
+ if (!this.locked) {
+ if (this.isJumping && this.goingUpwards) {
+ (this.time += this.entity.game.deltaSecs), this.time > this.duration && (this.time = this.duration);
+ var e = this.time / this.duration,
+ i = St.sineOut(e),
+ n = V.lerp(this.startY, this.endY, i);
+ (this.entity.body.velocity.y = t ? (n - this.entity.body.y) / t : 0), 1 <= e && ((this.entity.body.velocity.y = 0), (this.goingUpwards = !1));
+ } else this.entity.body.velocity.y -= this.gravity * t;
+ this.entity.body.bottom <= this.entity.body.ground + 0.01 && this.entity.body.velocity.y <= 0 && ((this.entity.body.velocity.y = 0), (this.entity.body.bottom = this.entity.body.ground), this.isJumping && this.end());
+ }
+ }),
+ (n.perform = function (t, e) {
+ void 0 === t && (t = 20),
+ void 0 === e && (e = !1),
+ B.freejump && (e = !0),
+ (!e && this.locked) ||
+ (!e && this.isJumping) ||
+ ((e || this.entity.body.canJump) &&
+ (this.entity.roll && this.entity.roll.cancel(),
+ this.entity.body.resetGroundChangeTolerance(),
+ (this.isJumping = !0),
+ (this.entity.body.velocity.y = 0),
+ (this.entity.body.y += 1),
+ (this.startY = this.entity.body.y),
+ (this.endY = this.startY + t - 1),
+ (this.time = 0),
+ (this.duration = 0.41),
+ (this.goingUpwards = !0),
+ this.entity.game.sfx.play("hero_jump")));
+ }),
+ (n.end = function () {
+ (this.isJumping = !1), (this.goingUpwards = !1);
+ }),
+ (n.cancel = function () {
+ this.end();
+ }),
+ (n.lock = function () {
+ this.end(), (this.locked = !0);
+ }),
+ (n.unlock = function () {
+ (this.locked = !1), (this.gravity = B.gravity);
+ }),
+ Jump
+ );
+ })(J.a);
+ var _i = (function (i) {
+ var t, e;
+
+ function Roll(t) {
+ var e;
+ return ((e = i.call(this, t) || this).onStart = new et.a("onRollStart")), (e.onEnd = new et.a("onRollEnd")), e.reset(), e;
+ }
+ (e = i), ((t = Roll).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n = Roll.prototype;
+ return (
+ (n.reset = function () {
+ (this.locked = !1), (this.isRolling = !1), (this.gravity = B.gravity), (this.duration = 30), (this.time = 0), (this.rollingHeight = 5), (this.regularHeight = 11), (this.entity.body.height = this.regularHeight);
+ }),
+ (n.turnOn = function () {
+ this._isOn || ((this._isOn = !0), this.entity.game.controller.onSwipeVertical.add(this));
+ }),
+ (n.turnOff = function () {
+ this._isOn && ((this._isOn = !1), this.entity.game.controller.onSwipeVertical.remove(this));
+ }),
+ (n.onSwipeVertical = function (t) {
+ -1 == t && this.perform();
+ }),
+ (n.update = function (t) {
+ this.isRolling && ((this.time += t), this.time > this.duration && (this.time = this.duration), this.time === this.duration && this.end());
+ }),
+ (n.perform = function () {
+ if (!this.locked && !this.isRolling) {
+ this.onStart.dispatch(),
+ this.entity.jump && this.entity.jump.cancel(),
+ this.entity.sneakers.isOn() && this.entity.sneakers.jumpCancel(),
+ (this.isRolling = !0),
+ (this.time = 0),
+ this.entity.body.landed || (this.entity.body.velocity.y = -2);
+ var t = this.entity.body.bottom;
+ (this.entity.body.height = this.rollingHeight), (this.entity.body.bottom = t), this.entity.game.sfx.play("hero_roll");
+ }
+ }),
+ (n.end = function () {
+ (this.isRolling = !1), (this.entity.body.height = this.regularHeight), this.entity.body.bottom < this.entity.body.ground && (this.entity.body.bottom = this.entity.body.ground), (this.time = 0), this.onEnd.dispatch();
+ }),
+ (n.cancel = function () {
+ this.end();
+ }),
+ (n.lock = function () {
+ this.end(), (this.locked = !0);
+ }),
+ (n.unlock = function () {
+ this.locked = !1;
+ }),
+ (n.isOn = function () {
+ return this._isOn;
+ }),
+ Roll
+ );
+ })(J.a);
+ var bi = (function (n) {
+ var t, e;
+
+ function Notifier(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).ignore = ["transform", "container", "notifier"]), (i.entity = t), i;
+ }
+ (e = n), ((t = Notifier).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Notifier.prototype;
+ return (
+ (i.cacheComponents = function () {
+ for (var t in ((this.comps = {}), this.entity))
+ if (!(0 <= this.ignore.indexOf(t))) {
+ var e = this.entity[t];
+ e instanceof J.a && (this.comps[t] = e);
+ }
+ }),
+ (i.notify = function (t) {
+ this.comps || this.cacheComponents();
+ for (var e = arguments.length, i = new Array(1 < e ? e - 1 : 0), n = 1; n < e; n++) i[n - 1] = arguments[n];
+ for (var o in this.comps) {
+ var s = this.comps[o];
+ if (s) {
+ var a = s[t];
+ a && a.apply(s, i);
+ }
+ }
+ }),
+ Notifier
+ );
+ })(J.a);
+ var wi = (function (i) {
+ var t, e;
+
+ function Character() {
+ var t;
+ (t = i.call(this) || this).add(it, {
+ boxColor: 5570560,
+ sensor: !0,
+ }),
+ (t.model = new v.a()),
+ t.addChild(t.model),
+ t.add(ci),
+ t.add(Ye),
+ t.add(di),
+ t.add(He),
+ t.add(Ue),
+ t.add(Ve),
+ t.add(Qe),
+ t.add($e),
+ t.add(ii),
+ t.add(ui),
+ t.add(yi),
+ t.add(vi),
+ t.add(_i),
+ t.add(ei),
+ t.add(bi),
+ (t.body.width = 4),
+ (t.body.height = 11),
+ (t.body.depth = 4),
+ t.anim.addAnim("0", hi.character_idle),
+ t.updateModel(),
+ (t.sprayCan = H.getEntityCloneOpaque("sprayCan", "props_tex", !1)),
+ (t.sprayCan.x = 0.2),
+ (t.sprayCan.z = -0.5),
+ (t.sprayCan.y = -0.5),
+ (t.sprayCan.rz = 0.5 * Math.PI),
+ (t.sprayCan.ry = 0.15 * Math.PI);
+ var e = t.anim.scenes[0];
+ return H.findEntity("R_Hand_jnt", e.pixiTree, 10).addChild(t.sprayCan), t;
+ }
+ (e = i), ((t = Character).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n = Character.prototype;
+ return (
+ (n.resetModel = function () {
+ (this.model.ry = Math.PI), (this.model.rx = 0), (this.model.rz = 0), (this.model.x = -1), (this.model.y = 0.5 * -this.body.height + 1), (this.model.z = 0);
+ }),
+ (n.init = function () {
+ this._initialized ||
+ ((this._initialized = !0),
+ this.add(ut),
+ this.add(pi),
+ (this.pop.view.y = 0),
+ (this.pop.view.z = -3),
+ this.anim.addAnim("1", hi.character_movement),
+ this.anim.addAnim("2", hi.character_jetpack),
+ this.anim.addAnim("3", hi.character_catch),
+ this.anim.addAnim("4", hi.character_pogo),
+ this.anim.addAnim("5", hi.character_start),
+ (this.anim.debug = !0));
+ }),
+ (n.playIntro = function () {
+ this.init(),
+ this.lane.reset(),
+ this.resetModel(),
+ (this.z = 0),
+ (this.x = -1),
+ (this.body.z = 0),
+ (this.body.x = 0),
+ (this.body.bottom = 0),
+ (this.y = this.body.bottom + 0.5 * this.body.height),
+ this.anim.play("start_run", {
+ sudden: !0,
+ crossfade: 0,
+ });
+ }),
+ (n.run = function () {
+ (this.body.velocity.z = -this.game.stats.speed), this.player.run();
+ }),
+ (n.reset = function () {
+ (this.model.x = 0),
+ (this.z = 0),
+ (this.x = 1),
+ (this.body.z = 0),
+ (this.body.x = 1),
+ (this.body.bottom = 0),
+ this.pogo.turnOff(),
+ this.magnet.turnOff(),
+ this.jetpack.turnOff(),
+ this.sneakers.turnOff(),
+ this.dizzy.turnOff(),
+ this.multiplier.turnOff(),
+ this.hoverboard.end(),
+ this.notifier.notify("reset"),
+ this.reviveHalo && this.reviveHalo.stop();
+ }),
+ (n.restoreSize = function () {
+ (this.body.width = 4), (this.body.height = 11), (this.body.depth = 4), (this.model.position.y = 0.5 * -this.body.height + 1);
+ }),
+ (n.updateModel = function () {
+ (this.model.position.y = 0.5 * -this.body.height + 1), (this.model.rotation.y = Math.PI);
+ }),
+ (n.onStateUpdate = function () {
+ var t;
+ this.statesReady ||
+ (((t = this).state.params = {
+ playing: !1,
+ landed: !1,
+ ascending: !1,
+ descending: !1,
+ dodging: !1,
+ rolling: !1,
+ hoverboard: !1,
+ dizzy: !1,
+ special: !1,
+ pogo: !1,
+ dead: !1,
+ catch: !1,
+ }),
+ t.state.add("idle", new ki()),
+ t.state.add("dead", new Ii()),
+ t.state.add("catch", new Li()),
+ t.state.add("running", new xi()),
+ t.state.add("grinding", new Ci()),
+ t.state.add("dodging", new Si()),
+ t.state.add("ascending", new zi()),
+ t.state.add("hangtime", new Ti()),
+ t.state.add("descending", new Pi()),
+ t.state.add("rolling", new Mi()),
+ t.state.add("jetpack", new Ei()),
+ t.state.add("jetpackDodging", new Oi()),
+ t.state.add("pogo", new Ri()),
+ t.state.addTransition("all", "idle"),
+ t.state.addTransition("idle", "running"),
+ t.state.addTransition("running", "dodging"),
+ t.state.addTransition("running", "rolling"),
+ t.state.addTransition("running", "airborne"),
+ t.state.addTransition("running", "jetpack"),
+ t.state.addTransition("running", "pogo"),
+ t.state.addTransition("running", "grinding", !0),
+ t.state.addTransition("dodging", "rolling"),
+ t.state.addTransition("dodging", "running"),
+ t.state.addTransition("dodging", "airborne"),
+ t.state.addTransition("dodging", "jetpack"),
+ t.state.addTransition("dodging", "pogo"),
+ t.state.addTransition("airborne", "rolling"),
+ t.state.addTransition("airborne", "running"),
+ t.state.addTransition("airborne", "dodging"),
+ t.state.addTransition("airborne", "jetpack"),
+ t.state.addTransition("airborne", "pogo"),
+ t.state.addTransition("ascending", "rolling", !0),
+ t.state.addTransition("ascending", "running", !0),
+ t.state.addTransition("ascending", "dodging", !0),
+ t.state.addTransition("ascending", "jetpack", !0),
+ t.state.addTransition("ascending", "pogo", !0),
+ t.state.addTransition("hangtime", "ascending", !0),
+ t.state.addTransition("hangtime", "rolling", !0),
+ t.state.addTransition("hangtime", "running", !0),
+ t.state.addTransition("hangtime", "dodging", !0),
+ t.state.addTransition("hangtime", "jetpack", !0),
+ t.state.addTransition("hangtime", "pogo", !0),
+ t.state.addTransition("descending", "ascending", !0),
+ t.state.addTransition("descending", "hangtime", !0),
+ t.state.addTransition("descending", "rolling", !0),
+ t.state.addTransition("descending", "running", !0),
+ t.state.addTransition("descending", "dodging", !0),
+ t.state.addTransition("descending", "jetpack", !0),
+ t.state.addTransition("descending", "pogo", !0),
+ t.state.addTransition("rolling", "running"),
+ t.state.addTransition("rolling", "airborne"),
+ t.state.addTransition("rolling", "dodging"),
+ t.state.addTransition("rolling", "jetpack"),
+ t.state.addTransition("rolling", "pogo"),
+ t.state.addTransition("jetpack", "ascending"),
+ t.state.addTransition("jetpack", "hangtime"),
+ t.state.addTransition("jetpack", "descending"),
+ t.state.addTransition("jetpack", "airborne"),
+ t.state.addTransition("jetpack", "jetpackDodging"),
+ t.state.addTransition("jetpackDodging", "jetpack"),
+ t.state.addTransition("jetpackDodging", "airborne"),
+ t.state.addTransition("jetpackDodging", "ascending"),
+ t.state.addTransition("jetpackDodging", "hangtime"),
+ t.state.addTransition("jetpackDodging", "descending"),
+ t.state.addTransition("pogo", "airborne"),
+ t.state.addTransition("pogo", "jetpack"),
+ t.state.addTransition("pogo", "rolling"),
+ t.state.addTransition("dead", "catch"),
+ t.state.addTransition("catch", "all"),
+ t.state.addTransition("all", "dead"),
+ t.state.addTransition("dead", "idle"),
+ t.state.addTransition("dead", "running"),
+ t.state.addTransition("grinding", "dodging", !0),
+ t.state.addTransition("grinding", "rolling", !0),
+ t.state.addTransition("grinding", "airborne", !0),
+ t.state.addTransition("grinding", "jetpack", !0),
+ t.state.addTransition("grinding", "pogo", !0),
+ t.state.addTransition("grinding", "ascending", !0),
+ t.state.addTransition("grinding", "descending", !0)),
+ (this.statesReady = !0);
+ var e = this.state.params;
+ (e.landed = this.body.landed),
+ (e.ascending = !this.body.hangtime && this.body.ascending),
+ (e.descending = !this.body.hangtime && this.body.descending),
+ (e.rolling = this.roll.isRolling),
+ (e.dead = !!this.player.deathCause),
+ (e.hoverboard = this.hoverboard.isOn()),
+ (e.dodging = this.lane.changing),
+ (e.playing = !!this.game.state && !this.player.deathCause),
+ (e.jetpack = this.jetpack.isOn()),
+ (e.pogo = this.pogo.isOn()),
+ (e.special = e.jetpack || e.pogo),
+ (e["catch"] = !!this.player.catchMode),
+ (e.grinding = this.hoverboard.grinding);
+ }),
+ (n.revive = function () {
+ this.reviveSmoke ||
+ this.add(
+ We,
+ {
+ EntityClass: mi,
+ container: this.game,
+ rate: 1,
+ life: 90,
+ xMod: [-10, 10],
+ yMod: [-2, 20],
+ velocityXMod: [-1, 1],
+ velocityYMod: [1, 3],
+ velocityZMod: [-1, -0.5],
+ scaleXMod: [0.8, 1.3],
+ scaleYMod: [0.8, 1.3],
+ scaleZMod: [0.8, 1.3],
+ growXMod: [0.01, 0.03],
+ growYMod: [0.01, 0.03],
+ growZMod: [0.01, 0.03],
+ },
+ "reviveSmoke"
+ ),
+ this.reviveHalo || this.add(fi),
+ this.reviveHalo.play(),
+ (this.reviveSmoke.data.x = this.x),
+ (this.reviveSmoke.data.y = 0),
+ (this.reviveSmoke.data.z = this.z),
+ this.reviveSmoke.spawn(20),
+ this.game.sfx.play("hero_revive");
+ }),
+ Character
+ );
+ })(v.a);
+ var ki = (function () {
+ function StateIdle() {
+ (this.playing = !1), (this.dead = !1);
+ }
+ return (
+ (StateIdle.prototype.begin = function () {
+ this.entity.anim.play("idle", {
+ loop: !0,
+ });
+ }),
+ StateIdle
+ );
+ })(),
+ xi = (function () {
+ function StateRunning() {
+ (this.playing = !0),
+ (this.landed = !0),
+ (this.rolling = !1),
+ (this.dodging = !1),
+ (this.grinding = !1),
+ (this.anim = {
+ normal: "run3",
+ hoverboard: "h_run",
+ sneakers: "superRun",
+ }),
+ (this.count = 0),
+ (this.alt = !1),
+ (this.soundSteps = !1);
+ }
+ var t = StateRunning.prototype;
+ return (
+ (t.begin = function () {
+ this.count = 0;
+ var t = this.entity.player.getMode(),
+ e = this.anim[t];
+ (this.soundSteps = "sneakers" === t),
+ "hoverboard" === t &&
+ this.entity.anim.play("h_landing", {
+ loop: !1,
+ enforce: 0.3,
+ }),
+ this.entity.anim.play(e, {
+ loop: !0,
+ });
+ }),
+ (t.update = function (t) {
+ if (this.soundSteps && ((this.count -= t), this.count <= 0)) {
+ (this.count = 25), (this.alt = !this.alt);
+ var e = this.alt ? "hero_sneakers_foot_l" : "hero_sneakers_foot_r";
+ this.entity.game.sfx.play(e);
+ }
+ }),
+ StateRunning
+ );
+ })(),
+ Ci = (function () {
+ function StateGrinding() {
+ (this.playing = !0), (this.landed = !0), (this.rolling = !1), (this.dodging = !1), (this.grinding = !0), (this.ascending = !1), (this.descending = !1);
+ }
+ var t = StateGrinding.prototype;
+ return (
+ (t.begin = function () {
+ var t = L.pick("1", "2", "3");
+ (this.animName = "h_Grind" + t),
+ this.entity.anim.play(this.animName + "_land", {
+ loop: !0,
+ enforce: 0.2,
+ }),
+ this.entity.anim.play(this.animName, {
+ loop: !0,
+ });
+ }),
+ (t.update = function (t) {
+ this.entity.anim.currentName === this.animName && this.entity.hoverboard.updateGrinding();
+ }),
+ StateGrinding
+ );
+ })(),
+ Si = (function () {
+ function StateDodging() {
+ (this.playing = !0),
+ (this.landed = !0),
+ (this.rolling = !1),
+ (this.dodging = !0),
+ (this.anim = {
+ normal: {
+ "-1": "dodgeLeft",
+ 1: "dodgeRight",
+ },
+ hoverboard: {
+ "-1": "h_left",
+ 1: "h_right",
+ },
+ sneakers: {
+ "-1": "dodgeLeft",
+ 1: "dodgeRight",
+ },
+ });
+ }
+ return (
+ (StateDodging.prototype.begin = function () {
+ var t = this.entity.player.getMode(),
+ e = this.anim[t][this.entity.lane.absStep];
+ this.entity.anim.play(e);
+ }),
+ StateDodging
+ );
+ })(),
+ zi = (function () {
+ function StateAscending() {
+ (this.playing = !0),
+ (this.landed = !1),
+ (this.special = !1),
+ (this.rolling = !1),
+ (this.ascending = !0),
+ (this.descending = !1),
+ (this.anim = {
+ normal: ["jump", "jump2", "jump3", "jump_salto"],
+ sneakers: ["jump", "jump2", "jump3", "jump_salto"],
+ hoverboard: [
+ "h_jump2_kickflip_flip",
+ "h_jump3_bs360grab",
+ "h_jump4_360_flip",
+ "h_jump5_Impossible_flip",
+ "h_jump6_nollie",
+ "h_jump7_heelflip_flip",
+ "h_jump8_pop_shuvit_flip",
+ "h_jump9_fs360grab",
+ "h_jump10_heel360_flip",
+ "h_jump11_fs_salto",
+ ],
+ });
+ }
+ return (
+ (StateAscending.prototype.begin = function () {
+ var t = this.entity.player.getMode(),
+ e = this.anim[t];
+ e && this.entity.anim.play(e);
+ }),
+ StateAscending
+ );
+ })(),
+ Ti = (function () {
+ function StateHangtime() {
+ (this.playing = !0),
+ (this.landed = !1),
+ (this.special = !1),
+ (this.rolling = !1),
+ (this.ascending = !1),
+ (this.descending = !1),
+ (this.anim = {
+ normal: ["hangtime", "hangtime2", "hangtime3"],
+ sneakers: ["hangtime", "hangtime2", "hangtime3"],
+ });
+ }
+ return (
+ (StateHangtime.prototype.begin = function () {
+ var t = this.entity.player.getMode(),
+ e = this.anim[t];
+ e &&
+ this.entity.anim.play(e, {
+ loop: !0,
+ });
+ }),
+ StateHangtime
+ );
+ })(),
+ Pi = (function () {
+ function StateDescending() {
+ (this.playing = !0),
+ (this.landed = !1),
+ (this.special = !1),
+ (this.rolling = !1),
+ (this.ascending = !1),
+ (this.descending = !0),
+ (this.anim = {
+ normal: ["hangtime", "hangtime2", "hangtime3"],
+ sneakers: ["hangtime", "hangtime2", "hangtime3"],
+ });
+ }
+ return (
+ (StateDescending.prototype.begin = function () {
+ var t = this.entity.player.getMode(),
+ e = this.anim[t];
+ e &&
+ this.entity.anim.play(e, {
+ loop: !0,
+ });
+ }),
+ StateDescending
+ );
+ })(),
+ Mi = (function () {
+ function StateRolling() {
+ (this.playing = !0),
+ (this.rolling = !0),
+ (this.anim = {
+ normal: "roll",
+ hoverboard: "h_roll",
+ sneakers: "roll",
+ });
+ }
+ return (
+ (StateRolling.prototype.begin = function () {
+ var t = this.entity.player.getMode(),
+ e = this.anim[t];
+ "hoverboard" === t &&
+ this.entity.anim.play("h_jump2_kickflip_flip", {
+ sudden: !0,
+ }),
+ this.entity.anim.play(e, {
+ loop: !0,
+ });
+ }),
+ StateRolling
+ );
+ })(),
+ Ei = (function () {
+ function StateJetpack() {
+ (this.jetpack = !0), (this.dodging = !1);
+ }
+ return (
+ (StateJetpack.prototype.begin = function () {
+ this.entity.anim.play("Jetpack_forward", {
+ loop: !0,
+ });
+ }),
+ StateJetpack
+ );
+ })(),
+ Oi = (function () {
+ function StateJetpackDodging() {
+ (this.jetpack = !0),
+ (this.dodging = !0),
+ (this.anim = {
+ "-1": "Jetpack_changeLane_left",
+ 1: "Jetpack_changeLane_right",
+ });
+ }
+ return (
+ (StateJetpackDodging.prototype.begin = function () {
+ var t = this.anim[this.entity.lane.absStep];
+ this.entity.anim.play(t);
+ }),
+ StateJetpackDodging
+ );
+ })(),
+ Ri = (function () {
+ function StatePogo() {
+ (this.pogo = !0), (this.anim = ["pogostick_Hangtime_flying"]);
+ }
+ return (StatePogo.prototype.begin = function () {}), StatePogo;
+ })(),
+ Ii = (function () {
+ function StateDead() {
+ (this.dead = !0),
+ (this["catch"] = !1),
+ (this.anim = {
+ upper: "death_upper",
+ lower: "death_lower",
+ train: "death_movingTrain",
+ bounce: "death_bounce",
+ out: "death_bounce",
+ });
+ }
+ return (
+ (StateDead.prototype.begin = function () {
+ var t = this.entity.player.deathCause,
+ e = this.anim[t] || "death_bounce";
+ this.entity.anim.play(e, {
+ sudden: !0,
+ });
+ }),
+ StateDead
+ );
+ })(),
+ Li = (function () {
+ function StateCatch() {
+ (this.dead = !0), (this["catch"] = !0);
+ }
+ return (
+ (StateCatch.prototype.begin = function () {
+ "train" !== this.entity.player.deathCause &&
+ this.entity.anim.play("Avatar_Catch_Shoulder", {
+ sudden: !0,
+ });
+ }),
+ StateCatch
+ );
+ })();
+
+ function Follower_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var ji = (function (n) {
+ var t, e;
+
+ function Follower(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).offsetX = e.offsetX || 0), i.reset(), i;
+ }
+ (e = n), ((t = Follower).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ o,
+ s,
+ a = Follower.prototype;
+ return (
+ (a.reset = function () {
+ this.entity.body &&
+ ((this.entity.body.lane = 0),
+ (this.entity.body.x = 0),
+ (this.entity.body.z = 999),
+ (this.entity.body.bottom = 0),
+ (this.mode = Follower.DISABLED),
+ (this.entity.active = !1),
+ (this.near = !1),
+ (this.enabled = !1),
+ (this.lastGround = 0),
+ (this.lastPos = 0));
+ }),
+ (a.update = function (t) {
+ if (this.enabled) {
+ t || (t = this.entity.game.delta);
+ var e = this.entity.game.hero;
+ e.player.running &&
+ (this.mode === Follower.INTRO
+ ? this.changeMode(Follower.NEAR)
+ : this.entity.game.level.isTutorial()
+ ? this.changeMode(Follower.FAR)
+ : e.pogo.isOn() || e.jetpack.isOn()
+ ? this.changeMode(Follower.GO_AWAY)
+ : e.player.dead
+ ? "train" === e.player.deathCause
+ ? this.changeMode(Follower.GO_AWAY)
+ : this.changeMode(Follower.CATCH)
+ : e.player.dizzy
+ ? this.changeMode(Follower.NEAR)
+ : this.changeMode(Follower.FAR)),
+ this.time <= this.duration && ((this.time += this.entity.game.deltaSecs), this.time > this.duration && (this.time = this.duration));
+ var i = e.body.x + this.offsetX;
+ (this.entity.body.x = V.lerp(this.entity.body.x, i, 0.5 * t)), e.body.landed && (this.lastGround = e.body.ground);
+ var n = this.lastGround + 0.5 * (e.body.bottom - this.lastGround);
+ (this.entity.body.bottom = V.lerp(this.entity.body.bottom, n, 0.5 * t)), this.entity.body.bottom > e.body.bottom && (this.entity.body.bottom = e.body.bottom);
+ var o = this.curve ? this.curve(this.time / this.duration) : this.time / this.duration,
+ s = V.lerp(this.distanceStart, this.distanceEnd, o);
+ (this.distance = s), this.sound && this.sound.volume(1 - V.clamp(this.distance / 70, 0, 1));
+ }
+ }),
+ (a.changeMode = function (t) {
+ this.mode !== t &&
+ (this.mode === Follower.FAR && t === Follower.NEAR ? this.entity.game.sfx.play("guard_proximity") : t === Follower.CATCH && this.entity.game.sfx.play("guard_catch"),
+ (this.mode = t),
+ (this.distanceStart = this.distance),
+ (this.distanceEnd = this.mode.distance),
+ (this.duration = this.mode.duration),
+ (this.curve = this.mode.curve),
+ (this.time = 0));
+ }),
+ (a.enable = function () {
+ (this.enabled = !0), this.changeMode(Follower.NEAR);
+ }),
+ (a.disable = function () {
+ (this.entity.active = !0), (this.entity.body.z = 9999), (this.enabled = !1);
+ }),
+ (a.playIntro = function () {
+ (this.distance = 50), (this.time = this.duration = 0.01), this.enable(), this.changeMode(Follower.INTRO);
+ }),
+ (a.dismiss = function () {
+ this.changeMode(Follower.DISABLED);
+ }),
+ (i = Follower),
+ (o = [
+ {
+ key: "distance",
+ set: function (t) {
+ var e = this.entity.game.stats.z + t;
+ this.entity.body.z = e;
+ },
+ get: function () {
+ return this.entity.z - this.entity.game.stats.z;
+ },
+ },
+ ]) && Follower_defineProperties(i.prototype, o),
+ s && Follower_defineProperties(i, s),
+ Follower
+ );
+ })(J.a);
+ (ji.DISABLED = {
+ distance: 9999,
+ duration: 0.1,
+ curve: null,
+ }),
+ (ji.FAR = {
+ distance: 70,
+ duration: 3,
+ curve: St.sineIn,
+ }),
+ (ji.GO_AWAY = {
+ distance: 100,
+ duration: 1,
+ curve: St.sineIn,
+ }),
+ (ji.NEAR = {
+ distance: 10,
+ duration: 0.6,
+ curve: St.sineOut,
+ }),
+ (ji.CATCH = {
+ distance: 0,
+ duration: 0.3,
+ curve: St.sineOut,
+ }),
+ (ji.INTRO = {
+ distance: 10,
+ duration: 1e-10,
+ curve: St.expoOut,
+ });
+ var Fi = (function (e) {
+ var t, i;
+
+ function Cop() {
+ var t;
+ return (
+ (t = e.call(this) || this).add(it, {
+ deco: !0,
+ ghost: !0,
+ }),
+ t.add(ji),
+ t.add(ci),
+ t.add(di),
+ (t.body.height = 14),
+ (t.body.width = 6),
+ (t.body.depth = 6),
+ (t.model = new v.a()),
+ (t.model.y = 0.4 * -t.body.height),
+ (t.model.ry = Math.PI),
+ t.addChild(t.model),
+ (t["catch"] = null),
+ (t.catchCount = 0),
+ t.scale.set(0.01),
+ t
+ );
+ }
+ (i = e), ((t = Cop).prototype = Object.create(i.prototype)), ((t.prototype.constructor = t).__proto__ = i);
+ var n = Cop.prototype;
+ return (
+ (n.init = function () {
+ this._initialized || ((this._initialized = !0), this.anim.addAnim("movement", hi.guard_movement), this.anim.addAnim("catch", hi.guard_catch));
+ }),
+ (n.playIntro = function () {
+ var t = this;
+ this.init(),
+ this.scale.set(0.01),
+ (this.active = !0),
+ (this.z = 999),
+ (this.body.z = this.z),
+ this.game.sfx.play("guard_start"),
+ this.anim.play("Guard_run", {
+ sudden: !0,
+ loop: !1,
+ }),
+ this.anim.play("Guard_playIntro", {
+ sudden: !0,
+ crossfade: 0,
+ }),
+ this.follower.playIntro(),
+ setTimeout(function () {
+ t.scale.set(1);
+ }, 100);
+ }),
+ (n.run = function () {
+ this.init(),
+ (this.active = !0),
+ this.anim.play("Guard_run", {
+ loop: !0,
+ }),
+ this.follower.enable();
+ }),
+ (n.reset = function () {
+ this._initialized && (this.follower.reset(), (this.z = 999), (this.body.z = this.z), (this.catchCount = 0), (this["catch"] = null), (this.active = !1));
+ }),
+ (n.onStateUpdate = function () {
+ var t;
+ this.statesReady ||
+ (((t = this).state.params = {
+ playing: !1,
+ landed: !1,
+ dodging: !1,
+ rolling: !1,
+ catch: !1,
+ hasDeathCause: !1,
+ }),
+ t.state.add("idle", new Ai()),
+ t.state.add("running", new Di()),
+ t.state.add("dodging", new Gi()),
+ t.state.add("airborne", new Bi()),
+ t.state.add("rolling", new Ni()),
+ t.state.add("catch", new Xi()),
+ t.state.addTransition("all", "idle"),
+ t.state.addTransition("idle", "running"),
+ t.state.addTransition("running", "dodging", !0),
+ t.state.addTransition("running", "airborne", !0),
+ t.state.addTransition("running", "rolling", !0),
+ t.state.addTransition("airborne", "rolling", !0),
+ t.state.addTransition("airborne", "dodging", !0),
+ t.state.addTransition("all", "catch"),
+ t.state.addTransition("catch", "idle"),
+ t.state.addTransition("catch", "running")),
+ (this.statesReady = !0),
+ this.catchCount && ((this.catchCount -= 1), 0 === this.catchCount && (this["catch"] = !0));
+ var e = this.state.params;
+ (e.landed = this.game.hero.body.landed),
+ (e.rolling = !!this.game.hero.player.rolling),
+ (e.dodging = !!this.game.hero.body.dodging),
+ (e.playing = !!this.game.state && !this.game.hero.player.deathCause),
+ (e["catch"] = !!this["catch"]),
+ (e.hasDeathCause = !!this.game.hero.player.deathCause);
+ }),
+ (n.catchHero = function () {
+ this.catchCount = 10;
+ }),
+ Cop
+ );
+ })(v.a);
+ var Ai = (function () {
+ function StateIdle() {
+ (this.playing = !1), (this["catch"] = !1);
+ }
+ var t = StateIdle.prototype;
+ return (t.begin = function () {}), (t.end = function () {}), StateIdle;
+ })(),
+ Di = (function () {
+ function StateRunning() {
+ (this.playing = !0), (this.landed = !0), (this.rolling = !1), (this.dodging = !1);
+ }
+ var t = StateRunning.prototype;
+ return (
+ (t.begin = function () {
+ this.entity.anim.play("Guard_run", {
+ loop: !0,
+ });
+ }),
+ (t.update = function () {
+ !this._catchScene && this.entity.anim.scenes[1] && (this._catchScene = this.entity.anim.scenes[1].pixiTree), this._catchScene && (this._catchScene.active = !1);
+ }),
+ StateRunning
+ );
+ })(),
+ Gi = (function () {
+ function StateDodging() {
+ (this.playing = !0),
+ (this.landed = !0),
+ (this.rolling = !1),
+ (this.dodging = !0),
+ (this.anim = {
+ 1: "Guard_dodgeLeft",
+ "-1": "Guard_dodgeRight",
+ });
+ }
+ return (
+ (StateDodging.prototype.begin = function () {
+ var t = this.anim[this.entity.game.hero.body.dodging];
+ this.entity.anim.play(t, {
+ sudden: !1,
+ });
+ }),
+ StateDodging
+ );
+ })(),
+ Bi = (function () {
+ function StateAirborne() {
+ (this.playing = !0), (this.landed = !1), (this.rolling = !1);
+ }
+ return (
+ (StateAirborne.prototype.begin = function () {
+ this.entity.anim.play("Guard_jump", {
+ sudden: !0,
+ });
+ }),
+ StateAirborne
+ );
+ })(),
+ Ni = (function () {
+ function StateRolling() {
+ (this.playing = !0), (this.rolling = !0);
+ }
+ return (
+ (StateRolling.prototype.begin = function () {
+ this.entity.anim.play("Guard_roll", {
+ loop: !0,
+ sudden: !0,
+ });
+ }),
+ StateRolling
+ );
+ })(),
+ Xi = (function () {
+ function StateCatch() {
+ (this["catch"] = !0), (this.anims = ["Catch_Shoulder", "Catch_Left_Pickup", "Catch_Right_Pickup"]);
+ }
+ return (
+ (StateCatch.prototype.begin = function () {
+ if (!this.playing)
+ if ("train" === this.entity.game.hero.player.deathCause) this.entity.follower.dismiss();
+ else {
+ var t = this.entity.game.hero,
+ e = t.body.x,
+ i = t.body.lane * B.laneWidth,
+ n = L.item(this.anims);
+ (n = i - 4 < e && e < i + 4 ? "Catch_Shoulder" : -1 === t.player.bumpSide ? "Catch_Right_Pickup" : 1 === t.player.bumpSide ? "Catch_Left_Pickup" : "Catch_Shoulder"),
+ this.entity.anim.play("Guard_" + n, {
+ sudden: !0,
+ }),
+ this.entity.game.hero.anim.play("Avatar_" + n, {
+ sudden: !0,
+ });
+ }
+ }),
+ StateCatch
+ );
+ })();
+ var Yi = (function (d) {
+ var t, e;
+
+ function Skyline() {
+ var t;
+ (t = d.call(this) || this).rotation.y = Math.PI;
+ var e = H.whichScene("sl_monument_4", "sl_monument_04"),
+ i = H.getEntityCloneColor(e, 9490943, !1);
+ t.addChild(i), (i.x = 100), (i.y = -50), (i.z = 0);
+ var n = H.whichScene("sl_monument_2", "sl_monument_02"),
+ o = H.getEntityCloneColor(n, 6533631, !1);
+ t.addChild(o), (o.x = 0), (o.z = -30);
+ var s = H.whichScene("sl_monument_3", "sl_monument_03"),
+ a = H.getEntityCloneColor(s, 9490943, !1);
+ t.addChild(a), (o.x = 0), (o.y = -200), (a.z = -60);
+ var r = H.whichScene("sl_monument_1", "sl_monument_01"),
+ h = H.getEntityCloneColor(r, 6533631, !1);
+ return t.addChild(h), (o.x = 100), (h.z = -90), t;
+ }
+ return (e = d), ((t = Skyline).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e), Skyline;
+ })(v.a),
+ Hi = {};
+ (Hi["new"] = function () {
+ return H.getEntityClone("tube");
+ }),
+ (Hi.new001 = function () {
+ return H.getEntityClone("tube001");
+ }),
+ (Hi.new002 = function () {
+ return H.getEntityClone("tube002");
+ }),
+ (Hi.spawn = function (t, e) {
+ void 0 === e && (e = {}), e.z || (e.z = t.z);
+ var i = t.game.pool.get(Hi["new"]);
+ if (((i.x = 0), (i.y = 0), (i.z = e.z), (i.ry = Math.PI), t.game.addChild(i), "1103_seoul" === B.env)) {
+ var n = t.game.pool.get(Hi.new001);
+ (n.x = 0), (n.y = 0), (n.z = e.z), (n.ry = Math.PI), (n.view3d.state.blend = !0), (n.view3d.material.opacity = 0.5), t.game.addChild(n);
+ var o = t.game.pool.get(Hi.new002);
+ (o.x = 0), (o.y = 0), (o.z = e.z), (o.ry = Math.PI), t.game.addChild(o);
+ }
+ }),
+ (Hi.mount = function (t) {
+ for (var e = t.blocks / 2, i = 0; i < e; i++) {
+ var n = t.z - i * B.blockSize * 2;
+ Hi.spawn(t, {
+ z: n,
+ });
+ }
+ });
+ var Ui = i(190),
+ Vi = i.n(Ui),
+ qi = i(191),
+ Wi = i.n(qi);
+ var Zi = (function (n) {
+ var t, e;
+
+ function SeaMaterial(t, e) {
+ void 0 === t && (t = {}), void 0 === e && (e = {});
+ var i = [e.fog ? "#define FOG" : "", e.rails ? "#define RAILS" : ""];
+ return (t.uniforms = O.unformGroup()), n.call(this, t, Vi.a, Wi.a, i, "sea") || this;
+ }
+ return (e = n), ((t = SeaMaterial).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e), SeaMaterial;
+ })(z.a),
+ Ki = {},
+ Ji = Ki;
+ (Ki.newStart = function () {
+ return H.getEntityClone("epic_start");
+ }),
+ (Ki.newStart001 = function () {
+ return H.getEntityClone("epic_start001", "ocean", !1, Zi);
+ }),
+ (Ki.newStart002 = function () {
+ return H.getEntityClone("epic_start002", "", !1, R);
+ }),
+ (Ki.newStart003 = function () {
+ return H.getEntityClone("epic_start003", "", !1, R);
+ }),
+ (Ki.newMid = function () {
+ return H.getEntityClone("epic_mid");
+ }),
+ (Ki.newMid001 = function () {
+ return H.getEntityClone("epic_mid001", "", !1, R);
+ }),
+ (Ki.newMid002 = function () {
+ return H.getEntityClone("epic_mid002", "ocean", !1, Zi);
+ }),
+ (Ki.newMid003 = function () {
+ return H.getEntityClone("epic_mid003", "", !1, R);
+ }),
+ (Ki.newEnd = function () {
+ return H.getEntityClone("epic_end");
+ }),
+ (Ki.newEnd001 = function () {
+ return H.getEntityClone("epic_end001", "", !1, R);
+ }),
+ (Ki.newEnd002 = function () {
+ return H.getEntityClone("epic_end002", "ocean", !1, Zi);
+ }),
+ (Ki.newEnd003 = function () {
+ return H.getEntityClone("epic_end003", "", !1, R);
+ }),
+ (Ki.newStartAlt = function () {
+ return H.getEntityClone("epic_1_start");
+ }),
+ (Ki.newStart001Alt = function () {
+ return H.getEntityClone("epic_1_start001", "ocean", !1, Zi);
+ }),
+ (Ki.newStart002Alt = function () {
+ return H.getEntityClone("epic_1_start002", "", !1, R);
+ }),
+ (Ki.newStart003Alt = function () {
+ return H.getEntityClone("epic_1_start003", "", !1, R);
+ }),
+ (Ki.newMidAlt = function () {
+ return H.getEntityClone("epic_1_mid");
+ }),
+ (Ki.newMid001Alt = function () {
+ return H.getEntityClone("epic_1_mid001", "", !1, R);
+ }),
+ (Ki.newMid002Alt = function () {
+ return H.getEntityClone("epic_1_mid002", "ocean", !1, Zi);
+ }),
+ (Ki.newMid003Alt = function () {
+ return H.getEntityClone("epic_1_mid003", "", !1, R);
+ }),
+ (Ki.newEndAlt = function () {
+ return H.getEntityClone("epic_1_end");
+ }),
+ (Ki.newEnd001Alt = function () {
+ return H.getEntityClone("epic_1_end001", "", !1, R);
+ }),
+ (Ki.newEnd002Alt = function () {
+ return H.getEntityClone("epic_1_end002", "ocean", !1, Zi);
+ }),
+ (Ki.newEnd003Alt = function () {
+ return H.getEntityClone("epic_1_end003", "", !1, R);
+ }),
+ (Ki.spawn = function (t, e) {
+ void 0 === e && (e = {}), e.z || (e.z = t.z), e.alt || (e.alt = !1), e.part || (e.part = "Start"), "1103_seoul" === B.env && (e.alt = !1);
+ var i = "new" + e.part + (e.alt ? "Alt" : ""),
+ n = "new" + e.part + "001" + (e.alt ? "Alt" : ""),
+ o = "new" + e.part + "002" + (e.alt ? "Alt" : ""),
+ s = "new" + e.part + "003" + (e.alt ? "Alt" : ""),
+ a = t.game.pool.get(Ki[i]);
+ if (((a.x = 0), (a.y = 0), (a.z = e.z), (a.ry = Math.PI), t.game.addChild(a), "1103_seoul" === B.env)) {
+ var r = t.game.pool.get(Ki[n]);
+ (r.x = 0), (r.y = 0), (r.z = e.z), (r.ry = Math.PI), t.game.addChild(r);
+ var h = t.game.pool.get(Ki[o]);
+ (h.x = 0), (h.y = 0), (h.z = e.z), (h.ry = Math.PI), t.game.addChild(h);
+ var d = t.game.pool.get(Ki[s]);
+ (d.x = 0), (d.y = 0), (d.z = e.z), (d.ry = Math.PI), t.game.addChild(d);
+ }
+ }),
+ (Ki.mount = function (t) {
+ for (var e = t.blocks, i = 12 < t.blocks, n = 0.25 * e, o = 0, s = 0; s < n; s++)
+ 0 === s
+ ? Ki.spawn(t, {
+ z: t.z - o,
+ part: "Start",
+ alt: i,
+ })
+ : s < n - 1
+ ? Ki.spawn(t, {
+ z: t.z - o,
+ part: "Mid",
+ alt: i,
+ })
+ : Ki.spawn(t, {
+ z: t.z - o,
+ part: "End",
+ alt: i,
+ }),
+ (o += 4 * B.blockSize);
+ });
+ var Qi = (function (n) {
+ var t, e;
+
+ function EnvironmentSystem(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).models = []),
+ (i.game = t.game),
+ i.game.onRun.add(
+ (function (t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ })(i)
+ ),
+ i
+ );
+ }
+ (e = n), ((t = EnvironmentSystem).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = EnvironmentSystem.prototype;
+ return (
+ (i.run = function () {
+ this.skyline || ((this.skyline = new Yi()), this.game.addChild(this.skyline));
+ }),
+ (i.update = function () {
+ this.skyline && (this.skyline.z = this.game.stats.z - 0.95 * B.visibleMaxDistance);
+ }),
+ (i.setup = function (t) {
+ var e = ue.environment(t.node),
+ i = e ? ue.environmentType(e) : null;
+ if (!i)
+ if (t.node.name.match(/tunnel/)) i = ["Gates", "All"];
+ else if (t.node.name.match(/epic/)) i = ["Epic", "All"];
+ else if (t.node.components.RouteChunk) {
+ var n = t.node.components.RouteChunk._limitedAllowedEnvironmentKinds;
+ i = (n.length ? L.item(n)._type.split(",") : ["Fillers", "All"]) || [];
+ } else i = [];
+ (t.envTube = !1),
+ (t.envStation = !1),
+ (t.envEpic = !1),
+ (t.envGates = !1),
+ (t.envEmpty = !1),
+ (t.envPillars = !1),
+ B.forceTube || 0 <= i.indexOf("Tube")
+ ? (t.envTube = this.game.route.canSpawn("tube", t.z))
+ : 0 <= i.indexOf("Station")
+ ? (t.envStation = !0)
+ : 0 <= i.indexOf("Epic")
+ ? (t.envEpic = this.game.route.canSpawn("epic", t.z))
+ : 0 <= i.indexOf("Gates")
+ ? (t.envGates = !0)
+ : 0 <= i.indexOf("Pillars")
+ ? (t.envPillars = !0)
+ : 0 <= i.indexOf("Empty") && (t.envEmpty = !0);
+ }),
+ (i.mount = function (t) {
+ t.envTube ? this.spawnTube(t) : t.envStation ? this.spawnStation(t) : t.envEpic ? this.spawnEpic(t) : t.envEmpty ? this.spawnRegular(t) : t.envGates ? this.spawnGates(t) : this.spawnRegular(t);
+ }),
+ (i.spawnEpic = function (t) {
+ Ji.mount(t), this.game.route.setSpawn("epic", t.z - t.length - 1800);
+ }),
+ (i.spawnTube = function (t) {
+ var e = t.node,
+ i = t.game.pool.get(he);
+ t.game.addChild(i), i.init(t, e), this.game.route.setSpawn("tube", t.z - t.length - 360);
+ }),
+ (i.spawnStation = function (t) {
+ var e = ue.environment(t.node),
+ i = (e.components.Transform.position.z, t.game.pool.get(Kt));
+ i.init(t, e), t.game.addChild(i), Nt.mount(t), Yt.mount(t);
+ }),
+ (i.spawnGates = function (t) {}),
+ (i.spawnRegular = function (t) {
+ Yt.mount(t), Nt.mount(t);
+ }),
+ EnvironmentSystem
+ );
+ })(f.a),
+ $i = i(127);
+
+ function RouteSystem_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var tn = (function (n) {
+ var t, e;
+
+ function RouteSystem(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).game = t.game),
+ i.game.onReset.add(
+ (function (t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ })(i)
+ ),
+ (i._spawns = {}),
+ (i.builder = new en(i.game)),
+ (i.firstPassed = !1),
+ i
+ );
+ }
+ (e = n), ((t = RouteSystem).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ o,
+ s,
+ a = RouteSystem.prototype;
+ return (
+ (a.reset = function () {
+ this.builder.reset(),
+ (this.firstPassed = !1),
+ (this.game.stats.route = ""),
+ (this._spawns = {
+ pickup: -900,
+ tube: -90,
+ });
+ }),
+ (a.getSequence = function () {
+ var t = Math.clamp(this.game.stats.level, 0, 3),
+ e = [],
+ i = [],
+ n = [];
+ if (B.routeSection) n.push(we.section("default_fallback")), n.push(we.section(B.routeSection));
+ else {
+ if (!this.firstPassed) {
+ var o = we.section(this.game.tutorial.enabled ? "tutorial" : "default_start");
+ n.push(o), (this.firstPassed = !0);
+ }
+ n.push(this.builder.getSectionByLevel(t));
+ }
+ for (var s = 0; s < n.length; s++) {
+ var a = n[s];
+ if (!(0 <= i.indexOf(a.name))) {
+ if ((i.push(a.name), a.start)) for (var r in a.start) e.push(a.start[r]);
+ if ((a.mid && e.push(L.item(a.mid)), a.end)) for (var h in a.end) e.push(a.end[h]);
+ }
+ }
+ return e;
+ }),
+ (a.canSpawn = function (t, e) {
+ return void 0 === this._spawns[t] || e <= this._spawns[t];
+ }),
+ (a.setSpawn = function (t, e) {
+ this._spawns[t] = e;
+ }),
+ (a.resetSpawns = function () {
+ (this.builder.picked = {}),
+ (this._spawns = {
+ pickup: -900,
+ tube: -90,
+ });
+ }),
+ (i = RouteSystem),
+ (o = [
+ {
+ key: "profile",
+ get: function () {
+ return this._profile || (this._profile = {}), this._profile;
+ },
+ },
+ ]) && RouteSystem_defineProperties(i.prototype, o),
+ s && RouteSystem_defineProperties(i, s),
+ RouteSystem
+ );
+ })(f.a),
+ en = (function () {
+ function RouteBuilder(t) {
+ (this.game = t),
+ (this.minDistanceBetweenRepeats = 2700),
+ (this.sectionsStart = {
+ default_start: 10,
+ }),
+ (this.sectionsMid = {
+ "default_b-s-b": 10,
+ default_choice: 10,
+ "default_s-b-s-b": 10,
+ "default_s-s": 10,
+ "default_s-s-s-s": 10,
+ default_train_tops_1: 10,
+ default_train_tops_2: 10,
+ default_tunnel_notrain: 10,
+ default_ramp_1: 10,
+ default_epic: 20,
+ default_1_track: 30,
+ default_2_tracks: 10,
+ default_train_tops_moving: 10,
+ default_train_tops_moving_combined: 10,
+ default_train_tops_moving_multiple: 10,
+ default_tunnel: 30,
+ default_epic_various: 20,
+ "default_4_units_3_tracks_b-s-b": 10,
+ default_4_units_3_tracks_choice: 10,
+ "default_4_units_3_tracks_s-b-s-b": 10,
+ "default_4_units_3_tracks_s-s": 10,
+ "default_4_units_3_tracks_s-s-s-s": 10,
+ default_short_1_track: 10,
+ default_ramp_2: 10,
+ default_short_2_tracks: 10,
+ default_short_train_tops_moving_combined: 10,
+ default_short_train_tops_moving_multiple: 10,
+ default_short_train_tops_moving: 10,
+ default_pogostick_start: 5,
+ default_bonus_short: 10,
+ default_bonus_long: 10,
+ }),
+ (this.levels = ["easy", "normal", "hard", "expert"]),
+ this.reset();
+ }
+ var t = RouteBuilder.prototype;
+ return (
+ (t.reset = function () {
+ (this.picked = {
+ default_tunnel: 1,
+ default_tunnel_notrain: 1,
+ }),
+ (this.level = 0),
+ (this.availableSections = {}),
+ this.addAvailableSections("easy");
+ }),
+ (t.getSectionByLevel = function (t) {
+ if (t > this.level) {
+ this.level = t;
+ var e = this.levels[this.level];
+ this.addAvailableSections(e), 2 == t && (this.addAvailableSection("default_bonus_short"), this.addAvailableSection("default_bonus_long"), this.addAvailableSection("default_pogostick_start"));
+ }
+ for (var i in this.picked) this.game.stats.distance > this.picked[i] && delete this.picked[i];
+ var n = Object.assign({}, this.availableSections);
+ for (var o in this.picked) delete n[o];
+ var s = L.item(n);
+ if (!s) throw new Error("No section available");
+ return (
+ s.__shortname.match("default_tunnel")
+ ? ((this.picked.default_tunnel = this.game.stats.distance + 0.75 * this.minDistanceBetweenRepeats), (this.picked.default_tunnel_notrain = this.game.stats.distance + 0.75 * this.minDistanceBetweenRepeats))
+ : (this.picked[s.__shortname] = this.game.stats.distance + this.minDistanceBetweenRepeats),
+ s
+ );
+ }),
+ (t.addAvailableSections = function (t) {
+ var e = $i["default"][t]["default"];
+ for (var i in e) this.addAvailableSection(e[i]);
+ }),
+ (t.addAvailableSection = function (t) {
+ "string" == typeof t && (t = we.section(t));
+ var e = t.name.replace("routeSection_", "").replace("route_section_", "");
+ this.sectionsMid[e] && ((this.availableSections[e] = t).__shortname = e);
+ }),
+ RouteBuilder
+ );
+ })(),
+ nn = i(7);
+
+ function Label_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var on = {
+ basic: {
+ align: "center",
+ fill: 16777215,
+ fontSize: 50,
+ fontFamily: "Titan One",
+ lineJoin: "round",
+ dropShadow: !1,
+ dropShadowDistance: 3,
+ anchor: 0.5,
+ maxWidth: 0,
+ },
+ title: {
+ align: "center",
+ fill: 211825,
+ fontSize: 70,
+ fontFamily: "Titan One",
+ dropShadow: !1,
+ dropShadowDistance: 2,
+ anchor: 0.5,
+ },
+ subtitle: {
+ align: "center",
+ fill: 211825,
+ fontSize: 60,
+ fontFamily: "Titan One",
+ dropShadow: !1,
+ dropShadowDistance: 2,
+ anchor: 0.5,
+ },
+ small: {
+ align: "center",
+ fill: 211825,
+ fontSize: 50,
+ fontFamily: "Titan One",
+ },
+ },
+ sn = (function (s) {
+ var t, e;
+
+ function Label(t, e, i) {
+ var n;
+ void 0 === e && (e = "basic"), void 0 === i && (i = {}), (n = s.call(this) || this);
+ var o = "string" == typeof e ? on[e] : e;
+ return (
+ (e = Object.assign({}, on.basic, o, i)),
+ (n._text = new c.Text(t, e)),
+ n._text.anchor.set(e.anchor),
+ n.addChild(n._text),
+ void 0 !== e.anchorX && (n._text.anchor.x = e.anchorX),
+ void 0 !== e.anchorY && (n._text.anchor.y = e.anchorY),
+ e.x && (n.x = e.x),
+ e.y && (n.y = e.y),
+ e.maxWidth && (n.maxWidth = e.maxWidth),
+ e.icon && ((n.icon = c.Sprite.from(e.icon)), n.icon.anchor.set(0.5), n.addChild(n.icon), (n.icon.x = 0), n.update()),
+ n
+ );
+ }
+ (e = s), ((t = Label).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ n,
+ o,
+ a = Label.prototype;
+ return (
+ (a.update = function () {
+ if ((this.maxWidth && this._text.width > this.maxWidth && ((this._text.scale.x = 1), (this._text.width = this.maxWidth), (this._text.scale.y = this._text.scale.x)), this.icon)) {
+ (this._text.x = 0), (this.icon.x = this._text.x - 0.5 * this._text.width - 0.5 * this.icon.width - 5);
+ var t = 0.5 * (this.width - this._text.width);
+ (this.icon.x += t), (this._text.x += t);
+ }
+ }),
+ (a.prompt = function () {
+ if (!this._prompting) {
+ this._prompting = !0;
+ var t = window.prompt(this.description, this.text);
+ t && (this.text = t), (this._prompting = !1), this.emit("change", this.text);
+ }
+ }),
+ (i = Label),
+ (n = [
+ {
+ key: "text",
+ get: function () {
+ return this._text.text;
+ },
+ set: function (t) {
+ this._text.text !== t && ((this._text.text = t), this.update());
+ },
+ },
+ {
+ key: "editable",
+ get: function () {
+ return !!this._editable;
+ },
+ set: function (t) {
+ (this._editable = t), (this.interactive = t), (this.buttonMode = t), void 0 === this.description && (this.description = "Set text"), this[this._editable ? "on" : "off"]("pointertap", this.prompt, this);
+ },
+ },
+ ]) && Label_defineProperties(i.prototype, n),
+ o && Label_defineProperties(i, o),
+ Label
+ );
+ })(c.Container),
+ an = i(131);
+
+ function TutorialSystem_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+
+ function TutorialSystem_assertThisInitialized(t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ }
+
+ function TutorialSystem_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ var rn = (function (n) {
+ function TutorialSystem(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = {}),
+ ((i = n.call(this, t, e) || this).view = new c.Container()),
+ (i.game = t.game),
+ i.game.onRun.add(TutorialSystem_assertThisInitialized(i)),
+ i.game.onPause.add(TutorialSystem_assertThisInitialized(i)),
+ i.game.onResume.add(TutorialSystem_assertThisInitialized(i)),
+ i
+ );
+ }
+ TutorialSystem_inheritsLoose(TutorialSystem, n);
+ var t,
+ e,
+ i,
+ o = TutorialSystem.prototype;
+ return (
+ (o.run = function () {
+ this._enabled && this.show();
+ }),
+ (o.pause = function () {
+ this._enabled && (this.view.visible = !1);
+ }),
+ (o.resume = function () {
+ this._enabled && (this.view.visible = !0);
+ }),
+ (o.build = function () {
+ this._built || ((this._built = !0), (this.arrow = new hn()), this.view.addChild(this.arrow), (this.msg = new dn(this.game.app)), this.view.addChild(this.msg), this.resize());
+ }),
+ (o.show = function () {
+ this._enabled && (this.build(), this.game.stage.addChild(this.view), this.game.hero.hoverboard.lock());
+ }),
+ (o.hide = function () {
+ this.game.stage.removeChild(this.view);
+ }),
+ (o.enterTrigger = function (t) {
+ this._enabled && (this.game.stats.distanceDelta < 0 || (this.arrow.show(t), this.msg.show(t, this.arrow.visible), "hoverboard" === t && ((this.game.stats.hoverboards = 2), this.game.hero.hoverboard.unlock())));
+ }),
+ (o.exitTrigger = function (t) {}),
+ (o.update = function (t) {
+ this._enabled && (this.arrow && this.arrow.update(t), this.msg && this.msg.update(t));
+ }),
+ (o.resize = function (t, e, i) {
+ (this.sw = t || this.sw),
+ (this.sh = e || this.sh),
+ (this.sr = i || this.sr),
+ (this.s = this.sh / (667 * this.sr)),
+ (this.w = this.sw / this.s),
+ (this.h = this.sh / this.s),
+ this.view.scale.set(this.s),
+ (this.view.x = this.sw / 2),
+ (this.view.y = this.sh / 2);
+ }),
+ (t = TutorialSystem),
+ (e = [
+ {
+ key: "enabled",
+ get: function () {
+ return this._enabled;
+ },
+ set: function (t) {
+ this._enabled = t;
+ },
+ },
+ ]) && TutorialSystem_defineProperties(t.prototype, e),
+ i && TutorialSystem_defineProperties(t, i),
+ TutorialSystem
+ );
+ })(f.a),
+ hn = (function (e) {
+ function Arrow() {
+ var t;
+ return (
+ ((t = e.call(this) || this).img = c.Sprite.from("tutorial_arrow.png")), t.img.anchor.set(0.5), t.img.scale.set(2), (t.img.alpha = 0.5), t.addChild(t.img), (t.visible = !1), (t.time = 0), (t.duration = 0), (t.animRange = 300), t
+ );
+ }
+ TutorialSystem_inheritsLoose(Arrow, e);
+ var t = Arrow.prototype;
+ return (
+ (t.show = function (t, e) {
+ void 0 === e && (e = 40);
+ var i = {
+ up: 0,
+ right: 1,
+ down: 2,
+ left: 3,
+ };
+ void 0 !== i[t] && ((this.visible = !0), (this.rotation = V.PI_HALF * i[t]), (this.time = 0), (this.duration = e), (this.img.y = this.animRange));
+ }),
+ (t.hide = function () {
+ this.visible = !1;
+ }),
+ (t.update = function (t) {
+ if (this.visible) {
+ this.time += t;
+ var e = this.time / this.duration;
+ (this.img.y = this.animRange - 2 * this.animRange * e), 1 < e && this.hide();
+ }
+ }),
+ Arrow
+ );
+ })(c.Container),
+ dn = (function (i) {
+ function Msg(t) {
+ var e;
+ return (
+ ((e =
+ i.call(this, "MSG", {
+ align: "center",
+ fill: 16777215,
+ fontSize: 50,
+ fontFamily: "Lilita One",
+ stroke: "black",
+ strokeThickness: 5,
+ anchor: 0.5,
+ }) || this).app = t),
+ (e.visible = !1),
+ (e.time = 0),
+ (e.duration = 60),
+ e
+ );
+ }
+ TutorialSystem_inheritsLoose(Msg, i);
+ var t = Msg.prototype;
+ return (
+ (t.show = function (t, e) {
+ var i = B.mobile ? "" : "_desktop",
+ n = this.app.strings.get("tutorial_" + t + i);
+ n || (n = this.app.strings.get("tutorial_" + t)),
+ n &&
+ ((this.text = n),
+ (this.visible = !0),
+ (this.time = 0),
+ (this.duration = 20 + 2 * n.length),
+ (this.scale.y = 0),
+ an.a.to(this.scale, 0.01, {
+ y: 1,
+ }),
+ (this.y = e ? 300 : 0),
+ (this.showing = !0));
+ }),
+ (t.hide = function () {
+ var t = this;
+ (this.showing = !1),
+ an.a.to(this.scale, 0.1, {
+ y: 0,
+ onComplete: function () {
+ t.visible = !1;
+ },
+ });
+ }),
+ (t.update = function (t) {
+ this.visible && this.showing && ((this.time += t), this.time > this.duration && this.hide());
+ }),
+ Msg
+ );
+ })(sn);
+
+ function IntroSystem_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+
+ function IntroSystem_createClass(t, e, i) {
+ return e && IntroSystem_defineProperties(t.prototype, e), i && IntroSystem_defineProperties(t, i), t;
+ }
+ var ln = (function (n) {
+ var t, e;
+
+ function IntroSystem(t, e) {
+ var i;
+ return void 0 === e && (e = {}), ((i = n.call(this, t, e) || this).game = t.game), (i.onIntroComplete = new et.a("onIntroComplete")), (i.time = 0), (i.duration = 60), (i.playing = !1), i;
+ }
+ (e = n), ((t = IntroSystem).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = IntroSystem.prototype;
+ return (
+ (i.update = function (t) {
+ this.playing && (this.step1 && this.step1.update(t), this.step2 && this.step2.update(t), this.step3 && this.step3.update(t));
+ }),
+ (i.preupdate = function (t) {
+ this.playing && (t || (t = this.game.delta), (this.time += t), this.time >= this.duration && (this.time = this.duration), this.time >= this.duration && this.complete());
+ }),
+ (i.play = function () {
+ (this.playing = !0),
+ this.game.camera.takeControl(),
+ this.game.camera.updateIdle(0),
+ (this.time = 0),
+ (this.step1 = new un("step1", this.game.camera.rig, 0.4 * this.duration)),
+ (this.step1.to.idleX = -16.49361),
+ (this.step1.to.idleY = -8.666094),
+ (this.step1.to.idleZ = 12.52404),
+ (this.step1.to.idleRotX = 23.52661 * V.DEG_TO_RAD),
+ (this.step1.to.idleRotY = 55.26425 * V.DEG_TO_RAD),
+ (this.step1.to.mainX = 0),
+ (this.step1.to.mainY = B.cameraPosY),
+ (this.step1.to.mainZ = B.cameraPosZ),
+ (this.step1.to.mainRotX = B.cameraRotX),
+ (this.step1.to.mainRotY = 0),
+ (this.step2 = new un("step2", this.game.camera.rig, 0.3 * this.duration)),
+ (this.step2.to.idleX = -16.49361),
+ (this.step2.to.idleY = -8.666094),
+ (this.step2.to.idleZ = 12.52404),
+ (this.step2.to.idleRotX = 23.30551 * V.DEG_TO_RAD),
+ (this.step2.to.idleRotY = 55.47934 * V.DEG_TO_RAD),
+ (this.step2.to.mainX = 0),
+ (this.step2.to.mainY = B.cameraPosY),
+ (this.step2.to.mainZ = B.cameraPosZ),
+ (this.step2.to.mainRotX = B.cameraRotX),
+ (this.step2.to.mainRotY = 0),
+ (this.step3 = new un("step3", this.game.camera.rig, 0.3 * this.duration)),
+ (this.step3.to.idleX = 0),
+ (this.step3.to.idleY = 0),
+ (this.step3.to.idleZ = 0),
+ (this.step3.to.idleRotX = 0),
+ (this.step3.to.idleRotY = 0),
+ (this.step3.to.mainX = 0),
+ (this.step3.to.mainY = B.cameraPosY),
+ (this.step3.to.mainZ = B.cameraPosZ),
+ (this.step3.to.mainRotX = B.cameraRotX),
+ (this.step3.to.mainRotY = 0),
+ (this.step3.to.fov = B.cameraFov),
+ (this.step3.curve = St.quintIn),
+ (this.step1.next = this.step2),
+ (this.step2.next = this.step3),
+ this.step1.play();
+ }),
+ (i.complete = function () {
+ (this.playing = !1), this.game.camera.releaseControl(), this.onIntroComplete.dispatch(), this.game.runFromIntro();
+ }),
+ IntroSystem_createClass(IntroSystem, [
+ {
+ key: "ratio",
+ get: function () {
+ return this.time / this.duration;
+ },
+ },
+ ]),
+ IntroSystem
+ );
+ })(f.a),
+ cn = (function () {
+ function CameraPos(t) {
+ (this.idleX = 0), (this.idleY = 0), (this.idleZ = 0), (this.idleRotX = 0), (this.idleRotY = 0), (this.mainX = 0), (this.mainY = 0), (this.mainZ = 0), (this.mainRotX = 0), (this.mainRotY = 0), (this.fov = 60), t && this.copy(t);
+ }
+ return (
+ (CameraPos.prototype.copy = function (t) {
+ (this.idleX = t.idleX),
+ (this.idleY = t.idleY),
+ (this.idleZ = t.idleZ),
+ (this.idleRotX = t.idleRotX),
+ (this.idleRotY = t.idleRotY),
+ (this.mainX = t.mainX),
+ (this.mainY = t.mainY),
+ (this.mainZ = t.mainZ),
+ (this.mainRotX = t.mainRotX),
+ (this.mainRotY = t.mainRotY),
+ (this.fov = t.fov);
+ }),
+ CameraPos
+ );
+ })(),
+ un = (function () {
+ function CameraAnim(t, e, i) {
+ void 0 === i && (i = 1), (this.name = t), (this.rig = e), (this.from = new cn(this.rig)), (this.to = new cn(this.rig)), (this.curve = St.sineInOut), (this.time = 0), (this.duration = i), (this.next = null);
+ }
+ var t = CameraAnim.prototype;
+ return (
+ (t.play = function () {
+ (this.playing = !0), (this.time = 0), (this.from = new cn(this.rig));
+ }),
+ (t.update = function (t) {
+ if (this.playing) {
+ (this.time += t), this.time >= this.duration && (this.time = this.duration);
+ var e = this.curve ? this.curve(this.ratio) : this.ratio;
+ (this.rig.idleX = V.lerp(this.from.idleX, this.to.idleX, e)),
+ (this.rig.idleY = V.lerp(this.from.idleY, this.to.idleY, e)),
+ (this.rig.idleZ = V.lerp(this.from.idleZ, this.to.idleZ, e)),
+ (this.rig.idleRotX = V.lerp(this.from.idleRotX, this.to.idleRotX, e)),
+ (this.rig.idleRotY = V.lerp(this.from.idleRotY, this.to.idleRotY, e)),
+ (this.rig.mainX = V.lerp(this.from.mainX, this.to.mainX, e)),
+ (this.rig.mainY = V.lerp(this.from.mainY, this.to.mainY, e)),
+ (this.rig.mainZ = V.lerp(this.from.mainZ, this.to.mainZ, e)),
+ (this.rig.mainRotX = V.lerp(this.from.mainRotX, this.to.mainRotX, e)),
+ (this.rig.mainRotY = V.lerp(this.from.mainRotY, this.to.mainRotY, e)),
+ (this.rig.fov = V.lerp(this.from.fov, this.to.fov, e)),
+ this.time >= this.duration && this.complete();
+ }
+ }),
+ (t.complete = function () {
+ (this.playing = !1), (this.time = this.duration), this.next && this.next.play();
+ }),
+ IntroSystem_createClass(CameraAnim, [
+ {
+ key: "ratio",
+ get: function () {
+ return this.time / this.duration;
+ },
+ set: function (t) {
+ this.time = this.duration * V.clamp(t);
+ },
+ },
+ ]),
+ CameraAnim
+ );
+ })();
+
+ function Game_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ c.DisplayObject.prototype.depthOffset = 0;
+ var pn = (function (a) {
+ var t, e;
+
+ function Game(t, e, i) {
+ var n;
+ void 0 === e && (e = null);
+ var o = new c.Container(),
+ s = {
+ stage: o,
+ camera: new p.a(),
+ renderer: t.renderer,
+ };
+ return (
+ ((n = a.call(this, s) || this).app = t),
+ (n.w = 512),
+ (n.h = 512),
+ (n.s = 1),
+ n.app.renderer.addSystem(Ne, "bg"),
+ we.init(t.resourceManager.resources),
+ H.refreshCache(),
+ we.refreshCache(),
+ (n.config = e || B),
+ (n.stage = o),
+ (n.bendX = 0),
+ (n.bendY = 0),
+ (n.aspectRatio = 1),
+ (n.blurred = !1),
+ (n.sfx = i),
+ (n.onReset = new et.a("reset")),
+ (n.onIdle = new et.a("idle")),
+ (n.onRun = new et.a("run")),
+ (n.onPause = new et.a("pause")),
+ (n.onResume = new et.a("resume")),
+ (n.onGameover = new et.a("gameover")),
+ (n.onRevive = new et.a("revive")),
+ (n.onEnterTunnel = new et.a("enterTunnel")),
+ (n.onExitTunnel = new et.a("exitTunnel")),
+ n.addSystem(W, {}),
+ n.addSystem(Ie, {}),
+ n.addSystem(xe, {}),
+ n.addSystem(ke, {}),
+ n.addSystem(Pe, {}),
+ n.addSystem(Re, {}),
+ n.addSystem(Fe, {}),
+ n.addSystem(Qi, {}),
+ n.addSystem(tn, {}),
+ n.addSystem(rn, {}),
+ n.addSystem(ln, {}),
+ (e.debug || e.shortcuts) && n.addSystem(Be, {}),
+ (n.view3d.ambientLight.intensity = 1),
+ (n.hero = new wi()),
+ n.addChild(n.hero),
+ (n.cop = new Fi()),
+ n.addChild(n.cop),
+ n
+ );
+ }
+ (e = a), ((t = Game).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ n,
+ o,
+ s = Game.prototype;
+ return (
+ (s.onFocus = function () {
+ (this.blurred = !1), this.sfx.unmute();
+ }),
+ (s.onBlur = function () {
+ (this.blurred = !0), this.sfx.mute(), this.state === Game.RUNNING && this.pause();
+ }),
+ (s.reset = function () {
+ this.hero &&
+ ((this.time = 0),
+ (this.timeScale = this.config.timeScale),
+ (this.delta = 0),
+ (this.secs = 0),
+ (this.bendX = 0),
+ (this.bendY = 0),
+ this.hero.reset(),
+ this.cop && this.cop.reset(),
+ this.dog && this.dog.reset(),
+ this.hud.clearMessage(),
+ this.onReset.run(),
+ this.forceUpdate());
+ }),
+ (s.updateAnimFrame = function (t) {
+ if (!(B.frameSkip && (this._o || (this._o = 0), (this._o += 1), this._o % B.frameSkip))) {
+ void 0 === this._lastTime && (this._lastTime = t);
+ var e = t,
+ i = e - this._lastTime;
+ this._lastTime = e;
+ var n = i / (1e3 / 60);
+ this.update(n);
+ }
+ }),
+ (s.updateTicker = function (t) {
+ if (B.frameSkip) {
+ if ((this._o || (this._o = 0), this._acc || (this._acc = 0), (this._acc += t), (this._o += 1), this._o % B.frameSkip)) return;
+ (t = this._acc), (this._acc = 0);
+ }
+ this.update(t);
+ }),
+ (s.update = function (t, e) {
+ if ((void 0 === e && (e = !0), !this.app.suspended && !this.app.crashed)) {
+ if ((t > B.deltaCap && (t = B.deltaCap), 1 !== !this.timeScale && (t *= this.timeScale), B.smoothDelta ? (this.delta -= 0.2 * (this.delta - t)) : (this.delta = t), B.frameByFrame && this.state !== Game.RUNNING)) {
+ if ((this._accDelta || (this._accDelta = 0), (this._accDelta += 1 / 60 / B.frameByFrame), this._accDelta < 1)) return;
+ (this.delta = 1), (this._accDelta = 0);
+ }
+ if (((this.fps = (1 / this.delta) * B.fps), (this.targetDelta = 1), (this.targetDeltaSecs = 1 / B.fps), (this.deltaSecs = this.delta / B.fps), this.state !== Game.PAUSED)) {
+ if (((this.time += this.delta), (this.secs += this.deltaSecs), this.state === Game.RUNNING ? ((this.stats.time += this.deltaSecs), (this.stats.delta = this.deltaSecs)) : (this.stats.delta = 0), this.config.bend)) {
+ (this.bendX = B.bendX * this.aspectRatio), (this.bendY = B.bendY);
+ var i = O.unformGroup();
+ (i.uBend[0] = this.bendX), (i.uBend[1] = this.bendY), (i.uTime = this.secs);
+ }
+ this._addEntities(),
+ this._removeEntities(),
+ this.onPreupdate.run(),
+ this._removeEntities(),
+ this.onUpdateEntities.run(this.delta),
+ this._removeEntities(),
+ this.onPostupdate.run(),
+ this.updateAndRender && e && this.render(this.delta, 1);
+ }
+ }
+ }),
+ (s.forceUpdate = function (t, e) {
+ void 0 === t && (t = 1), void 0 === e && (e = !1), (this.delta = t), this.update(t, e);
+ }),
+ (s.idle = function () {
+ this.state === Game.RUNNING && nn.a.SDK.gameplayStop(),
+ (this.tutorial.enabled = this.app.user.tutorial || B.tutorial),
+ this.reset(),
+ (this.state = Game.IDLE),
+ this.hero.player.reset(0, 1.2),
+ this.cop && this.cop.reset(),
+ this.onIdle.run(),
+ B.loadAll && (this.level.queueNextChunk(), this.level.queueNextChunk(), this.level.queueNextChunk()),
+ this.forceUpdate();
+ }),
+ (s.run = function () {
+ this.state !== Game.RUNNING &&
+ (H.refreshCache(),
+ we.refreshCache(),
+ this.hud.build(),
+ this.hero.init(),
+ (this.state = Game.RUNNING),
+ this.reset(),
+ this.onRun.run(),
+ this.playTheme(),
+ this.cop && this.cop.run(),
+ this.hero.run(),
+ nn.a.SDK.gameplayStart(),
+ nn.a.sendCustomMessage("game", "roundStart", {}),
+ this.sfx.volume(this.app.settings.sound ? this.config.volume : 0));
+ }),
+ (s.runWithIntro = function () {
+ var t = this;
+ B.loadAll || (H.refreshCache(), we.refreshCache(), this.level.queueNextChunk(), this.level.queueNextChunk(), this.level.queueNextChunk()),
+ nn.a.SDK.gameplayStart(),
+ nn.a.sendCustomMessage("game", "roundStart", {}),
+ this.playTheme(),
+ this.sfx.volume(this.app.settings.sound ? this.config.volume : 0);
+ var e = this._firstIntroPassed ? 50 : 300;
+ this.cop.scale.set(0.01),
+ setTimeout(function () {
+ t.hero.playIntro(), t.cop.playIntro(), t.intro.play(), t.forceUpdate(3);
+ }, e),
+ (this._firstIntroPassed = !0);
+ }),
+ (s.runFromIntro = function () {
+ this.hud.build(), this.cop && this.cop.run(), this.hero.run(), this.camera.run(), this.onRun.run(), (this.state = Game.RUNNING);
+ }),
+ (s.pause = function () {
+ this.state === Game.RUNNING && ((this.state = Game.PAUSED), this.onPause.run(), nn.a.SDK.gameplayStop());
+ }),
+ (s.resume = function (t) {
+ void 0 === t && (t = 0), this.state === Game.PAUSED && (t ? this.hud.runCountdown(t, this.resume.bind(this)) : ((this.state = Game.RUNNING), this.onResume.run(), nn.a.SDK.gameplayStart()));
+ }),
+ (s.gameover = function () {
+ (this.state = Game.GAMEOVER), this.hero.player.stop(), this.cop && this.cop.catchHero(), this.hero && this.onGameover.run(), nn.a.SDK.gameplayStop(), nn.a.sendCustomMessage("game", "roundEnd", {});
+ }),
+ (s.revive = function (t) {
+ var e = this;
+ void 0 === t && (t = 0),
+ this.state !== Game.RUNNING &&
+ (this.hero.player.reset(this.hero.body.z, this.hero.body.x, this.hero.body.lane),
+ (this.hero.active = !1),
+ this.cop && this.cop.reset(),
+ t
+ ? this.hud.runCountdown(t, this.revive.bind(this))
+ : ((this.state = Game.RUNNING),
+ (this.hero.active = !0),
+ this.hero.revive(),
+ this.onRevive.run(),
+ this.hero.player.run(0),
+ this.cop && this.cop.run(),
+ nn.a.SDK.gameplayStart(),
+ setTimeout(function () {
+ e.level.reshuffle();
+ }, 0)));
+ }),
+ (s.resize = function (t, e, i) {
+ (this.aspectRatio = e / t), (this.w = t), (this.h = e), (this.s = i), this.hud && this.hud.resize(t, e, i), this.tutorial && this.tutorial.resize(t, e, i), this.controller && this.controller.resize(t, e);
+ }),
+ (s.playTheme = function () {
+ !this.playingTheme &&
+ B.theme &&
+ ((this.playingTheme = !0),
+ this.sfx.volume(this.config.volume),
+ this.sfx.play("theme", {
+ theme: !0,
+ }),
+ this.sfx.loadAll());
+ }),
+ (s.enterTunnel = function () {
+ this.onEnterTunnel.run();
+ }),
+ (s.exitTunnel = function () {
+ this.onExitTunnel.run();
+ }),
+ (i = Game),
+ (n = [
+ {
+ key: "profile",
+ get: function () {
+ return {
+ fps: this.fps,
+ deltaStep: this.delta,
+ deltaSecs: this.deltaSecs,
+ objects: this.allEntities.length,
+ entities: this.level.entities.length,
+ };
+ },
+ },
+ ]) && Game_defineProperties(i.prototype, n),
+ o && Game_defineProperties(i, o),
+ Game
+ );
+ })(s.a);
+ (pn.IDLE = 0), (pn.RUNNING = 1), (pn.PAUSED = 2), (pn.GAMEOVER = 3);
+ var mn = i(47),
+ fn = i(23);
+ mn.a.addSound = function (t, e, i) {
+ if (!this.disabled) {
+ for (var n = "", o = 1, s = null, a = 0; a < e.length; a++) "/" === e[a] && (s = a);
+ for (null !== s && (n = e.slice(s + 1, e.length)), e = n; this.exists(n); ) (n = e + "-" + o), o++;
+ i = i || {};
+ var r = new Howl({
+ src: t,
+ preload: this.preload,
+ autoplay: i.autoplay || !1,
+ loop: i.loop || !1,
+ volume: i.volume,
+ });
+ i.autoplay && (this.preload || r.load(), r.play()), (r.realVolume = i.volume || 1), (this.sounds[n] = r);
+ }
+ };
+ var gn = (function () {
+ function SoundFX(t) {
+ void 0 === t && (t = !1),
+ (this._volume = 1),
+ mn.a.disableVisibility(),
+ (mn.a._visibilityActive = !1),
+ (mn.a.mute = function () {}),
+ (mn.a.unmute = function () {}),
+ fn.Howler.volume(this._volume),
+ (this.map = {}),
+ (this.disabled = t);
+ }
+ var t = SoundFX.prototype;
+ return (
+ (t.setup = function (t, e) {
+ for (var i in t) {
+ var n = i.split("/").pop();
+ this.map[n] = {
+ key: i,
+ path: e + "/" + i,
+ };
+ }
+ }),
+ (t.load = function (t) {
+ if (!this.disabled) {
+ var e = this.map[t];
+ if (!e.added) {
+ e.added = !0;
+ var i = e.path,
+ n = [i + ".ogg?h=1gefxm5mjzi8pjlr", i + ".mp3?h=1gefxm5mjzi8pjlr"];
+ mn.a.addSound(n, e.key, {});
+ }
+ }
+ }),
+ (t.loadAll = function () {
+ if (!this.disabled) for (var t in this.map) this.load(t);
+ }),
+ (t.play = function (t, e) {
+ var i = void 0 === e ? {} : e,
+ n = i.volume,
+ o = void 0 === n ? null : n,
+ s = i.loop,
+ a = void 0 === s ? null : s,
+ r = i.theme,
+ h = void 0 === r ? null : r;
+ if (!this.disabled) {
+ this.load(t);
+ var d = mn.a.play(t);
+ return (
+ d &&
+ (null !== o && d.volume(o),
+ null !== a && d.loop(a),
+ null !== h &&
+ d.on("end", function () {
+ return d.play();
+ })),
+ d
+ );
+ }
+ }),
+ (t.stop = function (t) {
+ this.disabled || mn.a.stop(t);
+ }),
+ (t.volume = function (t) {
+ if (!this.disabled) return void 0 !== t && ((this._volume = t), fn.Howler.volume(t)), this._volume;
+ }),
+ (t.mute = function () {
+ fn.Howler.mute(!0), fn.Howler.volume(0);
+ }),
+ (t.unmute = function () {
+ fn.Howler.mute(!1), fn.Howler.volume(this._volume);
+ }),
+ SoundFX
+ );
+ })();
+
+ function Section_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+ var yn = {
+ w: 512,
+ h: 512,
+ single: !0,
+ },
+ vn = (function () {
+ function Section(t, e) {
+ void 0 === t && (t = ""),
+ void 0 === e && (e = {}),
+ (this.name = t),
+ (this.owner = null),
+ (this.subs = {}),
+ (this.view = new c.Container()),
+ (this.container = null),
+ (this._opened = !1),
+ (this._built = !1),
+ (this.ticker = new c.Ticker()),
+ this.ticker.stop(),
+ (this.on = {
+ build: new l.a(),
+ resize: new l.a(),
+ open: new l.a(),
+ close: new l.a(),
+ openSub: new l.a(),
+ }),
+ this.on.build.add(this.onBuild, this),
+ this.on.resize.add(this.onResize, this),
+ this.on.open.add(this.onOpen, this),
+ this.on.close.add(this.onClose, this),
+ this.setup(e);
+ }
+ var t,
+ e,
+ i,
+ n = Section.prototype;
+ return (
+ (n.setup = function (t) {
+ void 0 === t && (t = {}), (this.config = Object.assign({}, yn, t)), (this.w = this.config.w), (this.h = this.config.h), (this.s = 1);
+ }),
+ (n.addSub = function (t) {
+ this.subs[t.name] || (((this.subs[t.name] = t).w = this.w), (t.h = this.h), (t.owner = this), (t.container = this.view));
+ }),
+ (n.build = function () {
+ this._built || ((this._built = !0), this.on.build.dispatch());
+ }),
+ (n.open = function (t) {
+ if (
+ (this._opened ||
+ (this.config.single && this.closeOthers(), (this._opened = !0), this.owner && this.owner.open(), this._built || this.build(), this.resize(), this.container && this.container.addChild(this.view), this.on.open.dispatch()),
+ t && t.length)
+ ) {
+ var e = Array.isArray(t) ? t : t.split("/"),
+ i = e.shift(),
+ n = this.subs[i];
+ if (!n) throw new Error("Sub section not found: " + i + " path to open: " + t);
+ this.on.openSub.dispatch(n.name), n.open(e);
+ }
+ }),
+ (n.close = function () {
+ for (var t in this.subs) this.subs[t].close();
+ this._opened && this.on.close.dispatch(), this.view.parent && this.view.parent.removeChild(this.view), (this._opened = !1), this.ticker.stop();
+ }),
+ (n.closeOthers = function () {
+ if (this.owner)
+ for (var t in this.owner.subs) {
+ var e = this.owner.subs[t];
+ e !== this && e.close();
+ }
+ }),
+ (n.closeSubs = function () {
+ for (var t in this.subs) this.subs[t].close();
+ }),
+ (n.resize = function (t, e, i) {
+ for (var n in ((this.sw = t || this.sw),
+ (this.sh = e || this.sh),
+ (this.sr = i || this.sr),
+ (this.s = this.sh / (667 * this.sr)),
+ (this.w = this.sw / this.s),
+ (this.h = this.sh / this.s),
+ this.owner || this.view.scale.set(this.s),
+ this.on.resize.dispatch(),
+ this.subs)) {
+ var o = this.subs[n];
+ (o.w = this.w), (o.h = this.h), (o.s = this.s), (o.sw = this.sw), (o.sh = this.sh), (o.sr = this.sr), o._opened && o.resize(this.sw, this.sh, this.sr);
+ }
+ }),
+ (n.onBuild = function () {}),
+ (n.onResize = function () {}),
+ (n.onOpen = function () {}),
+ (n.onClose = function () {}),
+ (n.getMap = function (t) {
+ for (var e in (void 0 === t && (t = {}), this.owner && (t[this.path] = this), this.subs)) this.subs[e].getMap(t);
+ return t;
+ }),
+ (t = Section),
+ (e = [
+ {
+ key: "path",
+ get: function () {
+ return this.owner ? this.owner.path + "/" + this.name : this.name;
+ },
+ },
+ {
+ key: "root",
+ get: function () {
+ return this.owner ? this.owner.root : this;
+ },
+ },
+ ]) && Section_defineProperties(t.prototype, e),
+ i && Section_defineProperties(t, i),
+ Section
+ );
+ })();
+ var _n = (function (i) {
+ var t, e;
+
+ function TitleScreen(t) {
+ var e;
+ return ((e = i.call(this) || this).app = t), e;
+ }
+ return (e = i), ((t = TitleScreen).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e), TitleScreen;
+ })(c.Container);
+
+ function Button_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+
+ function Button_assertThisInitialized(t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ }
+ var bn = {
+ default: {
+ w: 120,
+ h: 120,
+ round: 5,
+ color: 3246014,
+ border: 16777215,
+ },
+ small: {
+ w: 80,
+ h: 80,
+ round: 5,
+ color: 3246014,
+ border: 16777215,
+ },
+ },
+ wn = (function (s) {
+ var t, e;
+
+ function Button(t) {
+ var e;
+ void 0 === t && (t = {}), ((e = s.call(this) || this).name = t.name || "");
+ var i = t,
+ n = i.base,
+ o = i.icon;
+ return n && e.setBase(n), o && e.setIcon(o), e.on("pointertap", e.onPointerTap.bind(Button_assertThisInitialized(e)), Button_assertThisInitialized(e)), e;
+ }
+ (e = s), ((t = Button).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i,
+ n,
+ o,
+ a = Button.prototype;
+ return (
+ (a.setBase = function (t) {
+ if ((this.base && (Ce.clear(this.base), this.removeChild(this.base)), t)) {
+ if ("string" != typeof t || bn[t])
+ if (t.children) this.base = t;
+ else {
+ var e = Object.assign({}, bn["default"], bn[t] || t);
+ this.base = Ce.roundRectBorder(e);
+ }
+ else (this.base = c.Sprite.from(t)), this.base.anchor.set(0.5);
+ this.addChildAt(this.base, 0);
+ }
+ }),
+ (a.setIcon = function (t) {
+ if ((this.icon && this.removeChild(this.icon), t)) {
+ var e = t.x || 0,
+ i = t.y || 0,
+ n = "string" == typeof t ? t : t.image;
+ (this.icon = c.Sprite.from(n)), this.icon.anchor.set(0.5), (this.icon.x = e), (this.icon.y = i), this.addChild(this.icon);
+ }
+ }),
+ (a.setLabel = function (t, e) {
+ this.label && this.removeChild(this.label), (this.label = new sn(t, e)), this.addChild(this.label);
+ }),
+ (a.onPointerTap = function (t) {
+ t.data.originalEvent.preventDefault(), this._onTap && this._onTap();
+ }),
+ (a.onKeyDown = function (t) {
+ this.interactive && this.visible && this._key && !t.repeat && this._onTap && t[this._keyField] === this._key && this._onTap();
+ }),
+ (a._update = function () {}),
+ (i = Button),
+ (n = [
+ {
+ key: "key",
+ get: function () {
+ return this._key;
+ },
+ set: function (t) {
+ (this._key = t),
+ (this._keyField = "string" == typeof t ? "code" : "which"),
+ this._onKeyDownBind || (this._onKeyDownBind = this.onKeyDown.bind(this)),
+ document.removeEventListener("keyup", this._onKeyDownBind),
+ this._key && document.addEventListener("keyup", this._onKeyDownBind);
+ },
+ },
+ {
+ key: "onTap",
+ set: function (t) {
+ (this._onTap = t), (this.enabled = !!t);
+ },
+ get: function () {
+ return this._onTap;
+ },
+ },
+ {
+ key: "enabled",
+ set: function (t) {
+ this.interactive = t;
+ var e = (this.buttonMode = t) ? 1 : 0.5;
+ this.base && (this.base.alpha = e);
+ },
+ get: function () {
+ return this.interactive;
+ },
+ },
+ {
+ key: "selected",
+ set: function (t) {
+ var e = (this._selected = t) ? 5592405 : 16777215;
+ this.base && (this.base.fill.tint = e);
+ },
+ get: function () {
+ return !!this._selected;
+ },
+ },
+ ]) && Button_defineProperties(i.prototype, n),
+ o && Button_defineProperties(i, o),
+ Button
+ );
+ })(c.Container);
+ var kn = (function (i) {
+ var t, e;
+
+ function GameScreen(t) {
+ var e;
+ return ((e = i.call(this) || this).app = t), e;
+ }
+ (e = i), ((t = GameScreen).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n = GameScreen.prototype;
+ return (
+ (n.onShow = function () {
+ this._firstRun || ((this._firstRun = !0), nn.a.sendCustomMessage("game", "play", {})),
+ this.app.game.onRun.add(this),
+ this.app.game.onPause.add(this),
+ this.app.game.onResume.add(this),
+ this.app.game.onGameover.add(this),
+ this.app.game.onRevive.add(this),
+ this.app.game.runWithIntro(),
+ this.btnPause ||
+ ((this.btnPause = new wn({
+ icon: "icon_pause.png",
+ base: "small",
+ })),
+ (this.btnPause.onTap = this.onBtnPausePress.bind(this)),
+ this.btnPause.scale.set(0.5),
+ (this.btnPause.x = 35),
+ (this.btnPause.y = 35)),
+ this.addChild(this.btnPause),
+ (this.btnPause.visible = !0);
+ }),
+ (n.onHide = function () {
+ this.app.game.onPause.remove(this), this.app.game.onResume.remove(this), this.app.game.onGameover.remove(this), this.app.game.onRevive.remove(this);
+ }),
+ (n.run = function () {
+ this.updateView();
+ }),
+ (n.gameover = function () {
+ var t = this;
+ this.updateView(), (this.btnPause.visible = !1);
+ var e = B.mobile ? "Mobile" : "",
+ i = this.app.config["rewardedBreaks" + e],
+ n = this.app.game.stats.revivals && !this.app.config.adBlocking;
+ setTimeout(function () {
+ i && n ? ((t.btnPause.visible = !1), (t.app.game.stats.revivals -= 1), t.app.sections.open("saveme")) : t.finishRun();
+ }, 1500);
+ }),
+ (n.finishRun = function () {
+ var e = this;
+ if ((this.updateView(), (this.btnPause.visible = !1), this.app.user.load(), (this.app.user.tutorial = !1), !this.app.user.nameSet && this.app.config.leaderboards)) {
+ var t = this.app.strings.get("nickname_prompt");
+ this.app.prompt.open(t, this.app.user.name, function (t) {
+ t && (e.app.user.name = t), (e.app.user.nameSet = !0), e.finishRunComplete();
+ });
+ } else this.finishRunComplete();
+ }),
+ (n.finishRunComplete = function () {
+ var t = this,
+ e = this.app.game.stats.score;
+ (this.app.user.coins += this.app.game.stats.coins),
+ e > this.app.user.score
+ ? ((this.app.user.score = e),
+ nn.a.SDK.happyTime(1),
+ nn.a.hangout.saveHighscore(this.app.user.name, e).then(function () {
+ t.app.sections.open("gameover");
+ }))
+ : this.app.sections.open("gameover"),
+ this.app.user.save();
+ }),
+ (n.revive = function () {
+ this.updateView();
+ }),
+ (n.pause = function () {
+ this.updateView();
+ }),
+ (n.resume = function () {
+ this.updateView();
+ }),
+ (n.resize = function (t, e) {}),
+ (n.onBtnPausePress = function () {
+ this.app.game.state === pn.PAUSED ? (this.app.game.resume(0), this.updateView(!1)) : (this.app.game.pause(), this.updateView());
+ }),
+ (n.onBtnPlayPress = function () {
+ this.app.game.resume(3), this.updateView(!1);
+ }),
+ (n.onBtnRestartPress = function () {
+ this.app.game.run(), this.updateView();
+ }),
+ (n.updateView = function (t) {
+ void 0 === t && (t = this.app.game.state === pn.PAUSED), t ? this.app.sections.open("pause") : this.app.sections.close(), this.btnPause && (this.btnPause.visible = this.app.game.state !== pn.PAUSED);
+ }),
+ GameScreen
+ );
+ })(c.Container);
+ var xn = (function (n) {
+ var t, e;
+
+ function LoadingScreen(t, e) {
+ var i;
+ return (
+ void 0 === e && (e = 998272),
+ ((i = n.call(this) || this).app = t),
+ (i.w = 512),
+ (i.h = 512),
+ (i.color = "string" == typeof e ? c.utils.string2hex(e) : e),
+ (i.view = new c.Container()),
+ i.addChild(i.view),
+ (i.firstLoadPassed = !1),
+ i
+ );
+ }
+ (e = n), ((t = LoadingScreen).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = LoadingScreen.prototype;
+ return (
+ (i.build = function () {
+ this.bg ||
+ ((this.bg = new c.Graphics()),
+ this.bg.beginFill(this.color, 1),
+ this.bg.drawRect(0, 0, 16, 16),
+ this.bg.endFill(),
+ this.addChildAt(this.bg, 0),
+ (this.splash = c.Sprite.from("preload/splash")),
+ this.splash.anchor.set(0.5),
+ this.view.addChild(this.splash),
+ this.buildBar(),
+ this.resize(),
+ this.updateView());
+ }),
+ (i.buildBar = function () {
+ if (!this.bar) {
+ (this.bar = new c.Container()), this.view.addChild(this.bar), (this.bar.y = 160);
+ var t = 300,
+ e = 40,
+ i = new c.Graphics();
+ i.beginFill(0, 0.75), i.drawRect(0, 0, t, e), i.position.set(-t / 2, -e / 2), this.bar.addChild(i), (this.bar.bg = i), (t -= 8), (e -= 8);
+ var n = new c.Graphics();
+ n.beginFill(16142336), n.drawRect(0, 0, t, e), n.position.set(-t / 2, -e / 2), (n.scale.x = 0.01), this.bar.addChild(n), (this.bar.fill = n);
+ var o = "loading_" + this.app.config.lang,
+ s = (this.app.config[o] || "loading").toUpperCase() + "...",
+ a = new sn(s, {
+ fill: 16777215,
+ fontSize: 20,
+ dropShadow: !1,
+ });
+ this.bar.addChild(a), (this.bar.label = a);
+ }
+ }),
+ (i.updateProgress = function (t) {
+ this.bar && (this.bar.fill.scale.x = t / 100);
+ }),
+ (i.resize = function (t, e) {
+ (this.w = t || this.w), (this.h = e || this.h), (this.view.position.x = this.w / 2), (this.view.position.y = this.h / 2), this.bg && ((this.bg.width = this.w), (this.bg.height = this.h)), this.updateView();
+ }),
+ (i.onShow = function () {
+ this.updateView(!this.app.bgLoading), this.reset(), (this._opened = !0);
+ }),
+ (i.onHidden = function () {}),
+ (i.updateView = function (t) {
+ void 0 !== t && (this.view.visible = t), this.bg && ((this.bg.visible = this.view.visible), (this.bg.alpha = this.firstLoadPassed ? 0.5 : 1)), this.splash && (this.splash.visible = !this.firstLoadPassed);
+ }),
+ (i.holdForFrame = function () {
+ (this.view.visible = !0), this.bg && (this.bg.visible = !0), this.splash && (this.splash.visible = !0);
+ }),
+ (i.reset = function () {
+ this.updateProgress(0);
+ }),
+ LoadingScreen
+ );
+ })(c.Container),
+ Cn = i(68),
+ Sn = (function () {
+ function Event(t) {
+ this.app = t;
+ }
+ var t = Event.prototype;
+ return (
+ (t.init = function () {
+ var t = this.app.addSignal("onBlur"),
+ e = this.app.addSignal("onFocus");
+ Cn.a.onShow.add(function () {
+ return e.dispatch();
+ }),
+ Cn.a.onHide.add(function () {
+ return t.dispatch();
+ }),
+ window.addEventListener("blur", function () {
+ return t.dispatch();
+ }),
+ window.addEventListener("focus", function () {
+ return e.dispatch();
+ }),
+ window.addEventListener("pagehide", function () {
+ return t.dispatch();
+ }),
+ window.addEventListener("pageshow", function () {
+ return e.dispatch();
+ }),
+ window.addEventListener("gesturestart", this._onEventPreventDefault.bind(this)),
+ window.addEventListener("gesturechange", this._onEventPreventDefault.bind(this)),
+ window.addEventListener("gestureend", this._onEventPreventDefault.bind(this)),
+ window.addEventListener("touchmove", this._onEventPreventDefault.bind(this));
+ }),
+ (t._onEventPreventDefault = function (t) {
+ t.preventDefault();
+ }),
+ Event
+ );
+ })(),
+ zn = (function () {
+ function Message(t) {
+ this.app = t;
+ }
+ var t = Message.prototype;
+ return (
+ (t.init = function () {
+ var e = this.app.addSignal("onMessage");
+ window.addEventListener(
+ "message",
+ function (t) {
+ return e.dispatch(t);
+ },
+ !1
+ );
+ }),
+ (t.postToParent = function (t, e) {
+ var i = window.parent;
+ if (i)
+ try {
+ i.postMessage(
+ {
+ type: t,
+ content: {
+ event: e,
+ },
+ },
+ "*"
+ );
+ } catch (t) {}
+ }),
+ (t.sendCustomMessage = function (t, e, i) {
+ if (window.parent)
+ try {
+ window.parent.postMessage(
+ {
+ type: "pokiMessageEvent",
+ content: {
+ event: "pokiTrackingCustom",
+ data: {
+ eventNoun: t,
+ eventVerb: e,
+ eventData: i,
+ },
+ },
+ },
+ "*"
+ );
+ } catch (t) {}
+ }),
+ Message
+ );
+ })(),
+ Tn = (function () {
+ function Size(t) {
+ (this.app = t), (this.w = 512), (this.h = 512), (this.sw = 512), (this.sh = 512), (this.scale = 1);
+ }
+ var t = Size.prototype;
+ return (
+ (t.init = function () {
+ var t = this;
+ (this._onResize = this.app.addSignal("onResize")),
+ window.addEventListener("resize", function () {
+ return t.onChange();
+ }),
+ window.addEventListener("orientationchange", function () {
+ return t.onChange();
+ }),
+ this.update();
+ }),
+ (t.onChange = function () {
+ var t = this;
+ this.update();
+ for (var e = 0; e < 5; e++)
+ setTimeout(function () {
+ return t.update();
+ }, 200 * e);
+ }),
+ (t.update = function () {
+ window.scrollTo(0, 0),
+ (this.w = window.innerWidth),
+ (this.h = window.innerHeight),
+ (this.scale = window.devicePixelRatio || 1),
+ r.a.instance.isMobile && !window.devicePixelRatio && (this.scale = window.screen.deviceXDPI / window.screen.logicalXDPI),
+ this.scale > B.maxViewportScale && (this.scale = B.maxViewportScale),
+ (this.sw = this.w * this.scale),
+ (this.sh = this.h * this.scale),
+ this._onResize.dispatch(this);
+ }),
+ (t.requestFullScreen = function () {
+ r.a.instance.android && (document.body.mozRequestFullScreen ? document.body.mozRequestFullScreen() : document.body.webkitRequestFullScreen && document.body.webkitRequestFullScreen(), this.update());
+ }),
+ Size
+ );
+ })(),
+ Pn = (function () {
+ function Strings(t) {
+ (this.app = t), (this.lang = "en"), (this.data = {});
+ }
+ var t = Strings.prototype;
+ return (
+ (t.onAppReady = function () {
+ this.load(this.app.config.lang);
+ }),
+ (t.get = function (t) {
+ return this.data[t];
+ }),
+ (t.upper = function (t) {
+ return this.data[t].toUpperCase();
+ }),
+ (t.load = function (t) {
+ t && (this.lang = t), (this.data = this.loadStrings(this.lang));
+ }),
+ (t.loadStrings = function (t) {
+ var e = this.app.resourceManager.resources,
+ i = e["data/strings_en"].data,
+ n = e["data/strings_" + t].data;
+ return Object.assign({}, i, n);
+ }),
+ Strings
+ );
+ })(),
+ Mn = (function () {
+ function Debug(t) {
+ this.app = t;
+ }
+ var t = Debug.prototype;
+ return (
+ (t.init = function () {
+ (this.div = document.createElement("div")),
+ (this.div.style.backgroundColor = "rgba(255,255,255,0.5)"),
+ (this.div.style.width = "100%"),
+ (this.div.style.height = "100%"),
+ (this.div.style.top = "50px"),
+ (this.div.style.left = "0px"),
+ (this.div.style.position = "absolute"),
+ (this.div.style.zIndex = 999),
+ window.addEventListener("keydown", this.onKeyDown.bind(this));
+ }),
+ (t.onAppReady = function () {}),
+ (t.onResize = function (t, e) {}),
+ (t.onKeyDown = function (t) {
+ "Escape" === t.key && this.toggle();
+ }),
+ (t.show = function () {
+ this.shown || ((this.shown = !0), document.body.appendChild(this.div), this.mountSections());
+ }),
+ (t.hide = function () {
+ this.shown && ((this.shown = !1), document.body.removeChild(this.div));
+ }),
+ (t.toggle = function () {
+ this.shown ? this.hide() : this.show();
+ }),
+ (t.mountSections = function () {
+ var o = this;
+ if (!this.divSections) {
+ (this.divSections = document.createElement("div")), this.div.appendChild(this.divSections);
+ var t = this.app.sections.getMap(),
+ s = Object.keys(t).sort(),
+ e = function (t) {
+ var e = s[t],
+ i = document.createElement("button"),
+ n = e.replace("root/", "");
+ (i.innerText = n),
+ o.divSections.appendChild(i),
+ o.divSections.appendChild(document.createElement("br")),
+ i.addEventListener("click", function () {
+ return o.app.sections.open(n);
+ });
+ };
+ for (var i in s) e(i);
+ }
+ }),
+ Debug
+ );
+ })();
+ var En = (function (i) {
+ var t, e;
+
+ function SectionTitle(t) {
+ var e;
+ return ((e = i.call(this) || this).app = t), (e.name = "title"), e;
+ }
+ (e = i), ((t = SectionTitle).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n = SectionTitle.prototype;
+ return (
+ (n.onBuild = function () {
+ var t = this;
+ i.prototype.onBuild.call(this),
+ (this.labelMsg = new sn("")),
+ (this.labelMsg.rotation = 0.15),
+ this.view.addChild(this.labelMsg),
+ (this.tapToPlayArea = new c.Graphics()),
+ this.tapToPlayArea.beginFill(16711680),
+ this.tapToPlayArea.drawRect(0, 0, 16, 16),
+ this.tapToPlayArea.endFill(),
+ (this.tapToPlayArea.alpha = 0),
+ (this.tapToPlayArea.interactive = !0),
+ this.tapToPlayArea.addListener("pointerdown", this.playGame.bind(this)),
+ this.view.addChild(this.tapToPlayArea),
+ (this.bottomMenu = new c.Container()),
+ this.view.addChild(this.bottomMenu),
+ (this.btnTopRun = new wn()),
+ this.btnTopRun.setIcon({
+ image: "front_icon_top_run.png",
+ y: -10,
+ }),
+ this.btnTopRun.setBase({
+ color: 5254027,
+ w: 230,
+ }),
+ this.bottomMenu.addChild(this.btnTopRun),
+ (this.btnTopRun.x = this.btnTopRun.width / 2),
+ (this.btnTopRun.onTap = function () {
+ return t.app.sections.open("toprun");
+ }),
+ (this.btnSettings = new wn()),
+ this.btnSettings.setIcon("icon_settings.png"),
+ this.btnSettings.setBase(
+ Ce.rectComp(
+ {
+ w: 96,
+ h: 98,
+ image: "box_border_grey_small.png",
+ x: 1,
+ y: 1,
+ },
+ {
+ w: 80,
+ h: 80,
+ color: 3574206,
+ round: 6,
+ }
+ )
+ ),
+ (this.btnSettings.onTap = function () {
+ return t.app.sections.open("settings");
+ }),
+ this.view.addChild(this.btnSettings),
+ (this.keyDownBind = this.onKeyDown.bind(this));
+ }),
+ (n.onResize = function () {
+ i.prototype.onResize.call(this);
+ var t = this.w,
+ e = this.h;
+ (this.labelMsg.x = 0.5 * t - 100),
+ (this.labelMsg.y = e - 300),
+ (this.tapToPlayArea.width = t),
+ (this.tapToPlayArea.height = e),
+ (this.bottomMenu.x = t / 2 - this.bottomMenu.width / 2),
+ (this.bottomMenu.y = e - 90),
+ (this.btnSettings.x = 60),
+ (this.btnSettings.y = 60);
+ }),
+ (n.onOpen = function () {
+ //alert("n.onOpen");
+ dataLayer.push({
+ event: "ga_event",
+ ga_category: "Gamepage",
+ ga_action: "Main Menu",
+ ga_label: window.productTitle,
+ ga_noninteraction: true,
+ });
+ i.prototype.onOpen.call(this),
+ (this.count = 0),
+ (this.tapToPlayArea.interactive = !0),
+ window.addEventListener("keydown", this.keyDownBind),
+ this.app.screenManager.gotoScreenByID("title"),
+ this.ticker.add(this.update, this, 1),
+ this.ticker.start();
+ var t = B.mobile ? "tap_to_play" : "tap_to_play_desktop",
+ e = this.app.strings.get(t);
+ this.labelMsg.text = e;
+ }),
+ (n.onClose = function () {
+ i.prototype.onClose.call(this), (this.tapToPlayArea.interactive = !1), window.removeEventListener("keydown", this.keyDownBind), this.ticker.remove(this.update, this);
+ }),
+ (n.onKeyDown = function (t) {
+ t.repeat || 32 !== t.which || (this.app.game.state === pn.IDLE && this.playGame());
+ }),
+ (n.playGame = function () {
+ console.info(window.productTitle);
+ dataLayer.push({
+ event: "ga_event",
+ ga_category: "Gamepage",
+ ga_action: "Start",
+ ga_label: window.productTitle,
+ ga_noninteraction: false,
+ });
+
+ this.app.game.state === pn.IDLE && (nn.a.sendCustomMessage("mainMenu", "pressPlay", {}), (this.tapToPlayArea.interactive = !1), this.app.nav.playGame());
+ }),
+ (n.update = function (t) {
+ (this.labelMsg.rotation = 0.15 + 0.02 * Math.sin(this.count)), (this.count += 0.1 * t);
+ }),
+ SectionTitle
+ );
+ })(vn);
+ var On = (function (e) {
+ var t, i;
+
+ function ScreenGlow() {
+ var t;
+ return (
+ ((t = e.call(this) || this).w = 512),
+ (t.h = 512),
+ (t.bottom = c.Sprite.from("base_blurry.png")),
+ t.addChild(t.bottom),
+ (t.top = c.Sprite.from("base_blurry.png")),
+ t.addChild(t.top),
+ (t.top.scale.y = -1),
+ (t.top.anchor.y = 1),
+ (t.bg = new c.Graphics()),
+ t.bg.beginFill(0, 0.5),
+ t.bg.drawRect(0, 0, 16, 16),
+ t.bg.endFill(),
+ t.addChild(t.bg),
+ t
+ );
+ }
+ return (
+ (i = e),
+ ((t = ScreenGlow).prototype = Object.create(i.prototype)),
+ ((t.prototype.constructor = t).__proto__ = i),
+ (ScreenGlow.prototype.resize = function (t, e) {
+ (this.w = t || this.w),
+ (this.h = e || this.h),
+ (this.bg.width = this.w),
+ (this.bg.height = this.h),
+ (this.bottom.width = this.w),
+ (this.bottom.height = 230),
+ (this.bottom.y = this.h - this.bottom.height),
+ (this.top.width = this.w),
+ (this.top.height = this.bottom.height);
+ }),
+ ScreenGlow
+ );
+ })(c.Container);
+ var Rn = (function (e) {
+ var t, i;
+
+ function Clock() {
+ var t;
+ return (
+ ((t = e.call(this) || this).base = c.Sprite.from("clock_base.png")),
+ t.base.anchor.set(0.5),
+ (t.base.x = -1),
+ (t.base.y = -1),
+ t.addChild(t.base),
+ (t.fill = c.Sprite.from("clock_fill.png")),
+ t.fill.anchor.set(0.5),
+ t.addChild(t.fill),
+ (t.onComplete = null),
+ (t.ticker = new c.Ticker()),
+ t.ticker.stop(),
+ t
+ );
+ }
+ (i = e), ((t = Clock).prototype = Object.create(i.prototype)), ((t.prototype.constructor = t).__proto__ = i);
+ var n = Clock.prototype;
+ return (
+ (n.run = function (t, e) {
+ this.secs && this.stop(), (this.time = t), (this.secs = t), (this.onComplete = e), this.update(0), this.ticker.add(this.update, this, 1), this.ticker.start();
+ }),
+ (n.stop = function () {
+ (this.secs = 0), this.ticker.remove(this.update, this), this.ticker.stop();
+ }),
+ (n.complete = function () {
+ this.stop(), this.onComplete && this.onComplete();
+ }),
+ (n.update = function (t) {
+ var e = t / 60;
+ (this.secs -= e), this.updatePizza(), this.secs < 0 && this.complete();
+ }),
+ (n.updatePizza = function () {
+ this.pizza || ((this.pizza = new c.Graphics()), this.addChild(this.pizza));
+ var t = this.secs / this.time,
+ e = V.PI_DOUBLE * t;
+ this.pizza.clear(), this.pizza.beginFill(15658734), this.pizza.moveTo(0, 0), this.pizza.arc(0, 0, 43, 0, e, !0), (this.pizza.rotation = -V.PI_HALF), (this.pizza.scale.y = -1);
+ }),
+ Clock
+ );
+ })(c.Container);
+ var In = (function (i) {
+ var t, e;
+
+ function SectionSaveMe(t) {
+ var e;
+ return ((e = i.call(this) || this).name = "saveme"), (e.app = t), e;
+ }
+ (e = i), ((t = SectionSaveMe).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n = SectionSaveMe.prototype;
+ return (
+ (n.onBuild = function () {
+ var t = this;
+ (this.bg = new On(this.app.color)),
+ this.view.addChild(this.bg),
+ (this.bg.interactive = !0),
+ this.bg.on("pointertap", function () {
+ return t.exit();
+ }),
+ (this.content = new c.Container()),
+ this.view.addChild(this.content);
+ (this.base = Ce.rectComp(
+ {
+ w: 500,
+ h: 250,
+ color: 15658734,
+ round: 16,
+ },
+ {
+ w: 522,
+ h: 274,
+ image: "box_border_grey.png",
+ x: 5,
+ y: 6,
+ }
+ )),
+ this.content.addChild(this.base),
+ (this.base.interactive = !0),
+ this.base.on("pointertap", function () {
+ return t.exit();
+ });
+ (this.btnRevive = new wn({
+ key: "Space",
+ })),
+ this.btnRevive.setBase(
+ Ce.rectComp(
+ {
+ w: 316,
+ h: 120,
+ image: "box_border_grey.png",
+ x: 5,
+ y: 6,
+ },
+ {
+ w: 300,
+ h: 100,
+ image: "box_fill_green.png",
+ x: 2,
+ y: 2,
+ r: 20,
+ b: 20,
+ }
+ )
+ ),
+ this.btnRevive.setIcon({
+ image: "icon_tv.png",
+ x: 60,
+ y: -10,
+ }),
+ this.btnRevive.setLabel(this.app.strings.upper("free"), {
+ fontSize: 40,
+ fontFamily: "Lilita One",
+ dropShadowDistance: 1,
+ x: -50,
+ }),
+ (this.btnRevive.onTap = function () {
+ return t.revive();
+ }),
+ this.content.addChild(this.btnRevive);
+ this.btnRevive.y = 40;
+ var e = this.app.strings.get("save_me");
+ (this.title = new sn(e, {
+ align: "center",
+ fill: 19072,
+ fontSize: 40,
+ fontFamily: "Titan One",
+ dropShadow: !1,
+ dropShadowDistance: 1,
+ anchor: 0.5,
+ })),
+ this.content.addChild(this.title),
+ (this.title.y = -80),
+ (this.clock = new Rn()),
+ this.content.addChild(this.clock),
+ (this.clock.x = -230),
+ (this.clock.y = -105);
+ }),
+ (n.onOpen = function () {
+ var t = this;
+ i.prototype.onOpen.call(this),
+ this.clock.run(6, function () {
+ return t.exit();
+ }),
+ (this.btnRevive.key = "Space"),
+ (this._allowExit = !1),
+ setTimeout(function () {
+ t._allowExit = !0;
+ }, 500);
+ }),
+ (n.onClose = function () {
+ i.prototype.onClose.call(this), this.clock.stop(), (this.btnRevive.key = null);
+ }),
+ (n.exit = function () {
+ this._allowExit && this.app.gameScreen.finishRun();
+ }),
+ (n.onResize = function () {
+ i.prototype.onResize.call(this), this.bg.resize(this.w, this.h), (this.content.x = this.w / 2), (this.content.y = this.h / 2);
+ }),
+ (n.revive = function () {
+ var e = this;
+ this.app.sections.close(),
+ this.app.suspend(),
+ B.debug
+ ? (this.app.resume(), this.app.game.revive(1))
+ : nn.a.SDK.rewardedBreak().then(function (t) {
+ e.app.resume(), t ? e.app.game.revive(5) : e.app.gameScreen.finishRun();
+ });
+ }),
+ SectionSaveMe
+ );
+ })(vn);
+ var Ln = (function (e) {
+ var t, i;
+
+ function Scoreboard() {
+ var t;
+ return (
+ ((t = e.call(this) || this).base = c.Sprite.from("scoreboard.png")),
+ t.base.anchor.set(0.5),
+ t.addChild(t.base),
+ (t.title = new sn("", {
+ align: "center",
+ fill: 19072,
+ fontSize: 60,
+ fontFamily: "Titan One",
+ dropShadow: !1,
+ dropShadowDistance: 1,
+ })),
+ t.addChild(t.title),
+ (t.title.x = -15),
+ (t.title.y = -110),
+ (t.title.rotation = -0.07),
+ (t.score = new sn("", {
+ align: "center",
+ fill: 16777215,
+ fontSize: 55,
+ fontFamily: "Lilita One",
+ dropShadow: !0,
+ dropShadowDistance: 1,
+ })),
+ t.addChild(t.score),
+ (t.score.y = -33),
+ (t.coins = new sn("", {
+ align: "center",
+ fill: 16777215,
+ fontSize: 45,
+ fontFamily: "Lilita One",
+ dropShadow: !0,
+ dropShadowDistance: 1,
+ })),
+ t.addChild(t.coins),
+ (t.coins.y = 35),
+ (t.icon = c.Sprite.from("icon_coin.png")),
+ t.icon.anchor.set(0.5),
+ t.icon.scale.set(0.75),
+ t.addChild(t.icon),
+ (t.icon.x = t.coins.x - 100),
+ (t.icon.y = t.coins.y),
+ (t.starL = c.Sprite.from("icon_star.png")),
+ t.starL.anchor.set(0.5),
+ (t.starL.x = -120),
+ t.title.addChild(t.starL),
+ (t.starR = c.Sprite.from("icon_star.png")),
+ t.starR.anchor.set(0.5),
+ (t.starR.x = -t.starL.x),
+ t.title.addChild(t.starR),
+ t
+ );
+ }
+ return (
+ (i = e),
+ ((t = Scoreboard).prototype = Object.create(i.prototype)),
+ ((t.prototype.constructor = t).__proto__ = i),
+ (Scoreboard.prototype.update = function (t) {
+ void 0 === t && (t = {}),
+ (t = Object.assign(
+ {
+ title: "Score",
+ score: 0,
+ coins: 0,
+ },
+ t
+ )),
+ (this.title.text = t.title),
+ (this.score.text = t.score),
+ (this.coins.text = t.coins);
+ }),
+ Scoreboard
+ );
+ })(c.Container);
+ var jn = (function (n) {
+ var t, e;
+
+ function Spinner(t) {
+ var e;
+ e = n.call(this) || this;
+ var i = Object.assign(
+ {},
+ {
+ radius: 32,
+ color: 0,
+ },
+ t
+ );
+ return (
+ (e.image = new c.Graphics()),
+ e.image.lineStyle(i.radius, i.color),
+ e.image.arc(0, 0, 2 * i.radius, 0, 0.5 * Math.PI, !0),
+ e.addChild(e.image),
+ e.image.scale.set(0.5),
+ (e.image.alpha = 0.25),
+ (e.visible = !1),
+ (e.ticker = new c.Ticker()),
+ e.ticker.stop(),
+ e.ticker.add(
+ e.update,
+ (function (t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ })(e),
+ 1
+ ),
+ e
+ );
+ }
+ (e = n), ((t = Spinner).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Spinner.prototype;
+ return (
+ (i.show = function () {
+ (this.visible = !0), this.ticker.start();
+ }),
+ (i.hide = function () {
+ (this.visible = !1), this.ticker.stop();
+ }),
+ (i.update = function (t) {
+ void 0 === t && (t = 0), (this.image.rotation += 0.2 * t);
+ }),
+ Spinner
+ );
+ })(c.Container);
+ var Fn = (function (n) {
+ var t, e;
+
+ function RemoteImage(t) {
+ var e;
+ e = n.call(this) || this;
+ var i = Object.assign(
+ {},
+ {
+ path: "",
+ w: 0,
+ h: 0,
+ bg: null,
+ }
+ );
+ return (
+ "string" == typeof t ? (i.path = t) : Object.assign(i, t),
+ null !== i.bg && ((e.bg = new c.Graphics()), e.bg.beginFill(i.bg), e.bg.drawRect(-i.w / 2, -i.h / 2, i.w, i.h), e.bg.endFill(), e.addChildAt(e.bg, 0)),
+ (e.image = new c.Sprite()),
+ i.w && (e.image.width = i.w),
+ i.h && (e.image.height = i.h),
+ e.addChild(e.image),
+ (e.spinner = new jn()),
+ e.addChild(e.spinner),
+ e.spinner.show(),
+ i.path && e.load(i.path),
+ e
+ );
+ }
+ (e = n), ((t = RemoteImage).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = RemoteImage.prototype;
+ return (
+ (i.load = function (t) {
+ if (((this._path = t), (this.image.visible = !1), this.spinner && this.spinner.show(), c.utils.TextureCache[t])) this.onLoadComplete();
+ else {
+ var e = RemoteImage.cache[t];
+ e || ((e = new c.Loader()).add(t, t), (RemoteImage.cache[t] = e)), e.onLoad.once(this.onLoadComplete, this), e.load();
+ }
+ }),
+ (i.onLoadComplete = function () {
+ (this.image.visible = !0), (this.image.texture = c.Texture.from(this._path)), this.image.anchor.set(0.5), this.spinner && this.spinner.hide();
+ }),
+ RemoteImage
+ );
+ })(c.Container);
+ Fn.cache = {};
+ var An = (function (i) {
+ var t, e;
+
+ function AvatarIcon(t) {
+ var e;
+ return (
+ void 0 === t && (t = 64),
+ ((e =
+ i.call(this, {
+ w: t,
+ h: t,
+ bg: 16777215,
+ path: "",
+ }) || this).w = t),
+ (e.h = t),
+ e.spinner.scale.set(0.4),
+ e
+ );
+ }
+ return (
+ (e = i),
+ ((t = AvatarIcon).prototype = Object.create(e.prototype)),
+ ((t.prototype.constructor = t).__proto__ = e),
+ (AvatarIcon.prototype.update = function (t) {
+ void 0 === t && (t = {}),
+ (t = Object.assign(
+ {
+ image: "icon_friend",
+ color: 16777215,
+ border: 4,
+ },
+ t
+ )),
+ (this.bg.width = this.w),
+ (this.bg.height = this.h),
+ (this.image.width = this.w - 2 * t.border),
+ (this.image.height = this.h - 2 * t.border),
+ this.spinner.scale.set(0.4),
+ this.load("assets/placeholder/" + t.image + ".png");
+ }),
+ AvatarIcon
+ );
+ })(Fn);
+
+ function Ranking_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ var Dn = (function (s) {
+ function Ranking(t, e) {
+ var i;
+ void 0 === t && (t = 70), void 0 === e && (e = 10), ((i = s.call(this) || this).entries = []), (i.length = 11), (i.name = "");
+ for (var n = (i.score = 0); n < i.length; n++) {
+ var o = new Gn(t, e);
+ i.entries.push(o), i.addChild(o);
+ }
+ return i.placeholder(), i;
+ }
+ Ranking_inheritsLoose(Ranking, s);
+ var t = Ranking.prototype;
+ return (
+ (t.placeholder = function () {
+ for (var t = [], e = 0; e < this.length; e++)
+ t.push({
+ index: e + 1,
+ loading: !0,
+ });
+ this.updateEntries(t);
+ }),
+ (t.update = function (t, e) {
+ var i = this;
+ (this.name = t),
+ (this.score = e),
+ nn.a.hangout.getLeaderboard(this.length, t, e).then(function (t) {
+ return i.updateScores(t);
+ });
+ }),
+ (t.updateScores = function (t) {
+ t = t.sort(function (t, e) {
+ return e.score - t.score;
+ });
+ for (var e = !1, i = 0; i < this.length; i++) {
+ var n = t[i];
+ n && (n.image || (n.image = "icon_friend"), (n.highlight = n.name === this.name && n.score === this.score), "ME" === n.name && (n.highlight = !0), n.highlight && (e = !0), (n.index = i + 1));
+ }
+ e ||
+ (t[this.length - 1] = {
+ name: this.name,
+ score: this.score,
+ image: "icon_friend",
+ highlight: !0,
+ index: "",
+ }),
+ this.updateEntries(t);
+ }),
+ (t.updateEntries = function (t) {
+ for (var e = this.title && this.title.text ? 80 : 0, i = 0; i < this.length; i++) {
+ var n = this.entries[i],
+ o = t[i];
+ (n.visible = !!o), o && (n.update(o), (n.y = i * n.h + e));
+ }
+ }),
+ (t.setTitle = function (t) {
+ this.title ||
+ (this.title = new sn("", {
+ align: "center",
+ fill: 211825,
+ fontSize: 70,
+ fontFamily: "Titan One",
+ dropShadowDistance: 1,
+ })),
+ (this.title.visible = !!t),
+ (this.title.text = t),
+ this.addChild(this.title);
+ }),
+ Ranking
+ );
+ })(c.Container),
+ Gn = (function (o) {
+ function RankingEntry(t, e) {
+ var i;
+ void 0 === t && (t = 75), void 0 === e && (e = 10), ((i = o.call(this) || this).w = 640), (i.h = t), (i.clampChars = e);
+ var n = {
+ align: "center",
+ fill: 666451,
+ fontSize: t * Math.min(t / 100, 0.5),
+ fontFamily: "Lilita One",
+ dropShadow: !1,
+ dropShadowDistance: 1,
+ maxWidth: 300,
+ };
+ return (
+ (i.index = new sn("", n)),
+ i.addChild(i.index),
+ (i.index._text.anchor.x = 1),
+ (i.name = new sn("", n)),
+ i.addChild(i.name),
+ (i.name._text.anchor.x = 0),
+ (i.score = new sn("", n)),
+ i.addChild(i.score),
+ (i.score._text.anchor.x = 1),
+ (i.avatar = new An(0.85 * t)),
+ i.addChild(i.avatar),
+ i
+ );
+ }
+ return (
+ Ranking_inheritsLoose(RankingEntry, o),
+ (RankingEntry.prototype.update = function (t) {
+ void 0 === t && (t = {}),
+ (t = Object.assign(
+ {
+ name: "",
+ score: 0,
+ index: 0,
+ avatar: "icon_friends",
+ highlight: !1,
+ },
+ t
+ )),
+ (this.name.text = t.name.substr(0, this.clampChars)),
+ (this.score.text = t.score),
+ (this.index.text = t.index),
+ t.loading ||
+ this.avatar.update({
+ image: t.image,
+ }),
+ this.bg && (this.removeChild(this.bg), Ce.clear(this.bg), this.bg.destroy());
+ var e = t.index % 2 ? 13294308 : 11388888;
+ t.highlight && (e = 16773461),
+ (this.bg = Ce.rect({
+ w: this.w,
+ h: this.h,
+ round: 0,
+ color: e,
+ })),
+ this.addChildAt(this.bg, 0);
+ var i = this.w / 2 - 70;
+ (this.index.x = 0 - i), (this.avatar.x = 50 - i), (this.name.x = 100 - i), (this.score.x = 540 - i);
+ }),
+ RankingEntry
+ );
+ })(c.Container);
+ var Bn = (function (i) {
+ var t, e;
+
+ function CoinsTag(t) {
+ var e;
+ void 0 === t && (t = 64),
+ ((e = i.call(this) || this).base = Ce.rectShadow({
+ w: 150,
+ h: 35,
+ color: 5394255,
+ round: 10,
+ shadowDistance: 2,
+ })),
+ e.addChild(e.base);
+ return (
+ (e.coins = new sn("9", {
+ align: "center",
+ fill: 16185078,
+ fontSize: 30,
+ fontFamily: "Lilita One",
+ dropShadow: !0,
+ dropShadowDistance: 1,
+ icon: "icon_coin.png",
+ })),
+ e.addChild(e.coins),
+ e
+ );
+ }
+ return (
+ (e = i),
+ ((t = CoinsTag).prototype = Object.create(e.prototype)),
+ ((t.prototype.constructor = t).__proto__ = e),
+ (CoinsTag.prototype.update = function (t) {
+ this.coins.text = t;
+ }),
+ CoinsTag
+ );
+ })(c.Container);
+ var Nn = (function (i) {
+ var t, e;
+
+ function Menu(t) {
+ var e;
+ return ((e = i.call(this) || this).btnWidth = 150), (e.btnHeight = 100), (e.btns = []), (e.btn = {}), (e.w = 500), (e.h = 180), e;
+ }
+ (e = i), ((t = Menu).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n = Menu.prototype;
+ return (
+ (n.addButton = function (t) {
+ var e = t;
+ if (!t.on) {
+ var i = t.name,
+ n = t.icon,
+ o = t.color,
+ s = t.label,
+ a = t.onTap;
+ ((e = new wn()).name = i),
+ e.setIcon(n),
+ e.setBase(
+ Ce.rectComp(
+ {
+ w: this.btnWidth + 16,
+ h: this.btnHeight + 20,
+ image: "box_border_grey.png",
+ x: 5,
+ y: 6,
+ },
+ {
+ w: this.btnWidth - 8,
+ h: this.btnHeight - 6,
+ color: o,
+ round: 12,
+ }
+ )
+ ),
+ e.setLabel(s, {
+ fontSize: 28,
+ y: this.btnHeight / 2 + 25,
+ fontFamily: "Lilita One",
+ }),
+ (e.onTap = a);
+ }
+ this.addChild(e), this.btns.push(e), (this.btn[e.name] = e), this.organise();
+ }),
+ (n.organise = function () {
+ for (var t = this.btnWidth + 30, e = ((this.btns.length - 1) * t) / 2, i = 0; i < this.btns.length; i++) {
+ var n = this.btns[i];
+ (n.x = t * i - e), (n.y = -12);
+ }
+ }),
+ (n.resize = function (t, e) {
+ (this.w = t), this.organise();
+ }),
+ (n.select = function (t) {
+ var e = this.btns,
+ i = Array.isArray(e),
+ n = 0;
+ for (e = i ? e : e[Symbol.iterator](); ; ) {
+ var o;
+ if (i) {
+ if (n >= e.length) break;
+ o = e[n++];
+ } else {
+ if ((n = e.next()).done) break;
+ o = n.value;
+ }
+ var s = o;
+ s.selected = s.name === t;
+ }
+ }),
+ Menu
+ );
+ })(c.Container);
+
+ function SectionGameover_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ var Xn = (function (i) {
+ function SectionGameover(t) {
+ var e;
+ return ((e = i.call(this, t) || this).app = t), (e.name = "gameover"), e;
+ }
+ SectionGameover_inheritsLoose(SectionGameover, i);
+ var t = SectionGameover.prototype;
+ return (
+ (t.onBuild = function () {
+ var t = this;
+ i.prototype.onBuild.call(this), (this.bg = new On()), this.view.addChild(this.bg);
+ (this.base = Ce.rectComp(
+ {
+ w: 690,
+ h: 1e3,
+ color: 15658734,
+ round: 16,
+ },
+ {
+ w: 712,
+ h: 1024,
+ image: "box_border_grey.png",
+ x: 5,
+ y: 6,
+ }
+ )),
+ this.view.addChild(this.base),
+ (this.menu = new Nn(this.app)),
+ this.view.addChild(this.menu),
+ (this.content = new c.Container()),
+ this.view.addChild(this.content),
+ this.menu.addButton({
+ name: "back",
+ icon: "icon_white_house.png",
+ label: this.app.strings.get("menu"),
+ color: 3684408,
+ onTap: function () {
+ return t.goToTitle();
+ },
+ });
+ var e = new wn({
+ name: "play",
+ });
+ e.setBase(
+ Ce.rectComp(
+ {
+ w: 346,
+ h: 120,
+ image: "box_border_grey.png",
+ x: 5,
+ y: 6,
+ },
+ {
+ w: 322,
+ h: 94,
+ color: 4298538,
+ round: 12,
+ }
+ )
+ ),
+ e.setLabel(this.app.strings.upper("play"), {
+ fontFamily: "Lilita One",
+ }),
+ (e.onTap = function () {
+ return t.playAgain();
+ }),
+ this.menu.addButton(e),
+ (this.menu.btn.back.x = -270),
+ this.menu.btn.boosts && (this.menu.btn.boosts.x = -90),
+ (this.menu.btn.play.x = 180),
+ (this.menu.btn.play.y = -12),
+ (this.jake = new Fn("assets/placeholder/jake.png")),
+ (this.jake.x = -180),
+ (this.jake.y = 60),
+ this.content.addChild(this.jake),
+ (this.scoreboard = new Ln()),
+ this.content.addChild(this.scoreboard),
+ (this.scoreboard.x = 130),
+ (this.scoreboard.y = 130),
+ (this.ranking = new Dn(50, this.app.config.maxNicknameChars)),
+ this.content.addChild(this.ranking),
+ (this.ranking.y = 300),
+ (this.coins = new Bn()),
+ this.content.addChild(this.coins),
+ (this.coins.x = this.scoreboard.x),
+ (this.coins.y = -80);
+ }),
+ (t.createBox = function (t, e, i, n) {}),
+ (t.onOpen = function () {
+ i.prototype.onOpen.call(this),
+ (this._actionTaken = !1),
+ this.ranking.update(this.app.user.name, this.app.game.stats.score),
+ this.coins.update(this.app.user.coins),
+ this.scoreboard.update({
+ score: this.app.game.stats.score,
+ coins: this.app.game.stats.coins,
+ title: this.app.strings.get("score"),
+ }),
+ (this.menu.btn.play.key = 32);
+ }),
+ (t.onClose = function () {
+ i.prototype.onClose.call(this), (this.menu.btn.play.key = null);
+ }),
+ (t.goToTitle = function () {
+ this._actionTaken || ((this._actionTaken = !0), this.app.nav.goToTitle());
+ }),
+ (t.playAgain = function () {
+ dataLayer.push({
+ event: "ga_event",
+ ga_category: "Gamepage",
+ ga_action: "Start",
+ ga_label: window.productTitle,
+ ga_noninteraction: false,
+ });
+
+ this._actionTaken || ((this._actionTaken = !0), this.app.nav.playAgain());
+ }),
+ (t.onResize = function () {
+ i.prototype.onResize.call(this),
+ this.bg.resize(this.w, this.h),
+ (this.menu.x = this.w / 2),
+ (this.menu.y = this.h - this.menu.h / 2),
+ this.base && ((this.base.x = 0.5 * this.w), (this.base.y = 0.5 * (this.h - this.menu.h))),
+ this.title && ((this.title.x = this.w / 2), (this.title.y = 150)),
+ (this.content.x = this.w / 2),
+ (this.content.y = 240);
+ }),
+ SectionGameover
+ );
+ })(vn);
+ c.Container;
+ var Yn = (function (i) {
+ var t, e;
+
+ function SectionTopRun(t) {
+ var e;
+ return ((e = i.call(this) || this).app = t), (e.name = "toprun"), e;
+ }
+ (e = i), ((t = SectionTopRun).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n = SectionTopRun.prototype;
+ return (
+ (n.onBuild = function () {
+ var t = this;
+ i.prototype.onBuild.call(this), (this.bg = new On()), this.view.addChild(this.bg);
+ (this.base = Ce.rectComp(
+ {
+ w: 690,
+ h: 1e3,
+ color: 15658734,
+ round: 16,
+ },
+ {
+ w: 712,
+ h: 1024,
+ image: "box_border_grey.png",
+ x: 5,
+ y: 6,
+ }
+ )),
+ this.view.addChild(this.base),
+ (this.menu = new Nn(this.app)),
+ this.view.addChild(this.menu),
+ this.menu.addButton({
+ name: "back",
+ icon: "icon_white_house.png",
+ label: this.app.strings.get("menu"),
+ color: 3684408,
+ onTap: function () {
+ return t.app.nav.goToTitle();
+ },
+ }),
+ (this.ranking = new Dn(70, this.app.config.maxNicknameChars)),
+ this.base.addChild(this.ranking),
+ (this.ranking.y = -310),
+ (this.title = new sn(this.app.strings.get("highscores"), {
+ align: "center",
+ fill: 19072,
+ fontSize: 70,
+ fontFamily: "Titan One",
+ dropShadow: !1,
+ dropShadowDistance: 2,
+ anchor: 0.5,
+ })),
+ this.base.addChild(this.title),
+ (this.title.y = -420);
+ }),
+ (n.onOpen = function () {
+ i.prototype.onOpen.call(this), this.ranking.update(this.app.user.name, this.app.user.score);
+ }),
+ (n.onResize = function () {
+ i.prototype.onResize.call(this), this.bg.resize(this.w, this.h), (this.menu.x = this.w / 2), (this.menu.y = this.h - this.menu.h / 2), (this.base.x = 0.5 * this.w), (this.base.y = 0.5 * (this.h - this.menu.h));
+ }),
+ SectionTopRun
+ );
+ })(vn);
+ var Hn = (function (i) {
+ var t, e;
+
+ function SectionPause(t) {
+ var e;
+ return ((e = i.call(this) || this).app = t), (e.name = "pause"), e;
+ }
+ (e = i), ((t = SectionPause).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var n = SectionPause.prototype;
+ return (
+ (n.onBuild = function () {
+ var t = this;
+ i.prototype.onBuild.call(this),
+ (this.bg = new On()),
+ this.view.addChild(this.bg),
+ (this.menu = new Nn(this.app)),
+ this.view.addChild(this.menu),
+ this.menu.addButton({
+ name: "back",
+ icon: "icon_white_house.png",
+ label: this.app.strings.get("menu"),
+ color: 3684408,
+ onTap: function () {
+ t._actionTaken || ((t._actionTaken = !0), nn.a.sendCustomMessage("game", "roundCancel", {}), t.app.nav.goToTitle());
+ },
+ });
+ var e = new wn({
+ name: "resume",
+ });
+ e.setBase(
+ Ce.rectComp(
+ {
+ w: 346,
+ h: 120,
+ image: "box_border_grey.png",
+ x: 5,
+ y: 6,
+ },
+ {
+ w: 322,
+ h: 94,
+ color: 4298538,
+ round: 12,
+ }
+ )
+ ),
+ e.setLabel(this.app.strings.upper("resume"), {
+ fontFamily: "Lilita One",
+ }),
+ (e.onTap = function () {
+ t.app.sections.close(), t.app.game.resume(3);
+ }),
+ this.menu.addButton(e),
+ (this.menu.btn.back.x = -270),
+ (this.menu.btn.resume.x = 180),
+ (this.menu.btn.resume.y = -12),
+ (this.title = new sn(this.app.strings.upper("pause"), {
+ align: "center",
+ fill: 16777215,
+ fontSize: 70,
+ fontFamily: "Titan One",
+ dropShadow: !0,
+ dropShadowDistance: 2,
+ anchor: 0.5,
+ })),
+ this.view.addChild(this.title);
+ }),
+ (n.onOpen = function () {
+ i.prototype.onOpen.call(this), (this._actionTaken = !1);
+ }),
+ (n.onResize = function () {
+ i.prototype.onResize.call(this),
+ this.bg.resize(this.w, this.h),
+ (this.menu.x = this.w / 2),
+ (this.menu.y = this.h - this.menu.h / 2),
+ this.base && ((this.base.x = 0.5 * this.w), (this.base.y = 0.5 * (this.h - this.menu.h))),
+ this.title && ((this.title.x = this.w / 2), (this.title.y = 150)),
+ (this.title.x = this.w / 2),
+ (this.title.y = this.h / 2);
+ }),
+ SectionPause
+ );
+ })(vn);
+
+ function SectionSettings_defineProperties(t, e) {
+ for (var i = 0; i < e.length; i++) {
+ var n = e[i];
+ (n.enumerable = n.enumerable || !1), (n.configurable = !0), "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n);
+ }
+ }
+
+ function SectionSettings_assertThisInitialized(t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ }
+
+ function SectionSettings_inheritsLoose(t, e) {
+ (t.prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ }
+ var Un = (function (i) {
+ function SectionSettings(t) {
+ var e;
+ return ((e = i.call(this) || this).name = "settings"), (e.app = t), e;
+ }
+ SectionSettings_inheritsLoose(SectionSettings, i);
+ var t = SectionSettings.prototype;
+ return (
+ (t.onBuild = function () {
+ var t = this;
+ (this.bg = new On(this.app.color)), this.view.addChild(this.bg);
+ (this.base = Ce.rectComp(
+ {
+ w: 690,
+ h: 1e3,
+ color: 15658734,
+ round: 16,
+ },
+ {
+ w: 712,
+ h: 1024,
+ image: "box_border_grey.png",
+ x: 5,
+ y: 6,
+ }
+ )),
+ this.view.addChild(this.base),
+ (this.title = new sn(this.app.strings.get("settings"), {
+ align: "center",
+ fill: 19072,
+ fontSize: 70,
+ fontFamily: "Titan One",
+ dropShadow: !1,
+ dropShadowDistance: 2,
+ anchor: 0.5,
+ })),
+ this.base.addChild(this.title),
+ (this.title.y = -420),
+ (this.btnClose = new wn()),
+ (this.btnClose.x = -325),
+ (this.btnClose.y = -480),
+ this.base.addChild(this.btnClose),
+ this.btnClose.setBase("btn_close.png"),
+ (this.btnClose.onTap = function () {
+ return t.app.sections.open("title");
+ }),
+ (this.version = new sn("v0.3.9", {
+ align: "right",
+ fill: 3836863,
+ fontSize: 18,
+ fontFamily: "Titan One",
+ anchor: 1,
+ })),
+ this.base.addChild(this.version),
+ (this.version.alpha = 0.5),
+ (this.version.x = 335),
+ (this.version.y = 494),
+ this.updateEntries();
+ }),
+ (t.onOpen = function () {
+ i.prototype.onOpen.call(this);
+ }),
+ (t.onClose = function () {
+ i.prototype.onClose.call(this);
+ }),
+ (t.onResize = function () {
+ i.prototype.onResize.call(this), this.bg.resize(this.w, this.h), (this.base.x = 0.5 * this.w), (this.base.y = 0.5 * this.h);
+ }),
+ (t.buildEntries = function () {
+ var e = this;
+ if (!this._entriesBuilt) {
+ this._entriesBuilt = !0;
+ for (
+ var t = [
+ {
+ name: "nickname",
+ type: "input",
+ value: this.app.user.name,
+ icon: "icon_user.png",
+ title: this.app.strings.get("nickname"),
+ description: this.app.strings.get("nickname_prompt"),
+ onChange: function (t) {
+ (e.app.user.name = t), e.app.user.save();
+ },
+ },
+ {
+ name: "sound",
+ type: "toggle",
+ value: this.app.settings.sound,
+ icon: "icon_sound.png",
+ title: this.app.strings.get("sound"),
+ subtitleTrue: this.app.strings.get("on"),
+ subtitleFalse: this.app.strings.get("off"),
+ onChange: function (t) {
+ (e.app.settings.sound = t), e.app.settings.save(), e.app.sfx.volume(t ? B.volume : 0);
+ },
+ },
+ {
+ name: "info",
+ type: "link",
+ icon: "icon_info.png",
+ title: this.app.strings.get("privacy_policy"),
+ link: this.app.strings.get("privacy_policy_link"),
+ },
+ ],
+ i = 0;
+ i < t.length;
+ i++
+ ) {
+ var n = t[i],
+ o = new Vn(this.app, n);
+ this.base.addChild(o), (o.y = i * o.h - 250), (this[o.name] = o);
+ }
+ }
+ }),
+ (t.updateEntries = function () {
+ this.buildEntries(), (this.nickname.value = this.app.user.name), (this.sound.value = this.app.settings.sound);
+ }),
+ SectionSettings
+ );
+ })(vn),
+ Vn = (function (o) {
+ function Entry(t, e) {
+ var i;
+ void 0 === e && (e = {}), ((i = o.call(this) || this).app = t);
+ var n = Object.assign(
+ {},
+ {
+ name: "entry",
+ type: "toggle",
+ value: !0,
+ icon: "icon_white_missions.png",
+ title: "Title",
+ subtitleTrue: "",
+ subtitleFalse: "",
+ description: "",
+ onChange: function (t) {
+ return t;
+ },
+ },
+ e
+ );
+ return (
+ (i.w = 550),
+ (i.h = 130),
+ (i.opts = n),
+ (i.name = n.name),
+ (i.type = n.type),
+ (i.bg = new c.Graphics()),
+ i.bg.beginFill(16711680, 1),
+ i.bg.drawRect(-i.w / 2, -i.h / 2, i.w, i.h),
+ i.addChild(i.bg),
+ (i.bg.alpha = 0),
+ (i.bg.interactive = !0),
+ i.bg.on("pointertap", i.onTap.bind(SectionSettings_assertThisInitialized(i)), SectionSettings_assertThisInitialized(i)),
+ (i.btn = new wn()),
+ i.btn.setIcon(n.icon),
+ i.btn.setBase(
+ Ce.rectComp(
+ {
+ w: 116,
+ h: 118,
+ image: "box_border_grey_small.png",
+ x: 1,
+ y: 1,
+ },
+ {
+ w: 100,
+ h: 100,
+ color: 3574206,
+ round: 6,
+ }
+ )
+ ),
+ (i.btn.onTap = i.onTap.bind(SectionSettings_assertThisInitialized(i))),
+ i.addChild(i.btn),
+ (i.btn.x = -i.w / 2 + 60),
+ (i.title = new sn(n.title, {
+ align: "left",
+ fill: 19072,
+ fontSize: 40,
+ fontFamily: "Titan One",
+ anchor: 0,
+ })),
+ i.addChild(i.title),
+ (i.title.x = i.btn.x + 80),
+ (i.title.y = n.value ? -35 : -20),
+ (i.subtitle = new sn(n.subtitleTrue, {
+ align: "left",
+ fill: 3836863,
+ fontSize: 30,
+ fontFamily: "Titan One",
+ anchor: 0,
+ })),
+ i.addChild(i.subtitle),
+ (i.subtitle.x = i.title.x),
+ (i.subtitle.y = i.title.y + 40),
+ (i.subtitle.description = n.description),
+ i.subtitle.on("change", function (t) {
+ return (i.value = t);
+ }),
+ (i.diagonal = c.Sprite.from("diagonal.png")),
+ i.diagonal.anchor.set(0.5),
+ i.btn.addChild(i.diagonal),
+ (i.diagonal.visible = !1),
+ (i.value = n.value),
+ i
+ );
+ }
+ SectionSettings_inheritsLoose(Entry, o);
+ var t,
+ e,
+ i,
+ n = Entry.prototype;
+ return (
+ (n.onTap = function () {
+ var e = this;
+ "toggle" === this.type && this.toggle(),
+ "input" === this.type &&
+ this.app.prompt.open(this.subtitle.description, this.subtitle.text, function (t) {
+ t && ((e.subtitle.text = t), (e.value = t));
+ }),
+ "link" === this.type && window.open(this.opts.link, "_blank");
+ }),
+ (n.toggle = function () {
+ this.value = !this.value;
+ }),
+ (n.update = function () {
+ var t = this._value;
+ this.diagonal.visible = !t;
+ var e = t ? this.opts.subtitleTrue : this.opts.subtitleFalse,
+ i = "string" == typeof t ? t : e;
+ (this.subtitle.text = i), (this.title.y = i ? -35 : -20), (this.subtitle.y = this.title.y + 40);
+ }),
+ (t = Entry),
+ (e = [
+ {
+ key: "value",
+ get: function () {
+ return this._value;
+ },
+ set: function (t) {
+ this._value !== t && ((this._value = t), this.opts.onChange(t), this.update());
+ },
+ },
+ ]) && SectionSettings_defineProperties(t.prototype, e),
+ i && SectionSettings_defineProperties(t, i),
+ Entry
+ );
+ })(c.Container),
+ qn = (function () {
+ function Navigation(t) {
+ (this.app = t), this.uiLoaded;
+ }
+ var t = Navigation.prototype;
+ return (
+ (t.onAppReady = function () {
+ this._initialised ||
+ ((this._initialised = !0),
+ this.app.sections.addSub(new En(this.app)),
+ this.app.sections.addSub(new In(this.app)),
+ this.app.sections.addSub(new Xn(this.app)),
+ this.app.sections.addSub(new Yn(this.app)),
+ this.app.sections.addSub(new Hn(this.app)),
+ this.app.sections.addSub(new Un(this.app)),
+ this.app.resources.isLoaded("ui") && (this.app.size.update(), B.fastplay || this.app.sections.open(B.section)));
+ }),
+ (t.onLoadComplete = function (t) {
+ B.fastplay || ("ui" === t && this.app._ready && (this.app.size.update(), this.app.sections.open(B.section)));
+ }),
+ (t.playGame = function () {
+ var t = this;
+ this.app.sections.close(),
+ nn.a.hangout.initHighscoreSession().then(function () {
+ t.app.startGame();
+ });
+ }),
+ (t.goToTitle = function () {
+ var t = this;
+ this.app.config.commercials
+ ? (this.app.sections.close(),
+ this.app.suspend(),
+ nn.a.SDK.commercialBreak().then(function () {
+ return t._goToTitle();
+ }))
+ : this._goToTitle();
+ }),
+ (t._goToTitle = function () {
+ var t = this;
+ this.app.game.state !== pn.IDLE && this.app.game.idle(),
+ setTimeout(function () {
+ t.app.sections.close(), t.app.screenManager.gotoScreenByID("title"), t.app.sections.open("title");
+ }, 30);
+ }),
+ (t.playAgain = function () {
+ var t = this;
+ this.app.sections.close(),
+ this.app.config.commercials
+ ? (this.app.suspend(),
+ nn.a.SDK.commercialBreak().then(function () {
+ return t._playAgain();
+ }))
+ : this._playAgain();
+ }),
+ (t._playAgain = function () {
+ var t = this;
+ this.app.sections.close(),
+ nn.a.hangout.initHighscoreSession().then(function () {
+ t.app.resume(), t.app.game.idle(), t.app.sfx.unmute(), t.app.game.runWithIntro();
+ });
+ }),
+ Navigation
+ );
+ })(),
+ Wn = i(192),
+ Zn = (function () {
+ function Store(t, e) {
+ var i = this;
+ (this.id = t), (this.cache = Object.assign({}, e)), (this.data = Object.assign({}, e)), (this.storage = new Wn.a(t)), (this.onChange = new l.a()), (this._changes = {});
+ var n = function (e) {
+ Object.defineProperty(i, e, {
+ get: function () {
+ return i.get(e);
+ },
+ set: function (t) {
+ return i.set(e, t);
+ },
+ });
+ };
+ for (var o in this.data) n(o);
+ this.load();
+ }
+ var t = Store.prototype;
+ return (
+ (t.get = function (t) {
+ return this.data[t];
+ }),
+ (t.set = function (t, e) {
+ (this.data[t] = e),
+ this.cache[t] !== this.data[t] &&
+ ((this._lastChange = {
+ field: t,
+ from: this.cache[t],
+ to: this[t],
+ }),
+ (this._changes[t] = {
+ from: this.cache[t],
+ to: this[t],
+ }),
+ this.onChange.dispatch(t, this[t], this.cache[t]),
+ (this.cache[t] = this.data[t]));
+ }),
+ (t.update = function () {
+ for (var t in this.cache) this.set(t, this.data[t]);
+ }),
+ (t.load = function () {
+ var t = this.storage.getObject(this.id);
+ t && (Object.assign(this.data, t), this.update());
+ }),
+ (t.save = function () {
+ this.update(), this.storage.storeObject(this.id, this.data);
+ }),
+ (t.lastChange = function (t) {
+ return this._changes[t] || null;
+ }),
+ Store
+ );
+ })();
+
+ function asyncGeneratorStep(t, e, i, n, o, s, a) {
+ try {
+ var r = t[s](a),
+ h = r.value;
+ } catch (t) {
+ return void i(t);
+ }
+ r.done ? e(h) : Promise.resolve(h).then(n, o);
+ }
+ var Kn = [
+ {
+ name: "preload",
+ assets: ["preload"],
+ },
+ {
+ name: "idle",
+ assets: ["idle", "chunks_idle"],
+ },
+ {
+ name: "ui",
+ assets: ["ui"],
+ },
+ {
+ name: "game",
+ assets: ["game", "chunks_game"],
+ },
+ ],
+ Jn = (function () {
+ function Resources(t, e) {
+ (this.app = t), (this.config = e || Kn), (this.level = -1), (this.levelLoading = -1);
+ }
+ var t = Resources.prototype;
+ return (
+ (t.init = function () {
+ (this.app.resourceManager.version = "low"), (this.onLoadStart = this.app.addSignal("onLoadStart")), (this.onLoadComplete = this.app.addSignal("onLoadComplete"));
+ }),
+ (t.load = (function () {
+ var s,
+ e =
+ ((s = regeneratorRuntime.mark(function _callee(e) {
+ var i, n, o, s;
+ return regeneratorRuntime.wrap(
+ function (t) {
+ for (;;)
+ switch ((t.prev = t.next)) {
+ case 0:
+ if ((i = this.getLevel(e)) <= this.levelLoading) return t.abrupt("return");
+ t.next = 3;
+ break;
+ case 3:
+ if (-1 == i) throw new Error("Invalid level ref: " + e);
+ t.next = 5;
+ break;
+ case 5:
+ for (this.levelLoading = i, this.onLoadStart.dispatch(this.config[i].name, i), n = [], o = 0; o <= i; o++) (s = this.config[o]), (n = n.concat(s.assets));
+ return (t.next = 11), this.app.screenManager._loadAssets(n);
+ case 11:
+ (this.level = i), (this.levelLoading = -1), this.onLoadComplete.dispatch(this.config[i].name, i);
+ case 14:
+ case "end":
+ return t.stop();
+ }
+ },
+ _callee,
+ this
+ );
+ })),
+ function () {
+ var t = this,
+ o = arguments;
+ return new Promise(function (e, i) {
+ var n = s.apply(t, o);
+
+ function _next(t) {
+ asyncGeneratorStep(n, e, i, _next, _throw, "next", t);
+ }
+
+ function _throw(t) {
+ asyncGeneratorStep(n, e, i, _next, _throw, "throw", t);
+ }
+ _next(void 0);
+ });
+ });
+ return function (t) {
+ return e.apply(this, arguments);
+ };
+ })()),
+ (t.getLevel = function (t) {
+ switch (typeof t) {
+ case "number":
+ return t;
+ case "string":
+ return this.levelByName(t);
+ default:
+ return this.config.indexOf(t);
+ }
+ }),
+ (t.levelByName = function (t) {
+ return this.config
+ .map(function (t) {
+ return t.name;
+ })
+ .indexOf(t);
+ }),
+ (t.groupByName = function (t) {
+ var e = this.levelByName(t);
+ return this.config[e];
+ }),
+ (t.isLoaded = function (t) {
+ return this.getLevel(t) <= this.level;
+ }),
+ Resources
+ );
+ })(),
+ Qn = i(198),
+ $n = i(195),
+ to = i(196),
+ eo = i(132),
+ io = ["Good", "Fabulous", "Grumpy", "Normal", "Zealous", "Brainy", "Awesome", "Cute", "Simple", "Pretty", "Super", "Hyper", "Mega", "Wonder", "Master", "Fast", "Quick", "Giant", "Mega"],
+ no = ["Toaster", "Machine", "Runner", "Beast", "Genius", "Alien", "Zen", "Guy", "Player", "Llama", "Rider", "Bolt", "Monster", "Bird", "Cat"],
+ oo = (function () {
+ function NicknameGen() {}
+ return (
+ (NicknameGen.random = function () {
+ return this.pick.apply(this, io) + this.pick.apply(this, no);
+ }),
+ (NicknameGen.pick = function () {
+ for (var t = arguments.length, e = new Array(t), i = 0; i < t; i++) e[i] = arguments[i];
+ return e[Math.floor(Math.random() * e.length)];
+ }),
+ NicknameGen
+ );
+ })(),
+ so = (function () {
+ function Prompt(t, e) {
+ void 0 === e && (e = 10), (this.app = t), (this.w = 400), (this.h = 300), (this.maxChars = e), (this.useDefault = this.app.config.useDefaultPrompt);
+ }
+ var t = Prompt.prototype;
+ return (
+ (t.build = function () {
+ var t = this;
+ if (!this.element) {
+ var e = document.createElement("div");
+ (e.style.position = "absolute"),
+ (e.style.left = 0),
+ (e.style.top = 0),
+ (e.style.right = 0),
+ (e.style.bottom = 0),
+ (e.style.width = "100%"),
+ (e.style.height = "100%"),
+ (e.style.backgroundColor = "rgba(0, 0, 0, 0.5)"),
+ (e.style.zIndex = 99999);
+ var i = document.createElement("div");
+ (i.style.width = this.w + "px"),
+ (i.style.height = this.h + "px"),
+ (i.style.position = "absolute"),
+ (i.style.marginLeft = "50%"),
+ (i.style.left = -this.w / 2 + "px"),
+ (i.style.top = "20%"),
+ (i.style.backgroundImage = 'url("assets/placeholder/box_base.png")'),
+ (i.style.backgroundPosition = "center"),
+ (i.style.backgroundRepeat = "no-repeat"),
+ (i.style.backgroundSize = "contain"),
+ (i.style.fontFamily = "Lilita One"),
+ (i.style.textAlign = "center"),
+ (i.style.color = "#004a80"),
+ (i.style.display = "block"),
+ (i.style.overflow = "hidden"),
+ e.appendChild(i);
+ var n = document.createElement("div");
+ (n.style.fontSize = "2em"), (n.style.width = "100%"), (n.style.marginTop = "20%"), (n.style.textAlign = "center"), i.appendChild(n);
+ var o = document.createElement("input");
+ (o.style.fontSize = "1.5em"),
+ (o.type = "text"),
+ (o.maxLength = this.maxChars),
+ (o.style.width = "80%"),
+ (o.style.height = "30pt"),
+ (o.style.textAlign = "center"),
+ (o.style.fontFamily = "Lilita One"),
+ (o.style.color = "#3a8bbf"),
+ (o.style.margin = "5px"),
+ (o.style.backgroundColor = "#FFFFFF"),
+ (o.style.border = 0),
+ i.appendChild(o);
+ var s = document.createElement("button");
+ (s.innerText = this.app.strings.get("cancel")),
+ (s.onclick = function () {
+ return t.onCancel();
+ }),
+ (s.style.fontSize = "1em"),
+ (s.style.width = "120px"),
+ (s.style.height = "40px"),
+ (s.style.textAlign = "center"),
+ (s.style.fontFamily = "Lilita One"),
+ (s.style.color = "#FFFFFF"),
+ (s.style.margin = "10px"),
+ (s.style.backgroundColor = "#c93d48"),
+ (s.style.border = 0),
+ (s.style.cursor = "pointer"),
+ (s.style.borderRadius = "6px"),
+ i.appendChild(s);
+ var a = document.createElement("button");
+ (a.innerText = this.app.strings.get("ok")),
+ (a.onclick = function () {
+ return t.onOk();
+ }),
+ (a.style.fontSize = "1em"),
+ (a.style.width = "120px"),
+ (a.style.height = "40px"),
+ (a.style.textAlign = "center"),
+ (a.style.fontFamily = "Lilita One"),
+ (a.style.color = "#FFFFFF"),
+ (a.style.backgroundColor = "#3689be"),
+ (a.style.margin = "10px"),
+ (a.style.border = 0),
+ (a.style.cursor = "pointer"),
+ (a.style.borderRadius = "6px"),
+ i.appendChild(a),
+ (this.title = n),
+ (this.input = o),
+ (this.btnOk = a),
+ (this.btnCancel = s),
+ (this.element = e);
+ }
+ }),
+ (t.open = function (t, e, i) {
+ if (!this.opened) {
+ if (((this.opened = !0), (this.callback = i), this.useDefault)) {
+ var n = window.prompt(t, e);
+ return this.callback && this.callback(n), void (this.opened = !1);
+ }
+ this._onKeyDownBind || (this._onKeyDownBind = this.onKeyUp.bind(this)),
+ document.addEventListener("keyup", this._onKeyDownBind),
+ this.app.suspend(),
+ this.build(),
+ (this.title.innerText = t),
+ (this.input.value = e),
+ document.body.appendChild(this.element),
+ this.select();
+ }
+ }),
+ (t.close = function () {
+ this.opened && ((this.opened = !1), document.removeEventListener("keyup", this._onKeyDownBind), this.input.blur(), document.body.removeChild(this.element), this.app.resume());
+ }),
+ (t.onKeyUp = function (t) {
+ "Enter" != t.code || t.repeat || this.onOk();
+ }),
+ (t.onOk = function () {
+ this.close(), this.callback && this.callback(this.input.value);
+ }),
+ (t.onCancel = function () {
+ this.close(), this.callback && this.callback();
+ }),
+ (t.select = function () {
+ this.input.focus(), this.input.select && this.input.select(), this.input.setSelectionRange && this.input.setSelectionRange(0, this.input.value.length);
+ }),
+ Prompt
+ );
+ })();
+
+ function Application_asyncGeneratorStep(t, e, i, n, o, s, a) {
+ try {
+ var r = t[s](a),
+ h = r.value;
+ } catch (t) {
+ return void i(t);
+ }
+ r.done ? e(h) : Promise.resolve(h).then(n, o);
+ }
+
+ function Application_asyncToGenerator(s) {
+ return function () {
+ var t = this,
+ o = arguments;
+ return new Promise(function (e, i) {
+ var n = s.apply(t, o);
+
+ function _next(t) {
+ Application_asyncGeneratorStep(n, e, i, _next, _throw, "next", t);
+ }
+
+ function _throw(t) {
+ Application_asyncGeneratorStep(n, e, i, _next, _throw, "throw", t);
+ }
+ _next(void 0);
+ });
+ };
+ }
+ var ao = "assets";
+
+ function pathJoin() {
+ for (var t = arguments.length, e = new Array(t), i = 0; i < t; i++) e[i] = arguments[i];
+ return e.join("/");
+ }
+
+ function prepareManifest(t, e) {
+ !(function (t, e) {
+ for (var i in t)
+ for (var n in t[i])
+ for (var o in t[i][n])
+ for (var s in t[i][n][o]) {
+ var a = t[i][n][o][s];
+ if ("string" == typeof a) {
+ var r = pathJoin(e, a);
+ t[i][n][o][s] = r;
+ }
+ }
+ })(t, ao);
+ var i = e && e.config ? e.config.lang : "en",
+ n = {
+ default: ao + "/data/strings_en.json",
+ },
+ o = {
+ default: ao + "/data/strings_" + i + ".json",
+ };
+ return (
+ (t.idle.json["data/strings_en"] = n),
+ (t.idle.json["data/strings_" + i] = o),
+ e.bundle &&
+ (!(function (t) {
+ var e = t.meta.path;
+ for (var i in t)
+ if ("meta" !== i)
+ for (var n in t[i])
+ for (var o in t[i][n])
+ for (var s in t[i][n][o]) {
+ var a = pathJoin(e, t[i][n][o][s]).replace("assets/", "");
+ t[i][n][o][s] = a;
+ }
+ })(e.bundle),
+ (function merge(t, e) {
+ for (var i in e) {
+ var n = typeof t[i],
+ o = typeof e[i];
+ "object" === n && "object" === o ? merge(t[i], e[i]) : (t[i] = "object" === o ? JSON.parse(JSON.stringify(e[i])) : e[i]);
+ }
+ })(t, e.bundle)),
+ t
+ );
+ }
+ B.vertp && (c.settings.PRECISION_VERTEX = B.vertp), B.fragp && (c.settings.PRECISION_VERTEX = B.fragp);
+ var ro = (function (s) {
+ var t, e;
+
+ function Application(t) {
+ var e;
+ void 0 === t && (t = {}),
+ B.override({
+ env: t.config.env,
+ mobile: r.a.instance.isMobile || r.a.instance.isTouch,
+ }),
+ B.override(t.config);
+ var i,
+ n = {
+ manifest: prepareManifest(eo, t),
+ orientationMode: a.a.orientationModes.BOTH,
+ screenManagerOptions: {
+ defaultTransition: new h.a(),
+ },
+ middlewares: [((i = B.workers), i ? Object($n.a)(1 === i) : Qn.a)],
+ version: B.monitor || B.debug,
+ fps: B.monitor || B.debug,
+ upload: !1,
+ antialias: !1,
+ transparent: !1,
+ loadingScreenClass: xn,
+ };
+ ((e = s.call(this, n) || this).resourceManager.middlewaresPre = [to.a]), (e.config = Object.assign({}, t.config)), (e.bundle = Object.assign({}, t.bundle));
+ var o = e.bundle.meta.color;
+ return (
+ (e.color = "string" == typeof o ? c.utils.string2hex(o) : o),
+ (e.resourceManager.version = "low"),
+ (e.resourceManager.getLoader = function () {
+ var e = new c.Loader();
+ return (
+ this.middlewaresPre.forEach(function (t) {
+ return e.pre(t());
+ }),
+ this.middlewares.forEach(function (t) {
+ return e.use(t());
+ }),
+ e
+ );
+ }),
+ (e.crashed = !1),
+ window.addEventListener("error", function (t) {
+ e.crash(t.error.message);
+ }),
+ c.Ticker.shared.stop(),
+ c.Ticker._system.stop(),
+ d.a.instance.remove(
+ e.update,
+ (function (t) {
+ if (void 0 === t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return t;
+ })(e)
+ ),
+ B.ticker ? e.runWithTicker() : (d.a.instance.stop(), e.runWithAnimFrame()),
+ e
+ );
+ }
+ (e = s), ((t = Application).prototype = Object.create(e.prototype)), ((t.prototype.constructor = t).__proto__ = e);
+ var i = Application.prototype;
+ return (
+ (i.crash = function () {
+ (this.crashed = !0), d.a.instance.stop();
+ for (var t = arguments.length, e = new Array(t), i = 0; i < t; i++) e[i] = arguments[i];
+ throw new Error("CRASH! " + e.join(" "));
+ }),
+ (i.getFbxLoader = function () {}),
+ (i.init = function (t) {
+ (this.container = t),
+ this.addSignal("onAppReady", this.onReady),
+ this.addSystem(
+ "settings",
+ new Zn("settings", {
+ sound: !0,
+ })
+ ),
+ this.addSystem(
+ "user",
+ new Zn("user", {
+ score: 0,
+ coins: 0,
+ keys: 0,
+ sprays: 0,
+ hoverboards: 0,
+ character: "jake",
+ outfit: "default",
+ board: "default",
+ name: "",
+ nameSet: !1,
+ tutorial: !0,
+ })
+ ),
+ this.user.name || ((this.user.name = oo.random()), this.user.save()),
+ (this.sfx = new gn(0 === B.volume)),
+ this.sfx.setup(eo.audio.audio, ao),
+ this.sfx.volume(this.settings.sound ? B.volume : 0),
+ this.addSystem("resources", new Jn(this)),
+ this.addSystem("nav", new qn(this)),
+ this.addSystem("event", new Sn(this)),
+ this.addSystem("message", new zn(this)),
+ this.addSystem("size", new Tn(this)),
+ this.addSystem("strings", new Pn(this)),
+ this.addSystem("prompt", new so(this, this.config.maxNicknameChars)),
+ B.debug && this.addSystem("debug", new Mn(this)),
+ nn.a.hangout.setDebug(this.config.pokiSdkDebug),
+ nn.a.hangout.getLobbyId(),
+ this.addScreen("loading", new xn(this, this.color)),
+ this.preload();
+ }),
+ (i.show = function () {
+ this.container.appendChild(this.view), (this.view.style.position = "absolute"), (this.view.style.top = 0), (this.view.style.left = 0), this.size.update();
+ }),
+ (i.preload = (function () {
+ var t = Application_asyncToGenerator(
+ regeneratorRuntime.mark(function _callee() {
+ return regeneratorRuntime.wrap(
+ function (t) {
+ for (;;)
+ switch ((t.prev = t.next)) {
+ case 0:
+ return nn.a.sendCustomMessage("game", "loaderStart", {}), (t.next = 3), this.resources.load("preload");
+ case 3:
+ this.loadingScreen.build(), this.show(), this.load();
+ case 6:
+ case "end":
+ return t.stop();
+ }
+ },
+ _callee,
+ this
+ );
+ })
+ );
+ return function () {
+ return t.apply(this, arguments);
+ };
+ })()),
+ (i.load = (function () {
+ var t = Application_asyncToGenerator(
+ regeneratorRuntime.mark(function _callee2() {
+ return regeneratorRuntime.wrap(
+ function (t) {
+ for (;;)
+ switch ((t.prev = t.next)) {
+ case 0:
+ if (B.fastplay) return (this.shouldStartGame = !0), nn.a.sendCustomMessage("game", "loaderEnd", {}), nn.a.sendCustomMessage("mainMenu", "secondLoaderStart", {}), (t.next = 6), this.resources.load("game");
+ t.next = 11;
+ break;
+ case 6:
+ this.ready(), (this.gameLoaded = !0), nn.a.SDK.gameLoadingFinished(), (t.next = 24);
+ break;
+ case 11:
+ if (B.loadAll) return (t.next = 14), this.resources.load("game");
+ t.next = 16;
+ break;
+ case 14:
+ t.next = 18;
+ break;
+ case 16:
+ return (t.next = 18), this.resources.load("idle");
+ case 18:
+ return nn.a.sendCustomMessage("game", "loaderEnd", {}), (this.bgLoading = !0), (t.next = 22), this.resources.load("ui");
+ case 22:
+ (this.bgLoading = !1), B.autoload && this.loadGame();
+ case 24:
+ case "end":
+ return t.stop();
+ }
+ },
+ _callee2,
+ this
+ );
+ })
+ );
+ return function () {
+ return t.apply(this, arguments);
+ };
+ })()),
+ (i.loadGame = (function () {
+ var t = Application_asyncToGenerator(
+ regeneratorRuntime.mark(function _callee3() {
+ return regeneratorRuntime.wrap(
+ function (t) {
+ for (;;)
+ switch ((t.prev = t.next)) {
+ case 0:
+ if (this.bgLoading) return t.abrupt("return");
+ t.next = 2;
+ break;
+ case 2:
+ return (this.bgLoading = !0), nn.a.sendCustomMessage("mainMenu", "secondLoaderStart", {}), (t.next = 6), this.resources.load("game");
+ case 6:
+ (this.bgLoading = !1), (this.gameLoaded = !0);
+ case 8:
+ case "end":
+ return t.stop();
+ }
+ },
+ _callee3,
+ this
+ );
+ })
+ );
+ return function () {
+ return t.apply(this, arguments);
+ };
+ })()),
+ (i.onLoadStart = function (t, e) {}),
+ (i.onLoadComplete = function (t, e) {
+ switch (t) {
+ case "preload":
+ break;
+ case "idle":
+ B.fastplay || this.ready();
+ break;
+ case "ui":
+ B.fastplay || (nn.a.sendCustomMessage("mainMenu", "interactive", {}), nn.a.SDK.gameLoadingFinished());
+ break;
+ case "game":
+ nn.a.sendCustomMessage("mainMenu", "secondLoaderEnd", {}), this.ready(), (this.gameLoaded = !0), this.shouldStartGame && this.startGame();
+ }
+ this.size.update();
+ }),
+ (i.ready = function () {
+ var e = this;
+ this._readyDispatched ||
+ this._ready ||
+ ((this._readyDispatched = !0),
+ this.strings.onAppReady(),
+ this.createGame(),
+ (this.sections = new vn("root")),
+ (this.sections.container = this.stage),
+ this.addScreen("title", new _n(this)),
+ this.addScreen("game", new kn(this)),
+ setTimeout(function () {
+ e._ready = !0;
+ var t = B.fastplay ? "game" : "title";
+ e.screenManager.gotoScreenByID(t), e.onReady.dispatch(), (e.loadingScreen.firstLoadPassed = !0);
+ }, 100));
+ }),
+ (i.createGame = function () {
+ this.game || ((this.game = new pn(this, B, this.sfx)), this.game.idle(), this.stage.addChildAt(this.game.stage, 0));
+ }),
+ (i.startGame = function () {
+ if ((this.sections && this.sections.close(), !this.gameLoaded)) return this.loadGame(), (this.shouldStartGame = !0), void (this.loadingScreen && this.loadingScreen.updateView(!0));
+ this.loadingScreen.updateView(!1),
+ this.sfx.play("hero_foot_l", {
+ volume: 0.01,
+ }),
+ this.sfx.volume(this.settings.sound ? B.volume : 0),
+ this.screenManager.gotoScreenByID("game");
+ }),
+ (i.onFocus = function () {
+ this.suspended || (this.game && this.game.onFocus());
+ }),
+ (i.onBlur = function () {
+ this.suspended || (this.game && this.game.onBlur());
+ }),
+ (i.onMessage = function (t) {
+ "startGame" === t.data && this.startGame();
+ }),
+ (i.onResize = function () {
+ (this.view.style.width = this.size.w + "px"),
+ (this.view.style.height = this.size.h + "px"),
+ (this.view.style.left = "0px"),
+ (this.view.style.top = "0px"),
+ this.renderer.resize(this.size.sw, this.size.sh),
+ this.screenManager.resize(this.size.w, this.size.h),
+ (this.screenManager.container.scale.x = this.size.scale),
+ (this.screenManager.container.scale.y = this.size.scale),
+ this.sections && this.sections.resize(this.size.sw, this.size.sh, 2),
+ this.game && this.game.resize(this.size.sw, this.size.sh, 2),
+ this.blocker && this.blocker.visible && ((this.blocker.width = this.size.sw), (this.blocker.height = this.size.sh));
+ }),
+ (i.suspend = function () {
+ this.suspended ||
+ ((this.suspended = !0),
+ this.sfx.mute(),
+ this.blocker || ((this.blocker = new c.Graphics()), this.blocker.beginFill(this.color, 0.5), this.blocker.drawRect(0, 0, 16, 16), this.blocker.endFill()),
+ (this.blocker.visible = !0),
+ this.stage.addChild(this.blocker),
+ (this.blocker.width = this.size.sw),
+ (this.blocker.height = this.size.sh));
+ }),
+ (i.resume = function () {
+ this.suspended && ((this.suspended = !1), this.view.focus(), this.sfx.unmute(), this.blocker && (this.blocker.visible = !1), this.blocker && this.blocker.parent && this.stage.addChild(this.blocker));
+ }),
+ (i.runWithTicker = function () {
+ d.a.instance.add(this.updateTicker, this, 1);
+ }),
+ (i.runWithAnimFrame = function () {
+ (this.updateAnimFrameBind = this.updateAnimFrame.bind(this)), requestAnimationFrame(this.updateAnimFrameBind);
+ }),
+ (i.updateTicker = function (t) {
+ this.game && this.game.updateTicker(t), this.renderer.render(this.stage);
+ }),
+ (i.updateAnimFrame = function (t) {
+ requestAnimationFrame(this.updateAnimFrameBind), this.game && this.game.updateAnimFrame(t), this.renderer.render(this.stage);
+ }),
+ (i.addScreen = function (t, e) {
+ (this[t + "Screen"] = e), "loading" === t ? (this.screenManager.loadingScreen = e) : this.screenManager.addScreen(e, t);
+ }),
+ (i.addSystem = function (t, e) {
+ if ((this.system || (this.system = {}), this.system[t])) throw new Error("App already have system: " + t);
+ if (this[t]) throw new Error("App already have a member with the same name as the system: " + t);
+ for (var i in ((this.system[t] = e), (this[t] = e), this.signal)) e[i] && this.signal[i].add(e[i], e);
+ e.init && e.init(this);
+ }),
+ (i.addSignal = function (t, e) {
+ if ((this.signal || (this.signal = {}), this.signal[t])) throw new Error("App already have signal: " + t);
+ for (var i in (e || (e = new l.a()), (this.signal[t] = e), this.system)) {
+ var n = this.system[i];
+ n[t] && "function" == typeof this[t] && e.add(n[t], n);
+ }
+ return this[t] && "function" == typeof this[t] && e.add(this[t], this), e;
+ }),
+ Application
+ );
+ })(a.a),
+ ho = i(197),
+ lo = {
+ gid: "ssurfers",
+ gameDir: "",
+ gameContainerId: "og-game-holder",
+ isFullScreen: window.self === window.top,
+ exitGameUrl: "",
+ environment: "test",
+ embedVars: {
+ statsCounterName: "testCounterName",
+ statsAppName: "TestAppName",
+ },
+ };
+ !(function () {
+ if ((window.VConsole && new window.VConsole(), new ho.a().supported)) {
+ window.og || (window.og = lo),
+ window.ASSET_URL || (window.ASSET_URL = ""),
+ window.DEVICE_SCALE || (window.DEVICE_SCALE = window.devicePixelRatio || 1),
+ window.console || (window.console = {}),
+ window.console.log ||
+ (window.console.log = function (t) {
+ return t;
+ });
+ var t = document.getElementById(lo.gameContainerId);
+ new ro(window.sharedAppData).init(t);
+ }
+ })();
+ },
+ });
+
\ No newline at end of file
diff --git a/subway-surfers-ny/js/vendor.js b/subway-surfers-ny/js/vendor.js
new file mode 100644
index 00000000..2564a86d
--- /dev/null
+++ b/subway-surfers-ny/js/vendor.js
@@ -0,0 +1,28979 @@
+(this.webpackJsonp = this.webpackJsonp || []).push([
+ [2],
+ [function(t, e, r) {
+ "use strict";
+ r.r(e);
+ var n = {};
+ r.r(n), r.d(n, "isMobile", function() {
+ return h.a
+ }), r.d(n, "EventEmitter", function() {
+ return l.a
+ }), r.d(n, "earcut", function() {
+ return d.a
+ }), r.d(n, "url", function() {
+ return m.a
+ }), r.d(n, "BaseTextureCache", function() {
+ return k
+ }), r.d(n, "CanvasRenderTarget", function() {
+ return L
+ }), r.d(n, "DATA_URI", function() {
+ return U
+ }), r.d(n, "ProgramCache", function() {
+ return D
+ }), r.d(n, "TextureCache", function() {
+ return F
+ }), r.d(n, "clearTextureCache", function() {
+ return clearTextureCache
+ }), r.d(n, "correctBlendMode", function() {
+ return correctBlendMode
+ }), r.d(n, "createIndicesForQuads", function() {
+ return createIndicesForQuads
+ }), r.d(n, "decomposeDataUri", function() {
+ return decomposeDataUri
+ }), r.d(n, "deprecation", function() {
+ return deprecation
+ }), r.d(n, "destroyTextureCache", function() {
+ return destroyTextureCache
+ }), r.d(n, "determineCrossOrigin", function() {
+ return determineCrossOrigin
+ }), r.d(n, "getResolutionOfUrl", function() {
+ return getResolutionOfUrl
+ }), r.d(n, "hex2rgb", function() {
+ return hex2rgb
+ }), r.d(n, "hex2string", function() {
+ return hex2string
+ }), r.d(n, "isPow2", function() {
+ return isPow2
+ }), r.d(n, "isWebGLSupported", function() {
+ return isWebGLSupported
+ }), r.d(n, "log2", function() {
+ return log2
+ }), r.d(n, "nextPow2", function() {
+ return nextPow2
+ }), r.d(n, "premultiplyBlendMode", function() {
+ return C
+ }), r.d(n, "premultiplyRgba", function() {
+ return premultiplyRgba
+ }), r.d(n, "premultiplyTint", function() {
+ return premultiplyTint
+ }), r.d(n, "premultiplyTintToRgba", function() {
+ return premultiplyTintToRgba
+ }), r.d(n, "removeItems", function() {
+ return removeItems
+ }), r.d(n, "rgb2hex", function() {
+ return rgb2hex
+ }), r.d(n, "sayHello", function() {
+ return sayHello
+ }), r.d(n, "sign", function() {
+ return sign
+ }), r.d(n, "skipHello", function() {
+ return skipHello
+ }), r.d(n, "string2hex", function() {
+ return string2hex
+ }), r.d(n, "trimCanvas", function() {
+ return trimCanvas
+ }), r.d(n, "uid", function() {
+ return uid
+ });
+ var i = {};
+ r.r(i), r.d(i, "AccessibilityManager", function() {
+ return vt
+ }), r.d(i, "accessibleTarget", function() {
+ return mt
+ });
+ var o = {};
+ r.r(o), r.d(o, "Extract", function() {
+ return fr
+ });
+ var a = {};
+ r.r(a), r.d(a, "InteractionData", function() {
+ return dr
+ }), r.d(a, "InteractionEvent", function() {
+ return mr
+ }), r.d(a, "InteractionManager", function() {
+ return br
+ }), r.d(a, "InteractionTrackingData", function() {
+ return vr
+ }), r.d(a, "interactiveTarget", function() {
+ return yr
+ });
+ var s = {};
+ r.r(s), r.d(s, "BasePrepare", function() {
+ return $r
+ }), r.d(s, "CountLimiter", function() {
+ return Jr
+ }), r.d(s, "Prepare", function() {
+ return tn
+ }), r.d(s, "TimeLimiter", function() {
+ return en
+ });
+ r(401);
+ var u = r(46),
+ h = r.n(u);
+ var M = {
+ MIPMAP_TEXTURES: 1,
+ RESOLUTION: 1,
+ FILTER_RESOLUTION: 1,
+ SPRITE_MAX_TEXTURES: function(t) {
+ var e = !0;
+ if (h.a.tablet || h.a.phone) {
+ if (e = !1, h.a.apple.device) {
+ var r = navigator.userAgent.match(/OS (\d+)_(\d+)?/);
+ r && 11 <= parseInt(r[1], 10) && (e = !0)
+ }
+ if (h.a.android.device) {
+ var n = navigator.userAgent.match(/Android\s([0-9.]*)/);
+ n && 7 <= parseInt(n[1], 10) && (e = !0)
+ }
+ }
+ return e ? t : 4
+ }(32),
+ SPRITE_BATCH_SIZE: 4096,
+ RENDER_OPTIONS: {
+ view: null,
+ antialias: !1,
+ forceFXAA: !1,
+ autoResize: !1,
+ transparent: !1,
+ backgroundColor: 0,
+ clearBeforeRender: !0,
+ preserveDrawingBuffer: !1,
+ width: 800,
+ height: 600,
+ legacy: !1
+ },
+ GC_MODE: 0,
+ GC_MAX_IDLE: 3600,
+ GC_MAX_CHECK_COUNT: 600,
+ WRAP_MODE: 33071,
+ SCALE_MODE: 1,
+ PRECISION_VERTEX: "highp",
+ PRECISION_FRAGMENT: h.a.apple.device ? "highp" : "mediump",
+ CAN_UPLOAD_SAME_BUFFER: !h.a.apple.device,
+ CREATE_IMAGE_BITMAP: !0,
+ ROUND_PIXELS: !1
+ },
+ c = r(170),
+ l = r.n(c),
+ f = r(171),
+ d = r.n(f),
+ p = r(89),
+ m = r.n(p),
+ v = {
+ WEBGL_LEGACY: 0,
+ WEBGL: 1,
+ WEBGL2: 2
+ },
+ g = {
+ UNKNOWN: 0,
+ WEBGL: 1,
+ CANVAS: 2
+ },
+ y = {
+ NORMAL: 0,
+ ADD: 1,
+ MULTIPLY: 2,
+ SCREEN: 3,
+ OVERLAY: 4,
+ DARKEN: 5,
+ LIGHTEN: 6,
+ COLOR_DODGE: 7,
+ COLOR_BURN: 8,
+ HARD_LIGHT: 9,
+ SOFT_LIGHT: 10,
+ DIFFERENCE: 11,
+ EXCLUSION: 12,
+ HUE: 13,
+ SATURATION: 14,
+ COLOR: 15,
+ LUMINOSITY: 16,
+ NORMAL_NPM: 17,
+ ADD_NPM: 18,
+ SCREEN_NPM: 19,
+ NONE: 20,
+ SRC_OVER: 0,
+ SRC_IN: 21,
+ SRC_OUT: 22,
+ SRC_ATOP: 23,
+ DST_OVER: 24,
+ DST_IN: 25,
+ DST_OUT: 26,
+ DST_ATOP: 27,
+ ERASE: 26,
+ SUBTRACT: 28
+ },
+ x = {
+ POINTS: 0,
+ LINES: 1,
+ LINE_LOOP: 2,
+ LINE_STRIP: 3,
+ TRIANGLES: 4,
+ TRIANGLE_STRIP: 5,
+ TRIANGLE_FAN: 6
+ },
+ _ = {
+ RGBA: 6408,
+ RGB: 6407,
+ ALPHA: 6406,
+ LUMINANCE: 6409,
+ LUMINANCE_ALPHA: 6410,
+ DEPTH_COMPONENT: 6402,
+ DEPTH_STENCIL: 34041
+ },
+ b = {
+ TEXTURE_2D: 3553,
+ TEXTURE_CUBE_MAP: 34067,
+ TEXTURE_2D_ARRAY: 35866,
+ TEXTURE_CUBE_MAP_POSITIVE_X: 34069,
+ TEXTURE_CUBE_MAP_NEGATIVE_X: 34070,
+ TEXTURE_CUBE_MAP_POSITIVE_Y: 34071,
+ TEXTURE_CUBE_MAP_NEGATIVE_Y: 34072,
+ TEXTURE_CUBE_MAP_POSITIVE_Z: 34073,
+ TEXTURE_CUBE_MAP_NEGATIVE_Z: 34074
+ },
+ w = {
+ UNSIGNED_BYTE: 5121,
+ UNSIGNED_SHORT: 5123,
+ UNSIGNED_SHORT_5_6_5: 33635,
+ UNSIGNED_SHORT_4_4_4_4: 32819,
+ UNSIGNED_SHORT_5_5_5_1: 32820,
+ FLOAT: 5126,
+ HALF_FLOAT: 36193
+ },
+ T = {
+ LINEAR: 1,
+ NEAREST: 0
+ },
+ S = {
+ CLAMP: 33071,
+ REPEAT: 10497,
+ MIRRORED_REPEAT: 33648
+ },
+ E = {
+ OFF: 0,
+ POW2: 1,
+ ON: 2
+ },
+ A = {
+ AUTO: 0,
+ MANUAL: 1
+ },
+ P = {
+ LOW: "lowp",
+ MEDIUM: "mediump",
+ HIGH: "highp"
+ },
+ I = !(M.RETINA_PREFIX = /@([0-9\.]+)x/),
+ O = "5.0.0-rc.3";
+
+ function skipHello() {
+ I = !0
+ }
+
+ function sayHello(t) {
+ if (!I) {
+ if (-1 < navigator.userAgent.toLowerCase().indexOf("chrome")) {
+ var e = ["\n %c %c %c PixiJS " + O + " - ✰ " + t + " ✰ %c %c http://www.pixijs.com/ %c %c ♥%c♥%c♥ \n\n", "background: #ff66a5; padding:5px 0;", "background: #ff66a5; padding:5px 0;", "color: #ff66a5; background: #030307; padding:5px 0;", "background: #ff66a5; padding:5px 0;", "background: #ffc3dc; padding:5px 0;", "background: #ff66a5; padding:5px 0;", "color: #ff2424; background: #fff; padding:5px 0;", "color: #ff2424; background: #fff; padding:5px 0;", "color: #ff2424; background: #fff; padding:5px 0;"];
+ window.console.log.apply(console, e)
+ } else window.console && window.console.log("PixiJS " + O + " - " + t + " - http://www.pixijs.com/");
+ I = !0
+ }
+ }
+
+ function isWebGLSupported() {
+ var t = {
+ stencil: !0,
+ failIfMajorPerformanceCaveat: !0
+ };
+ try {
+ if (!window.WebGLRenderingContext) return !1;
+ var e = document.createElement("canvas"),
+ r = e.getContext("webgl", t) || e.getContext("experimental-webgl", t),
+ n = !(!r || !r.getContextAttributes().stencil);
+ if (r) {
+ var i = r.getExtension("WEBGL_lose_context");
+ i && i.loseContext()
+ }
+ return r = null, n
+ } catch (t) {
+ return !1
+ }
+ }
+
+ function hex2rgb(t, e) {
+ return (e = e || [])[0] = (t >> 16 & 255) / 255, e[1] = (t >> 8 & 255) / 255, e[2] = (255 & t) / 255, e
+ }
+
+ function hex2string(t) {
+ return t = t.toString(16), "#" + (t = "000000".substr(0, 6 - t.length) + t)
+ }
+
+ function string2hex(t) {
+ return "string" == typeof t && "#" === t[0] && (t = t.substr(1)), parseInt(t, 16)
+ }
+
+ function rgb2hex(t) {
+ return (255 * t[0] << 16) + (255 * t[1] << 8) + (255 * t[2] | 0)
+ }
+ var C = function() {
+ for (var t = [], e = [], r = 0; r < 32; r++) e[t[r] = r] = r;
+ t[y.NORMAL_NPM] = y.NORMAL, t[y.ADD_NPM] = y.ADD, t[y.SCREEN_NPM] = y.SCREEN, e[y.NORMAL] = y.NORMAL_NPM, e[y.ADD] = y.ADD_NPM, e[y.SCREEN] = y.SCREEN_NPM;
+ var n = [];
+ return n.push(e), n.push(t), n
+ }();
+
+ function correctBlendMode(t, e) {
+ return C[e ? 1 : 0][t]
+ }
+
+ function premultiplyRgba(t, e, r, n) {
+ return (r = r || new Float32Array(4))[2] = n || void 0 === n ? (r[0] = t[0] * e, r[1] = t[1] * e, t[2] * e) : (r[0] = t[0], r[1] = t[1], t[2]), r[3] = e, r
+ }
+
+ function premultiplyTint(t, e) {
+ if (1 === e) return (255 * e << 24) + t;
+ if (0 === e) return 0;
+ var r = t >> 16 & 255,
+ n = t >> 8 & 255,
+ i = 255 & t;
+ return (255 * e << 24) + ((r = r * e + .5 | 0) << 16) + ((n = n * e + .5 | 0) << 8) + (i = i * e + .5 | 0)
+ }
+
+ function premultiplyTintToRgba(t, e, r, n) {
+ return (r = r || new Float32Array(4))[0] = (t >> 16 & 255) / 255, r[1] = (t >> 8 & 255) / 255, r[2] = (255 & t) / 255, (n || void 0 === n) && (r[0] *= e, r[1] *= e, r[2] *= e), r[3] = e, r
+ }
+
+ function createIndicesForQuads(t) {
+ for (var e = 6 * t, r = new Uint16Array(e), n = 0, i = 0; n < e; n += 6, i += 4) r[n + 0] = i + 0, r[n + 1] = i + 1, r[n + 2] = i + 2, r[n + 3] = i + 0, r[n + 4] = i + 2, r[n + 5] = i + 3;
+ return r
+ }
+
+ function removeItems(t, e, r) {
+ var n, i = t.length;
+ if (!(i <= e || 0 === r)) {
+ var o = i - (r = i < e + r ? i - e : r);
+ for (n = e; n < o; ++n) t[n] = t[n + r];
+ t.length = o
+ }
+ }
+ var R = 0;
+
+ function uid() {
+ return ++R
+ }
+
+ function sign(t) {
+ return 0 === t ? 0 : t < 0 ? -1 : 1
+ }
+
+ function nextPow2(t) {
+ return t += 0 === t, --t, t |= t >>> 1, t |= t >>> 2, t |= t >>> 4, t |= t >>> 8, (t |= t >>> 16) + 1
+ }
+
+ function isPow2(t) {
+ return !(t & t - 1 || !t)
+ }
+
+ function log2(t) {
+ var e = (65535 < t) << 4,
+ r = (255 < (t >>>= e)) << 3;
+ return e |= r, e |= r = (15 < (t >>>= r)) << 2, (e |= r = (3 < (t >>>= r)) << 1) | (t >>>= r) >> 1
+ }
+ var D = {},
+ F = Object.create(null),
+ k = Object.create(null);
+
+ function destroyTextureCache() {
+ var t;
+ for (t in F) F[t].destroy();
+ for (t in k) k[t].destroy()
+ }
+
+ function clearTextureCache() {
+ var t;
+ for (t in F) delete F[t];
+ for (t in k) delete k[t]
+ }
+
+ function trimCanvas(t) {
+ var e, r, n, i = t.width,
+ o = t.height,
+ a = t.getContext("2d"),
+ s = a.getImageData(0, 0, i, o).data,
+ u = s.length,
+ h = {
+ top: null,
+ left: null,
+ right: null,
+ bottom: null
+ },
+ c = null;
+ for (e = 0; e < u; e += 4) 0 !== s[e + 3] && (r = e / 4 % i, n = ~~(e / 4 / i), null === h.top && (h.top = n), null === h.left ? h.left = r : r < h.left && (h.left = r), null === h.right ? h.right = r + 1 : h.right < r && (h.right = r + 1), null === h.bottom ? h.bottom = n : h.bottom < n && (h.bottom = n));
+ return null !== h.top && (i = h.right - h.left, o = h.bottom - h.top + 1, c = a.getImageData(h.left, h.top, i, o)), {
+ height: o,
+ width: i,
+ data: c
+ }
+ }
+ var L = function(t, e, r) {
+ this.canvas = document.createElement("canvas"), this.context = this.canvas.getContext("2d"), this.resolution = r || M.RESOLUTION, this.resize(t, e)
+ },
+ N = {
+ width: {
+ configurable: !0
+ },
+ height: {
+ configurable: !0
+ }
+ };
+ L.prototype.clear = function() {
+ this.context.setTransform(1, 0, 0, 1, 0, 0), this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)
+ }, L.prototype.resize = function(t, e) {
+ this.canvas.width = t * this.resolution, this.canvas.height = e * this.resolution
+ }, L.prototype.destroy = function() {
+ this.context = null, this.canvas = null
+ }, N.width.get = function() {
+ return this.canvas.width
+ }, N.width.set = function(t) {
+ this.canvas.width = t
+ }, N.height.get = function() {
+ return this.canvas.height
+ }, N.height.set = function(t) {
+ this.canvas.height = t
+ }, Object.defineProperties(L.prototype, N);
+ var B, U = /^\s*data:(?:([\w-]+)\/([\w+.-]+))?(?:;charset=([\w-]+))?(?:;(base64))?,(.*)/i;
+
+ function decomposeDataUri(t) {
+ var e = U.exec(t);
+ if (e) return {
+ mediaType: e[1] ? e[1].toLowerCase() : void 0,
+ subType: e[2] ? e[2].toLowerCase() : void 0,
+ charset: e[3] ? e[3].toLowerCase() : void 0,
+ encoding: e[4] ? e[4].toLowerCase() : void 0,
+ data: e[5]
+ }
+ }
+
+ function determineCrossOrigin(t, e) {
+ if (void 0 === e && (e = window.location), 0 === t.indexOf("data:")) return "";
+ e = e || window.location, B || (B = document.createElement("a")), B.href = t;
+ var r = !(t = m.a.parse(B.href)).port && "" === e.port || t.port === e.port;
+ return t.hostname === e.hostname && r && t.protocol === e.protocol ? "" : "anonymous"
+ }
+
+ function getResolutionOfUrl(t, e) {
+ var r = M.RETINA_PREFIX.exec(t);
+ return r ? parseFloat(r[1]) : void 0 !== e ? e : 1
+ }
+ var G = {};
+
+ function deprecation(t, e, r) {
+ if (void 0 === r && (r = 3), !G[e]) {
+ var n = (new Error).stack;
+ void 0 === n || (n = n.split("\n").splice(r).join("\n"), console.groupCollapsed), G[e] = !0
+ }
+ }
+ var q = function(t, e) {
+ void 0 === t && (t = 0), void 0 === e && (e = 0), this.x = t, this.y = e
+ };
+ q.prototype.clone = function() {
+ return new q(this.x, this.y)
+ }, q.prototype.copyFrom = function(t) {
+ return this.set(t.x, t.y), this
+ }, q.prototype.copyTo = function(t) {
+ return t.set(this.x, this.y), t
+ }, q.prototype.equals = function(t) {
+ return t.x === this.x && t.y === this.y
+ }, q.prototype.set = function(t, e) {
+ this.x = t || 0, this.y = e || (0 !== e ? this.x : 0)
+ };
+ var j = function(t, e, r, n) {
+ void 0 === r && (r = 0), void 0 === n && (n = 0), this._x = r, this._y = n, this.cb = t, this.scope = e
+ },
+ z = {
+ x: {
+ configurable: !0
+ },
+ y: {
+ configurable: !0
+ }
+ };
+ j.prototype.clone = function(t, e) {
+ void 0 === t && (t = null), void 0 === e && (e = null);
+ var r = t || this.cb,
+ n = e || this.scope;
+ return new j(r, n, this._x, this._y)
+ }, j.prototype.set = function(t, e) {
+ var r = t || 0,
+ n = e || (0 !== e ? r : 0);
+ this._x === r && this._y === n || (this._x = r, this._y = n, this.cb.call(this.scope))
+ }, j.prototype.copyFrom = function(t) {
+ return this._x === t.x && this._y === t.y || (this._x = t.x, this._y = t.y, this.cb.call(this.scope)), this
+ }, j.prototype.copyTo = function(t) {
+ return t.set(this._x, this._y), t
+ }, j.prototype.equals = function(t) {
+ return t.x === this._x && t.y === this._y
+ }, z.x.get = function() {
+ return this._x
+ }, z.x.set = function(t) {
+ this._x !== t && (this._x = t, this.cb.call(this.scope))
+ }, z.y.get = function() {
+ return this._y
+ }, z.y.set = function(t) {
+ this._y !== t && (this._y = t, this.cb.call(this.scope))
+ }, Object.defineProperties(j.prototype, z);
+ var X = 2 * Math.PI,
+ V = 180 / Math.PI,
+ H = Math.PI / 180,
+ W = {
+ POLY: 0,
+ RECT: 1,
+ CIRC: 2,
+ ELIP: 3,
+ RREC: 4
+ },
+ Y = function(t, e, r, n, i, o) {
+ void 0 === t && (t = 1), void 0 === e && (e = 0), void 0 === r && (r = 0), void 0 === n && (n = 1), void 0 === i && (i = 0), void 0 === o && (o = 0), this.a = t, this.b = e, this.c = r, this.d = n, this.tx = i, this.ty = o, this.array = null
+ },
+ K = {
+ IDENTITY: {
+ configurable: !0
+ },
+ TEMP_MATRIX: {
+ configurable: !0
+ }
+ };
+ Y.prototype.fromArray = function(t) {
+ this.a = t[0], this.b = t[1], this.c = t[3], this.d = t[4], this.tx = t[2], this.ty = t[5]
+ }, Y.prototype.set = function(t, e, r, n, i, o) {
+ return this.a = t, this.b = e, this.c = r, this.d = n, this.tx = i, this.ty = o, this
+ }, Y.prototype.toArray = function(t, e) {
+ this.array || (this.array = new Float32Array(9));
+ var r = e || this.array;
+ return r[8] = (r[7] = t ? (r[0] = this.a, r[1] = this.b, r[2] = 0, r[3] = this.c, r[4] = this.d, r[5] = 0, r[6] = this.tx, this.ty) : (r[0] = this.a, r[1] = this.c, r[2] = this.tx, r[3] = this.b, r[4] = this.d, r[5] = this.ty, r[6] = 0), 1), r
+ }, Y.prototype.apply = function(t, e) {
+ e = e || new q;
+ var r = t.x,
+ n = t.y;
+ return e.x = this.a * r + this.c * n + this.tx, e.y = this.b * r + this.d * n + this.ty, e
+ }, Y.prototype.applyInverse = function(t, e) {
+ e = e || new q;
+ var r = 1 / (this.a * this.d + this.c * -this.b),
+ n = t.x,
+ i = t.y;
+ return e.x = this.d * r * n + -this.c * r * i + (this.ty * this.c - this.tx * this.d) * r, e.y = this.a * r * i + -this.b * r * n + (-this.ty * this.a + this.tx * this.b) * r, e
+ }, Y.prototype.translate = function(t, e) {
+ return this.tx += t, this.ty += e, this
+ }, Y.prototype.scale = function(t, e) {
+ return this.a *= t, this.d *= e, this.c *= t, this.b *= e, this.tx *= t, this.ty *= e, this
+ }, Y.prototype.rotate = function(t) {
+ var e = Math.cos(t),
+ r = Math.sin(t),
+ n = this.a,
+ i = this.c,
+ o = this.tx;
+ return this.a = n * e - this.b * r, this.b = n * r + this.b * e, this.c = i * e - this.d * r, this.d = i * r + this.d * e, this.tx = o * e - this.ty * r, this.ty = o * r + this.ty * e, this
+ }, Y.prototype.append = function(t) {
+ var e = this.a,
+ r = this.b,
+ n = this.c,
+ i = this.d;
+ return this.a = t.a * e + t.b * n, this.b = t.a * r + t.b * i, this.c = t.c * e + t.d * n, this.d = t.c * r + t.d * i, this.tx = t.tx * e + t.ty * n + this.tx, this.ty = t.tx * r + t.ty * i + this.ty, this
+ }, Y.prototype.setTransform = function(t, e, r, n, i, o, a, s, u) {
+ return this.a = Math.cos(a + u) * i, this.b = Math.sin(a + u) * i, this.c = -Math.sin(a - s) * o, this.d = Math.cos(a - s) * o, this.tx = t - (r * this.a + n * this.c), this.ty = e - (r * this.b + n * this.d), this
+ }, Y.prototype.prepend = function(t) {
+ var e = this.tx;
+ if (1 !== t.a || 0 !== t.b || 0 !== t.c || 1 !== t.d) {
+ var r = this.a,
+ n = this.c;
+ this.a = r * t.a + this.b * t.c, this.b = r * t.b + this.b * t.d, this.c = n * t.a + this.d * t.c, this.d = n * t.b + this.d * t.d
+ }
+ return this.tx = e * t.a + this.ty * t.c + t.tx, this.ty = e * t.b + this.ty * t.d + t.ty, this
+ }, Y.prototype.decompose = function(t) {
+ var e = this.a,
+ r = this.b,
+ n = this.c,
+ i = this.d,
+ o = -Math.atan2(-n, i),
+ a = Math.atan2(r, e),
+ s = Math.abs(o + a);
+ return s < 1e-5 || Math.abs(X - s) < 1e-5 ? (t.rotation = a, t.skew.x = t.skew.y = 0) : (t.rotation = 0, t.skew.x = o, t.skew.y = a), t.scale.x = Math.sqrt(e * e + r * r), t.scale.y = Math.sqrt(n * n + i * i), t.position.x = this.tx, t.position.y = this.ty, t
+ }, Y.prototype.invert = function() {
+ var t = this.a,
+ e = this.b,
+ r = this.c,
+ n = this.d,
+ i = this.tx,
+ o = t * n - e * r;
+ return this.a = n / o, this.b = -e / o, this.c = -r / o, this.d = t / o, this.tx = (r * this.ty - n * i) / o, this.ty = -(t * this.ty - e * i) / o, this
+ }, Y.prototype.identity = function() {
+ return this.a = 1, this.b = 0, this.c = 0, this.d = 1, this.tx = 0, this.ty = 0, this
+ }, Y.prototype.clone = function() {
+ var t = new Y;
+ return t.a = this.a, t.b = this.b, t.c = this.c, t.d = this.d, t.tx = this.tx, t.ty = this.ty, t
+ }, Y.prototype.copyTo = function(t) {
+ return t.a = this.a, t.b = this.b, t.c = this.c, t.d = this.d, t.tx = this.tx, t.ty = this.ty, t
+ }, Y.prototype.copyFrom = function(t) {
+ return this.a = t.a, this.b = t.b, this.c = t.c, this.d = t.d, this.tx = t.tx, this.ty = t.ty, this
+ }, K.IDENTITY.get = function() {
+ return new Y
+ }, K.TEMP_MATRIX.get = function() {
+ return new Y
+ }, Object.defineProperties(Y, K);
+ var Z = [1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1],
+ Q = [0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1],
+ J = [0, -1, -1, -1, 0, 1, 1, 1, 0, 1, 1, 1, 0, -1, -1, -1],
+ $ = [1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, 1, 1, 1, 0, -1],
+ tt = [],
+ et = [];
+
+ function signum(t) {
+ return t < 0 ? -1 : 0 < t ? 1 : 0
+ }! function() {
+ for (var t = 0; t < 16; t++) {
+ var e = [];
+ et.push(e);
+ for (var r = 0; r < 16; r++)
+ for (var n = signum(Z[t] * Z[r] + J[t] * Q[r]), i = signum(Q[t] * Z[r] + $[t] * Q[r]), o = signum(Z[t] * J[r] + J[t] * $[r]), a = signum(Q[t] * J[r] + $[t] * $[r]), s = 0; s < 16; s++)
+ if (Z[s] === n && Q[s] === i && J[s] === o && $[s] === a) {
+ e.push(s);
+ break
+ }
+ }
+ for (var u = 0; u < 16; u++) {
+ var h = new Y;
+ h.set(Z[u], Q[u], J[u], $[u], 0, 0), tt.push(h)
+ }
+ }();
+ var rt = {
+ E: 0,
+ SE: 1,
+ S: 2,
+ SW: 3,
+ W: 4,
+ NW: 5,
+ N: 6,
+ NE: 7,
+ MIRROR_VERTICAL: 8,
+ MIRROR_HORIZONTAL: 12,
+ uX: function(t) {
+ return Z[t]
+ },
+ uY: function(t) {
+ return Q[t]
+ },
+ vX: function(t) {
+ return J[t]
+ },
+ vY: function(t) {
+ return $[t]
+ },
+ inv: function(t) {
+ return 8 & t ? 15 & t : 7 & -t
+ },
+ add: function(t, e) {
+ return et[t][e]
+ },
+ sub: function(t, e) {
+ return et[t][rt.inv(e)]
+ },
+ rotate180: function(t) {
+ return 4 ^ t
+ },
+ isVertical: function(t) {
+ return 2 == (3 & t)
+ },
+ byDirection: function(t, e) {
+ return 2 * Math.abs(t) <= Math.abs(e) ? 0 <= e ? rt.S : rt.N : 2 * Math.abs(e) <= Math.abs(t) ? 0 < t ? rt.E : rt.W : 0 < e ? 0 < t ? rt.SE : rt.SW : 0 < t ? rt.NE : rt.NW
+ },
+ matrixAppendRotationInv: function(t, e, r, n) {
+ void 0 === r && (r = 0), void 0 === n && (n = 0);
+ var i = tt[rt.inv(e)];
+ i.tx = r, i.ty = n, t.append(i)
+ }
+ },
+ nt = function() {
+ this.worldTransform = new Y, this.localTransform = new Y, this.position = new j(this.onChange, this, 0, 0), this.scale = new j(this.onChange, this, 1, 1), this.pivot = new j(this.onChange, this, 0, 0), this.skew = new j(this.updateSkew, this, 0, 0), this._rotation = 0, this._cx = 1, this._sx = 0, this._cy = 0, this._sy = 1, this._localID = 0, this._currentLocalID = 0, this._worldID = 0, this._parentID = 0
+ },
+ it = {
+ rotation: {
+ configurable: !0
+ }
+ };
+ nt.prototype.onChange = function() {
+ this._localID++
+ }, nt.prototype.updateSkew = function() {
+ this._cx = Math.cos(this._rotation + this.skew._y), this._sx = Math.sin(this._rotation + this.skew._y), this._cy = -Math.sin(this._rotation - this.skew._x), this._sy = Math.cos(this._rotation - this.skew._x), this._localID++
+ }, nt.prototype.updateLocalTransform = function() {
+ var t = this.localTransform;
+ this._localID !== this._currentLocalID && (t.a = this._cx * this.scale._x, t.b = this._sx * this.scale._x, t.c = this._cy * this.scale._y, t.d = this._sy * this.scale._y, t.tx = this.position._x - (this.pivot._x * t.a + this.pivot._y * t.c), t.ty = this.position._y - (this.pivot._x * t.b + this.pivot._y * t.d), this._currentLocalID = this._localID, this._parentID = -1)
+ }, nt.prototype.updateTransform = function(t) {
+ var e = this.localTransform;
+ if (this._localID !== this._currentLocalID && (e.a = this._cx * this.scale._x, e.b = this._sx * this.scale._x, e.c = this._cy * this.scale._y, e.d = this._sy * this.scale._y, e.tx = this.position._x - (this.pivot._x * e.a + this.pivot._y * e.c), e.ty = this.position._y - (this.pivot._x * e.b + this.pivot._y * e.d), this._currentLocalID = this._localID, this._parentID = -1), this._parentID !== t._worldID) {
+ var r = t.worldTransform,
+ n = this.worldTransform;
+ n.a = e.a * r.a + e.b * r.c, n.b = e.a * r.b + e.b * r.d, n.c = e.c * r.a + e.d * r.c, n.d = e.c * r.b + e.d * r.d, n.tx = e.tx * r.a + e.ty * r.c + r.tx, n.ty = e.tx * r.b + e.ty * r.d + r.ty, this._parentID = t._worldID, this._worldID++
+ }
+ }, nt.prototype.setFromMatrix = function(t) {
+ t.decompose(this), this._localID++
+ }, it.rotation.get = function() {
+ return this._rotation
+ }, it.rotation.set = function(t) {
+ this._rotation !== t && (this._rotation = t, this.updateSkew())
+ }, Object.defineProperties(nt.prototype, it), nt.IDENTITY = new nt;
+ var ot = function(t, e, r, n) {
+ void 0 === t && (t = 0), void 0 === e && (e = 0), void 0 === r && (r = 0), void 0 === n && (n = 0), this.x = Number(t), this.y = Number(e), this.width = Number(r), this.height = Number(n), this.type = W.RECT
+ },
+ at = {
+ left: {
+ configurable: !0
+ },
+ right: {
+ configurable: !0
+ },
+ top: {
+ configurable: !0
+ },
+ bottom: {
+ configurable: !0
+ }
+ },
+ st = {
+ EMPTY: {
+ configurable: !0
+ }
+ };
+ at.left.get = function() {
+ return this.x
+ }, at.right.get = function() {
+ return this.x + this.width
+ }, at.top.get = function() {
+ return this.y
+ }, at.bottom.get = function() {
+ return this.y + this.height
+ }, st.EMPTY.get = function() {
+ return new ot(0, 0, 0, 0)
+ }, ot.prototype.clone = function() {
+ return new ot(this.x, this.y, this.width, this.height)
+ }, ot.prototype.copyFrom = function(t) {
+ return this.x = t.x, this.y = t.y, this.width = t.width, this.height = t.height, this
+ }, ot.prototype.copyTo = function(t) {
+ return t.x = this.x, t.y = this.y, t.width = this.width, t.height = this.height, t
+ }, ot.prototype.contains = function(t, e) {
+ return !(this.width <= 0 || this.height <= 0) && (t >= this.x && t < this.x + this.width && e >= this.y && e < this.y + this.height)
+ }, ot.prototype.pad = function(t, e) {
+ t = t || 0, e = e || (0 !== e ? t : 0), this.x -= t, this.y -= e, this.width += 2 * t, this.height += 2 * e
+ }, ot.prototype.fit = function(t) {
+ var e = Math.max(this.x, t.x),
+ r = Math.min(this.x + this.width, t.x + t.width),
+ n = Math.max(this.y, t.y),
+ i = Math.min(this.y + this.height, t.y + t.height);
+ this.x = e, this.width = Math.max(r - e, 0), this.y = n, this.height = Math.max(i - n, 0)
+ }, ot.prototype.ceil = function(t, e) {
+ void 0 === t && (t = 1), void 0 === e && (e = .001);
+ var r = Math.ceil((this.x + this.width - e) * t) / t,
+ n = Math.ceil((this.y + this.height - e) * t) / t;
+ this.x = Math.floor((this.x + e) * t) / t, this.y = Math.floor((this.y + e) * t) / t, this.width = r - this.x, this.height = n - this.y
+ }, ot.prototype.enlarge = function(t) {
+ var e = Math.min(this.x, t.x),
+ r = Math.max(this.x + this.width, t.x + t.width),
+ n = Math.min(this.y, t.y),
+ i = Math.max(this.y + this.height, t.y + t.height);
+ this.x = e, this.width = r - e, this.y = n, this.height = i - n
+ }, Object.defineProperties(ot.prototype, at), Object.defineProperties(ot, st);
+ var ut = function(t, e, r) {
+ void 0 === t && (t = 0), void 0 === e && (e = 0), void 0 === r && (r = 0), this.x = t, this.y = e, this.radius = r, this.type = W.CIRC
+ };
+ ut.prototype.clone = function() {
+ return new ut(this.x, this.y, this.radius)
+ }, ut.prototype.contains = function(t, e) {
+ if (this.radius <= 0) return !1;
+ var r = this.radius * this.radius,
+ n = this.x - t,
+ i = this.y - e;
+ return (n *= n) + (i *= i) <= r
+ }, ut.prototype.getBounds = function() {
+ return new ot(this.x - this.radius, this.y - this.radius, 2 * this.radius, 2 * this.radius)
+ };
+ var ht = function(t, e, r, n) {
+ void 0 === t && (t = 0), void 0 === e && (e = 0), void 0 === r && (r = 0), void 0 === n && (n = 0), this.x = t, this.y = e, this.width = r, this.height = n, this.type = W.ELIP
+ };
+ ht.prototype.clone = function() {
+ return new ht(this.x, this.y, this.width, this.height)
+ }, ht.prototype.contains = function(t, e) {
+ if (this.width <= 0 || this.height <= 0) return !1;
+ var r = (t - this.x) / this.width,
+ n = (e - this.y) / this.height;
+ return (r *= r) + (n *= n) <= 1
+ }, ht.prototype.getBounds = function() {
+ return new ot(this.x - this.width, this.y - this.height, this.width, this.height)
+ };
+ var ct = function() {
+ for (var t = [], e = arguments.length; e--;) t[e] = arguments[e];
+ if (Array.isArray(t[0]) && (t = t[0]), t[0] instanceof q) {
+ for (var r = [], n = 0, i = t.length; n < i; n++) r.push(t[n].x, t[n].y);
+ t = r
+ }
+ this.points = t, this.type = W.POLY, this.closeStroke = !0
+ };
+ ct.prototype.clone = function() {
+ var t = new ct(this.points.slice());
+ return t.closeStroke = this.closeStroke, t
+ }, ct.prototype.contains = function(t, e) {
+ for (var r = !1, n = this.points.length / 2, i = 0, o = n - 1; i < n; o = i++) {
+ var a = this.points[2 * i],
+ s = this.points[2 * i + 1],
+ u = this.points[2 * o],
+ h = this.points[2 * o + 1];
+ e < s != e < h && t < (e - s) / (h - s) * (u - a) + a && (r = !r)
+ }
+ return r
+ };
+ var lt = function(t, e, r, n, i) {
+ void 0 === t && (t = 0), void 0 === e && (e = 0), void 0 === r && (r = 0), void 0 === n && (n = 0), void 0 === i && (i = 20), this.x = t, this.y = e, this.width = r, this.height = n, this.radius = i, this.type = W.RREC
+ };
+ lt.prototype.clone = function() {
+ return new lt(this.x, this.y, this.width, this.height, this.radius)
+ }, lt.prototype.contains = function(t, e) {
+ if (this.width <= 0 || this.height <= 0) return !1;
+ if (t >= this.x && t <= this.x + this.width && e >= this.y && e <= this.y + this.height) {
+ if (e >= this.y + this.radius && e <= this.y + this.height - this.radius || t >= this.x + this.radius && t <= this.x + this.width - this.radius) return !0;
+ var r = t - (this.x + this.radius),
+ n = e - (this.y + this.radius),
+ i = this.radius * this.radius;
+ if (r * r + n * n <= i) return !0;
+ if ((r = t - (this.x + this.width - this.radius)) * r + n * n <= i) return !0;
+ if (r * r + (n = e - (this.y + this.height - this.radius)) * n <= i) return !0;
+ if ((r = t - (this.x + this.radius)) * r + n * n <= i) return !0
+ }
+ return !1
+ }, M.SORTABLE_CHILDREN = !1;
+ var ft = function() {
+ this.minX = 1 / 0, this.minY = 1 / 0, this.maxX = -1 / 0, this.maxY = -1 / 0, this.rect = null
+ };
+ ft.prototype.isEmpty = function() {
+ return this.minX > this.maxX || this.minY > this.maxY
+ }, ft.prototype.clear = function() {
+ this.updateID++, this.minX = 1 / 0, this.minY = 1 / 0, this.maxX = -1 / 0, this.maxY = -1 / 0
+ }, ft.prototype.getRectangle = function(t) {
+ return this.minX > this.maxX || this.minY > this.maxY ? ot.EMPTY : ((t = t || new ot(0, 0, 1, 1)).x = this.minX, t.y = this.minY, t.width = this.maxX - this.minX, t.height = this.maxY - this.minY, t)
+ }, ft.prototype.addPoint = function(t) {
+ this.minX = Math.min(this.minX, t.x), this.maxX = Math.max(this.maxX, t.x), this.minY = Math.min(this.minY, t.y), this.maxY = Math.max(this.maxY, t.y)
+ }, ft.prototype.addQuad = function(t) {
+ var e = this.minX,
+ r = this.minY,
+ n = this.maxX,
+ i = this.maxY,
+ o = t[0],
+ a = t[1];
+ e = o < e ? o : e, r = a < r ? a : r, n = n < o ? o : n, i = i < a ? a : i, e = (o = t[2]) < e ? o : e, r = (a = t[3]) < r ? a : r, n = n < o ? o : n, i = i < a ? a : i, e = (o = t[4]) < e ? o : e, r = (a = t[5]) < r ? a : r, n = n < o ? o : n, i = i < a ? a : i, e = (o = t[6]) < e ? o : e, r = (a = t[7]) < r ? a : r, n = n < o ? o : n, i = i < a ? a : i, this.minX = e, this.minY = r, this.maxX = n, this.maxY = i
+ }, ft.prototype.addFrame = function(t, e, r, n, i) {
+ var o = t.worldTransform,
+ a = o.a,
+ s = o.b,
+ u = o.c,
+ h = o.d,
+ c = o.tx,
+ l = o.ty,
+ f = this.minX,
+ d = this.minY,
+ p = this.maxX,
+ m = this.maxY,
+ v = a * e + u * r + c,
+ g = s * e + h * r + l;
+ f = v < f ? v : f, d = g < d ? g : d, p = p < v ? v : p, m = m < g ? g : m, f = (v = a * n + u * r + c) < f ? v : f, d = (g = s * n + h * r + l) < d ? g : d, p = p < v ? v : p, m = m < g ? g : m, f = (v = a * e + u * i + c) < f ? v : f, d = (g = s * e + h * i + l) < d ? g : d, p = p < v ? v : p, m = m < g ? g : m, f = (v = a * n + u * i + c) < f ? v : f, d = (g = s * n + h * i + l) < d ? g : d, p = p < v ? v : p, m = m < g ? g : m, this.minX = f, this.minY = d, this.maxX = p, this.maxY = m
+ }, ft.prototype.addVertexData = function(t, e, r) {
+ for (var n = this.minX, i = this.minY, o = this.maxX, a = this.maxY, s = e; s < r; s += 2) {
+ var u = t[s],
+ h = t[s + 1];
+ n = u < n ? u : n, i = h < i ? h : i, o = o < u ? u : o, a = a < h ? h : a
+ }
+ this.minX = n, this.minY = i, this.maxX = o, this.maxY = a
+ }, ft.prototype.addVertices = function(t, e, r, n) {
+ for (var i = t.worldTransform, o = i.a, a = i.b, s = i.c, u = i.d, h = i.tx, c = i.ty, l = this.minX, f = this.minY, d = this.maxX, p = this.maxY, m = r; m < n; m += 2) {
+ var v = e[m],
+ g = e[m + 1],
+ y = o * v + s * g + h,
+ _ = u * g + a * v + c;
+ l = y < l ? y : l, f = _ < f ? _ : f, d = d < y ? y : d, p = p < _ ? _ : p
+ }
+ this.minX = l, this.minY = f, this.maxX = d, this.maxY = p
+ }, ft.prototype.addBounds = function(t) {
+ var e = this.minX,
+ r = this.minY,
+ n = this.maxX,
+ i = this.maxY;
+ this.minX = t.minX < e ? t.minX : e, this.minY = t.minY < r ? t.minY : r, this.maxX = t.maxX > n ? t.maxX : n, this.maxY = t.maxY > i ? t.maxY : i
+ }, ft.prototype.addBoundsMask = function(t, e) {
+ var r = t.minX > e.minX ? t.minX : e.minX,
+ n = t.minY > e.minY ? t.minY : e.minY,
+ i = t.maxX < e.maxX ? t.maxX : e.maxX,
+ o = t.maxY < e.maxY ? t.maxY : e.maxY;
+ if (r <= i && n <= o) {
+ var a = this.minX,
+ s = this.minY,
+ u = this.maxX,
+ h = this.maxY;
+ this.minX = r < a ? r : a, this.minY = n < s ? n : s, this.maxX = u < i ? i : u, this.maxY = h < o ? o : h
+ }
+ }, ft.prototype.addBoundsArea = function(t, e) {
+ var r = t.minX > e.x ? t.minX : e.x,
+ n = t.minY > e.y ? t.minY : e.y,
+ i = t.maxX < e.x + e.width ? t.maxX : e.x + e.width,
+ o = t.maxY < e.y + e.height ? t.maxY : e.y + e.height;
+ if (r <= i && n <= o) {
+ var a = this.minX,
+ s = this.minY,
+ u = this.maxX,
+ h = this.maxY;
+ this.minX = r < a ? r : a, this.minY = n < s ? n : s, this.maxX = u < i ? i : u, this.maxY = h < o ? o : h
+ }
+ };
+ var dt = function(t) {
+ function DisplayObject() {
+ t.call(this), this.tempDisplayObjectParent = null, this.transform = new nt, this.alpha = 1, this.visible = !0, this.renderable = !0, this.parent = null, this.worldAlpha = 1, this._lastSortedIndex = 0, this._zIndex = 0, this.filterArea = null, this.filters = null, this._enabledFilters = null, this._bounds = new ft, this._boundsID = 0, this._lastBoundsID = -1, this._boundsRect = null, this._localBoundsRect = null, this._mask = null, this._destroyed = !1, this.isSprite = !1
+ }
+ t && (DisplayObject.__proto__ = t);
+ var e = {
+ _tempDisplayObjectParent: {
+ configurable: !0
+ },
+ x: {
+ configurable: !0
+ },
+ y: {
+ configurable: !0
+ },
+ worldTransform: {
+ configurable: !0
+ },
+ localTransform: {
+ configurable: !0
+ },
+ position: {
+ configurable: !0
+ },
+ scale: {
+ configurable: !0
+ },
+ pivot: {
+ configurable: !0
+ },
+ skew: {
+ configurable: !0
+ },
+ rotation: {
+ configurable: !0
+ },
+ angle: {
+ configurable: !0
+ },
+ zIndex: {
+ configurable: !0
+ },
+ worldVisible: {
+ configurable: !0
+ },
+ mask: {
+ configurable: !0
+ }
+ };
+ return ((DisplayObject.prototype = Object.create(t && t.prototype)).constructor = DisplayObject).mixin = function(t) {
+ for (var e = Object.keys(t), r = 0; r < e.length; ++r) {
+ var n = e[r];
+ Object.defineProperty(DisplayObject.prototype, n, Object.getOwnPropertyDescriptor(t, n))
+ }
+ }, e._tempDisplayObjectParent.get = function() {
+ return null === this.tempDisplayObjectParent && (this.tempDisplayObjectParent = new DisplayObject), this.tempDisplayObjectParent
+ }, DisplayObject.prototype.updateTransform = function() {
+ this.transform.updateTransform(this.parent.transform), this.worldAlpha = this.alpha * this.parent.worldAlpha, this._bounds.updateID++
+ }, DisplayObject.prototype._recursivePostUpdateTransform = function() {
+ this.parent ? (this.parent._recursivePostUpdateTransform(), this.transform.updateTransform(this.parent.transform)) : this.transform.updateTransform(this._tempDisplayObjectParent.transform)
+ }, DisplayObject.prototype.getBounds = function(t, e) {
+ return t || (this.parent ? (this._recursivePostUpdateTransform(), this.updateTransform()) : (this.parent = this._tempDisplayObjectParent, this.updateTransform(), this.parent = null)), this._boundsID !== this._lastBoundsID && this.calculateBounds(), e || (this._boundsRect || (this._boundsRect = new ot), e = this._boundsRect), this._bounds.getRectangle(e)
+ }, DisplayObject.prototype.getLocalBounds = function(t) {
+ var e = this.transform,
+ r = this.parent;
+ this.parent = null, this.transform = this._tempDisplayObjectParent.transform, t || (this._localBoundsRect || (this._localBoundsRect = new ot), t = this._localBoundsRect);
+ var n = this.getBounds(!1, t);
+ return this.parent = r, this.transform = e, n
+ }, DisplayObject.prototype.toGlobal = function(t, e, r) {
+ return void 0 === r && (r = !1), r || (this._recursivePostUpdateTransform(), this.parent ? this.displayObjectUpdateTransform() : (this.parent = this._tempDisplayObjectParent, this.displayObjectUpdateTransform(), this.parent = null)), this.worldTransform.apply(t, e)
+ }, DisplayObject.prototype.toLocal = function(t, e, r, n) {
+ return e && (t = e.toGlobal(t, r, n)), n || (this._recursivePostUpdateTransform(), this.parent ? this.displayObjectUpdateTransform() : (this.parent = this._tempDisplayObjectParent, this.displayObjectUpdateTransform(), this.parent = null)), this.worldTransform.applyInverse(t, r)
+ }, DisplayObject.prototype.render = function(t) {}, DisplayObject.prototype.setParent = function(t) {
+ if (!t || !t.addChild) throw new Error("setParent: Argument must be a Container");
+ return t.addChild(this), t
+ }, DisplayObject.prototype.setTransform = function(t, e, r, n, i, o, a, s, u) {
+ return void 0 === t && (t = 0), void 0 === e && (e = 0), void 0 === r && (r = 1), void 0 === n && (n = 1), void 0 === i && (i = 0), void 0 === o && (o = 0), void 0 === a && (a = 0), void 0 === s && (s = 0), void 0 === u && (u = 0), this.position.x = t, this.position.y = e, this.scale.x = r || 1, this.scale.y = n || 1, this.rotation = i, this.skew.x = o, this.skew.y = a, this.pivot.x = s, this.pivot.y = u, this
+ }, DisplayObject.prototype.destroy = function() {
+ this.removeAllListeners(), this.parent && this.parent.removeChild(this), this.transform = null, this.parent = null, this._bounds = null, this._currentBounds = null, this._mask = null, this.filterArea = null, this.interactive = !1, this.interactiveChildren = !1, this._destroyed = !0
+ }, e.x.get = function() {
+ return this.position.x
+ }, e.x.set = function(t) {
+ this.transform.position.x = t
+ }, e.y.get = function() {
+ return this.position.y
+ }, e.y.set = function(t) {
+ this.transform.position.y = t
+ }, e.worldTransform.get = function() {
+ return this.transform.worldTransform
+ }, e.localTransform.get = function() {
+ return this.transform.localTransform
+ }, e.position.get = function() {
+ return this.transform.position
+ }, e.position.set = function(t) {
+ this.transform.position.copyFrom(t)
+ }, e.scale.get = function() {
+ return this.transform.scale
+ }, e.scale.set = function(t) {
+ this.transform.scale.copyFrom(t)
+ }, e.pivot.get = function() {
+ return this.transform.pivot
+ }, e.pivot.set = function(t) {
+ this.transform.pivot.copyFrom(t)
+ }, e.skew.get = function() {
+ return this.transform.skew
+ }, e.skew.set = function(t) {
+ this.transform.skew.copyFrom(t)
+ }, e.rotation.get = function() {
+ return this.transform.rotation
+ }, e.rotation.set = function(t) {
+ this.transform.rotation = t
+ }, e.angle.get = function() {
+ return this.transform.rotation * V
+ }, e.angle.set = function(t) {
+ this.transform.rotation = t * H
+ }, e.zIndex.get = function() {
+ return this._zIndex
+ }, e.zIndex.set = function(t) {
+ this._zIndex = t, this.parent && (this.parent.sortDirty = !0)
+ }, e.worldVisible.get = function() {
+ var t = this;
+ do {
+ if (!t.visible) return !1;
+ t = t.parent
+ } while (t);
+ return !0
+ }, e.mask.get = function() {
+ return this._mask
+ }, e.mask.set = function(t) {
+ this._mask && (this._mask.renderable = !0, this._mask.isMask = !1), this._mask = t, this._mask && (this._mask.renderable = !1, this._mask.isMask = !0)
+ }, Object.defineProperties(DisplayObject.prototype, e), DisplayObject
+ }(l.a);
+
+ function sortChildren(t, e) {
+ return t.zIndex === e.zIndex ? t._lastSortedIndex - e._lastSortedIndex : t.zIndex - e.zIndex
+ }
+ dt.prototype.displayObjectUpdateTransform = dt.prototype.updateTransform;
+ var pt = function(i) {
+ function Container() {
+ i.call(this), this.children = [], this.sortableChildren = M.SORTABLE_CHILDREN, this.sortDirty = !1
+ }
+ i && (Container.__proto__ = i);
+ var t = {
+ width: {
+ configurable: !0
+ },
+ height: {
+ configurable: !0
+ }
+ };
+ return ((Container.prototype = Object.create(i && i.prototype)).constructor = Container).prototype.onChildrenChange = function() {}, Container.prototype.addChild = function(t) {
+ var e = arguments,
+ r = arguments.length;
+ if (1 < r)
+ for (var n = 0; n < r; n++) this.addChild(e[n]);
+ else t.parent && t.parent.removeChild(t), (t.parent = this).sortDirty = !0, t.transform._parentID = -1, this.children.push(t), this._boundsID++, this.onChildrenChange(this.children.length - 1), this.emit("childAdded", t, this, this.children.length - 1), t.emit("added", this);
+ return t
+ }, Container.prototype.addChildAt = function(t, e) {
+ if (e < 0 || e > this.children.length) throw new Error(t + "addChildAt: The index " + e + " supplied is out of bounds " + this.children.length);
+ return t.parent && t.parent.removeChild(t), (t.parent = this).sortDirty = !0, t.transform._parentID = -1, this.children.splice(e, 0, t), this._boundsID++, this.onChildrenChange(e), t.emit("added", this), this.emit("childAdded", t, this, e), t
+ }, Container.prototype.swapChildren = function(t, e) {
+ if (t !== e) {
+ var r = this.getChildIndex(t),
+ n = this.getChildIndex(e);
+ this.children[r] = e, this.children[n] = t, this.onChildrenChange(r < n ? r : n)
+ }
+ }, Container.prototype.getChildIndex = function(t) {
+ var e = this.children.indexOf(t);
+ if (-1 === e) throw new Error("The supplied DisplayObject must be a child of the caller");
+ return e
+ }, Container.prototype.setChildIndex = function(t, e) {
+ if (e < 0 || e >= this.children.length) throw new Error("The index " + e + " supplied is out of bounds " + this.children.length);
+ var r = this.getChildIndex(t);
+ removeItems(this.children, r, 1), this.children.splice(e, 0, t), this.onChildrenChange(e)
+ }, Container.prototype.getChildAt = function(t) {
+ if (t < 0 || t >= this.children.length) throw new Error("getChildAt: Index (" + t + ") does not exist.");
+ return this.children[t]
+ }, Container.prototype.removeChild = function(t) {
+ var e = arguments,
+ r = arguments.length;
+ if (1 < r)
+ for (var n = 0; n < r; n++) this.removeChild(e[n]);
+ else {
+ var i = this.children.indexOf(t);
+ if (-1 === i) return null;
+ t.parent = null, t.transform._parentID = -1, removeItems(this.children, i, 1), this._boundsID++, this.onChildrenChange(i), t.emit("removed", this), this.emit("childRemoved", t, this, i)
+ }
+ return t
+ }, Container.prototype.removeChildAt = function(t) {
+ var e = this.getChildAt(t);
+ return e.parent = null, e.transform._parentID = -1, removeItems(this.children, t, 1), this._boundsID++, this.onChildrenChange(t), e.emit("removed", this), this.emit("childRemoved", e, this, t), e
+ }, Container.prototype.removeChildren = function(t, e) {
+ void 0 === t && (t = 0);
+ var r, n = t,
+ i = "number" == typeof e ? e : this.children.length,
+ o = i - n;
+ if (0 < o && o <= i) {
+ r = this.children.splice(n, o);
+ for (var a = 0; a < r.length; ++a) r[a].parent = null, r[a].transform && (r[a].transform._parentID = -1);
+ this._boundsID++, this.onChildrenChange(t);
+ for (var s = 0; s < r.length; ++s) r[s].emit("removed", this), this.emit("childRemoved", r[s], this, s);
+ return r
+ }
+ if (0 === o && 0 === this.children.length) return [];
+ throw new RangeError("removeChildren: numeric values are outside the acceptable range.")
+ }, Container.prototype.sortChildren = function() {
+ for (var t = !1, e = 0, r = this.children.length; e < r; ++e) {
+ var n = this.children[e];
+ n._lastSortedIndex = e, t || 0 === n.zIndex || (t = !0)
+ }
+ t && 1 < this.children.length && this.children.sort(sortChildren), this.sortDirty = !1
+ }, Container.prototype.updateTransform = function() {
+ this.sortableChildren && this.sortDirty && this.sortChildren(), this._boundsID++, this.transform.updateTransform(this.parent.transform), this.worldAlpha = this.alpha * this.parent.worldAlpha;
+ for (var t = 0, e = this.children.length; t < e; ++t) {
+ var r = this.children[t];
+ r.visible && r.updateTransform()
+ }
+ }, Container.prototype.calculateBounds = function() {
+ this._bounds.clear(), this._calculateBounds();
+ for (var t = 0; t < this.children.length; t++) {
+ var e = this.children[t];
+ e.visible && e.renderable && (e.calculateBounds(), e._mask ? (e._mask.calculateBounds(), this._bounds.addBoundsMask(e._bounds, e._mask._bounds)) : e.filterArea ? this._bounds.addBoundsArea(e._bounds, e.filterArea) : this._bounds.addBounds(e._bounds))
+ }
+ this._lastBoundsID = this._boundsID
+ }, Container.prototype._calculateBounds = function() {}, Container.prototype.render = function(t) {
+ if (this.visible && !(this.worldAlpha <= 0) && this.renderable)
+ if (this._mask || this.filters) this.renderAdvanced(t);
+ else {
+ this._render(t);
+ for (var e = 0, r = this.children.length; e < r; ++e) this.children[e].render(t)
+ }
+ }, Container.prototype.renderAdvanced = function(t) {
+ t.batch.flush();
+ var e = this.filters,
+ r = this._mask;
+ if (e) {
+ this._enabledFilters || (this._enabledFilters = []);
+ for (var n = this._enabledFilters.length = 0; n < e.length; n++) e[n].enabled && this._enabledFilters.push(e[n]);
+ this._enabledFilters.length && t.filter.push(this, this._enabledFilters)
+ }
+ r && t.mask.push(this, this._mask), this._render(t);
+ for (var i = 0, o = this.children.length; i < o; i++) this.children[i].render(t);
+ t.batch.flush(), r && t.mask.pop(this, this._mask), e && this._enabledFilters && this._enabledFilters.length && t.filter.pop()
+ }, Container.prototype._render = function(t) {}, Container.prototype.destroy = function(t) {
+ i.prototype.destroy.call(this), this.sortDirty = !1;
+ var e = "boolean" == typeof t ? t : t && t.children,
+ r = this.removeChildren(0, this.children.length);
+ if (e)
+ for (var n = 0; n < r.length; ++n) r[n].destroy(t)
+ }, t.width.get = function() {
+ return this.scale.x * this.getLocalBounds().width
+ }, t.width.set = function(t) {
+ var e = this.getLocalBounds().width;
+ this.scale.x = 0 !== e ? t / e : 1, this._width = t
+ }, t.height.get = function() {
+ return this.scale.y * this.getLocalBounds().height
+ }, t.height.set = function(t) {
+ var e = this.getLocalBounds().height;
+ this.scale.y = 0 !== e ? t / e : 1, this._height = t
+ }, Object.defineProperties(Container.prototype, t), Container
+ }(dt);
+ pt.prototype.containerUpdateTransform = pt.prototype.updateTransform;
+ var mt = {
+ accessible: !1,
+ accessibleTitle: null,
+ accessibleHint: null,
+ tabIndex: 0,
+ _accessibleActive: !1,
+ _accessibleDiv: !1
+ };
+ dt.mixin(mt);
+ var vt = function(t) {
+ this._hookDiv = null, (h.a.tablet || h.a.phone) && this.createTouchHook();
+ var e = document.createElement("div");
+ e.style.width = "100px", e.style.height = "100px", e.style.position = "absolute", e.style.top = "0px", e.style.left = "0px", e.style.zIndex = 2, this.div = e, this.pool = [], this.renderId = 0, this.debug = !1, this.renderer = t, this.children = [], this._onKeyDown = this._onKeyDown.bind(this), this._onMouseMove = this._onMouseMove.bind(this), this.isActive = !1, this.isMobileAccessibility = !1, window.addEventListener("keydown", this._onKeyDown, !1)
+ };
+ vt.prototype.createTouchHook = function() {
+ var t = this,
+ e = document.createElement("button");
+ e.style.width = "1px", e.style.height = "1px", e.style.position = "absolute", e.style.top = "-1000px", e.style.left = "-1000px", e.style.zIndex = 2, e.style.backgroundColor = "#FF0000", e.title = "HOOK DIV", e.addEventListener("focus", function() {
+ t.isMobileAccessibility = !0, t.activate(), t.destroyTouchHook()
+ }), document.body.appendChild(e), this._hookDiv = e
+ }, vt.prototype.destroyTouchHook = function() {
+ this._hookDiv && (document.body.removeChild(this._hookDiv), this._hookDiv = null)
+ }, vt.prototype.activate = function() {
+ this.isActive || (this.isActive = !0, window.document.addEventListener("mousemove", this._onMouseMove, !0), window.removeEventListener("keydown", this._onKeyDown, !1), this.renderer.on("postrender", this.update, this), this.renderer.view.parentNode && this.renderer.view.parentNode.appendChild(this.div))
+ }, vt.prototype.deactivate = function() {
+ this.isActive && !this.isMobileAccessibility && (this.isActive = !1, window.document.removeEventListener("mousemove", this._onMouseMove, !0), window.addEventListener("keydown", this._onKeyDown, !1), this.renderer.off("postrender", this.update), this.div.parentNode && this.div.parentNode.removeChild(this.div))
+ }, vt.prototype.updateAccessibleObjects = function(t) {
+ if (t.visible) {
+ t.accessible && t.interactive && (t._accessibleActive || this.addChild(t), t.renderId = this.renderId);
+ for (var e = t.children, r = 0; r < e.length; r++) this.updateAccessibleObjects(e[r])
+ }
+ }, vt.prototype.update = function() {
+ if (this.renderer.renderingToScreen) {
+ this.updateAccessibleObjects(this.renderer._lastObjectRendered);
+ var t = this.renderer.view.getBoundingClientRect(),
+ e = t.width / this.renderer.width,
+ r = t.height / this.renderer.height,
+ n = this.div;
+ n.style.left = t.left + "px", n.style.top = t.top + "px", n.style.width = this.renderer.width + "px", n.style.height = this.renderer.height + "px";
+ for (var i = 0; i < this.children.length; i++) {
+ var o = this.children[i];
+ if (o.renderId !== this.renderId) o._accessibleActive = !1, removeItems(this.children, i, 1), this.div.removeChild(o._accessibleDiv), this.pool.push(o._accessibleDiv), o._accessibleDiv = null, i--, 0 === this.children.length && this.deactivate();
+ else {
+ n = o._accessibleDiv;
+ var a = o.hitArea,
+ s = o.worldTransform;
+ o.hitArea ? (n.style.left = (s.tx + a.x * s.a) * e + "px", n.style.top = (s.ty + a.y * s.d) * r + "px", n.style.width = a.width * s.a * e + "px", n.style.height = a.height * s.d * r + "px") : (a = o.getBounds(), this.capHitArea(a), n.style.left = a.x * e + "px", n.style.top = a.y * r + "px", n.style.width = a.width * e + "px", n.style.height = a.height * r + "px", n.title !== o.accessibleTitle && null !== o.accessibleTitle && (n.title = o.accessibleTitle), n.getAttribute("aria-label") !== o.accessibleHint && null !== o.accessibleHint && n.setAttribute("aria-label", o.accessibleHint))
+ }
+ }
+ this.renderId++
+ }
+ }, vt.prototype.capHitArea = function(t) {
+ t.x < 0 && (t.width += t.x, t.x = 0), t.y < 0 && (t.height += t.y, t.y = 0), t.x + t.width > this.renderer.width && (t.width = this.renderer.width - t.x), t.y + t.height > this.renderer.height && (t.height = this.renderer.height - t.y)
+ }, vt.prototype.addChild = function(t) {
+ var e = this.pool.pop();
+ e || ((e = document.createElement("button")).style.width = "100px", e.style.height = "100px", e.style.backgroundColor = this.debug ? "rgba(255,0,0,0.5)" : "transparent", e.style.position = "absolute", e.style.zIndex = 2, e.style.borderStyle = "none", -1 < navigator.userAgent.toLowerCase().indexOf("chrome") ? e.setAttribute("aria-live", "off") : e.setAttribute("aria-live", "polite"), navigator.userAgent.match(/rv:.*Gecko\//) ? e.setAttribute("aria-relevant", "additions") : e.setAttribute("aria-relevant", "text"), e.addEventListener("click", this._onClick.bind(this)), e.addEventListener("focus", this._onFocus.bind(this)), e.addEventListener("focusout", this._onFocusOut.bind(this))), t.accessibleTitle && null !== t.accessibleTitle ? e.title = t.accessibleTitle : t.accessibleHint && null !== t.accessibleHint || (e.title = "displayObject " + t.tabIndex), t.accessibleHint && null !== t.accessibleHint && e.setAttribute("aria-label", t.accessibleHint), t._accessibleActive = !0, (t._accessibleDiv = e).displayObject = t, this.children.push(t), this.div.appendChild(t._accessibleDiv), t._accessibleDiv.tabIndex = t.tabIndex
+ }, vt.prototype._onClick = function(t) {
+ var e = this.renderer.plugins.interaction;
+ e.dispatchEvent(t.target.displayObject, "click", e.eventData)
+ }, vt.prototype._onFocus = function(t) {
+ t.target.getAttribute("aria-live", "off") || t.target.setAttribute("aria-live", "assertive");
+ var e = this.renderer.plugins.interaction;
+ e.dispatchEvent(t.target.displayObject, "mouseover", e.eventData)
+ }, vt.prototype._onFocusOut = function(t) {
+ t.target.getAttribute("aria-live", "off") || t.target.setAttribute("aria-live", "polite");
+ var e = this.renderer.plugins.interaction;
+ e.dispatchEvent(t.target.displayObject, "mouseout", e.eventData)
+ }, vt.prototype._onKeyDown = function(t) {
+ 9 === t.keyCode && this.activate()
+ }, vt.prototype._onMouseMove = function(t) {
+ 0 === t.movementX && 0 === t.movementY || this.deactivate()
+ }, vt.prototype.destroy = function() {
+ this.destroyTouchHook(), this.div = null;
+ for (var t = 0; t < this.children.length; t++) this.children[t].div = null;
+ window.document.removeEventListener("mousemove", this._onMouseMove, !0), window.removeEventListener("keydown", this._onKeyDown), this.pool = null, this.children = null, this.renderer = null
+ };
+ var gt = function(t) {
+ this.items = [], this._name = t
+ },
+ yt = {
+ empty: {
+ configurable: !0
+ },
+ name: {
+ configurable: !0
+ }
+ };
+ gt.prototype.emit = function(t, e, r, n, i, o, a, s) {
+ if (8 < arguments.length) throw new Error("max arguments reached");
+ for (var u = this.name, h = this.items, c = 0, l = h.length; c < l; c++) h[c][u](t, e, r, n, i, o, a, s);
+ return this
+ }, gt.prototype.add = function(t) {
+ return t[this._name] && (this.remove(t), this.items.push(t)), this
+ }, gt.prototype.remove = function(t) {
+ var e = this.items.indexOf(t);
+ return -1 !== e && this.items.splice(e, 1), this
+ }, gt.prototype.contains = function(t) {
+ return -1 !== this.items.indexOf(t)
+ }, gt.prototype.removeAll = function() {
+ return this.items.length = 0, this
+ }, gt.prototype.destroy = function() {
+ this.removeAll(), this.items = null, this._name = null
+ }, yt.empty.get = function() {
+ return 0 === this.items.length
+ }, yt.name.get = function() {
+ return this._name
+ }, Object.defineProperties(gt.prototype, yt), gt.prototype.dispatch = gt.prototype.emit, gt.prototype.run = gt.prototype.emit, M.TARGET_FPMS = .06;
+ var _t = {
+ INTERACTION: 50,
+ HIGH: 25,
+ NORMAL: 0,
+ LOW: -25,
+ UTILITY: -50
+ },
+ bt = function(t, e, r, n) {
+ void 0 === e && (e = null), void 0 === r && (r = 0), void 0 === n && (n = !1), this.fn = t, this.context = e, this.priority = r, this.once = n, this.next = null, this.previous = null, this._destroyed = !1
+ };
+ bt.prototype.match = function(t, e) {
+ return e = e || null, this.fn === t && this.context === e
+ }, bt.prototype.emit = function(t) {
+ this.fn && (this.context ? this.fn.call(this.context, t) : this.fn(t));
+ var e = this.next;
+ return this.once && this.destroy(!0), this._destroyed && (this.next = null), e
+ }, bt.prototype.connect = function(t) {
+ (this.previous = t).next && (t.next.previous = this), this.next = t.next, t.next = this
+ }, bt.prototype.destroy = function(t) {
+ void 0 === t && (t = !1), this._destroyed = !0, this.fn = null, this.context = null, this.previous && (this.previous.next = this.next), this.next && (this.next.previous = this.previous);
+ var e = this.next;
+ return this.next = t ? null : e, this.previous = null, e
+ };
+ var xt = function() {
+ var e = this;
+ this._head = new bt(null, null, 1 / 0), this._requestId = null, this._maxElapsedMS = 100, this._minElapsedMS = 0, this.autoStart = !1, this.deltaTime = 1, this.deltaMS = 1 / M.TARGET_FPMS, this.elapsedMS = 1 / M.TARGET_FPMS, this.lastTime = -1, this.speed = 1, this.started = !1, this._protected = !1, this._tick = function(t) {
+ e._requestId = null, e.started && (e.update(t), e.started && null === e._requestId && e._head.next && (e._requestId = requestAnimationFrame(e._tick)))
+ }
+ },
+ wt = {
+ FPS: {
+ configurable: !0
+ },
+ minFPS: {
+ configurable: !0
+ },
+ maxFPS: {
+ configurable: !0
+ }
+ },
+ Tt = {
+ shared: {
+ configurable: !0
+ },
+ system: {
+ configurable: !0
+ }
+ };
+ xt.prototype._requestIfNeeded = function() {
+ null === this._requestId && this._head.next && (this.lastTime = performance.now(), this._requestId = requestAnimationFrame(this._tick))
+ }, xt.prototype._cancelIfNeeded = function() {
+ null !== this._requestId && (cancelAnimationFrame(this._requestId), this._requestId = null)
+ }, xt.prototype._startIfPossible = function() {
+ this.started ? this._requestIfNeeded() : this.autoStart && this.start()
+ }, xt.prototype.add = function(t, e, r) {
+ return void 0 === r && (r = _t.NORMAL), this._addListener(new bt(t, e, r))
+ }, xt.prototype.addOnce = function(t, e, r) {
+ return void 0 === r && (r = _t.NORMAL), this._addListener(new bt(t, e, r, !0))
+ }, xt.prototype._addListener = function(t) {
+ var e = this._head.next,
+ r = this._head;
+ if (e) {
+ for (; e;) {
+ if (t.priority > e.priority) {
+ t.connect(r);
+ break
+ }
+ e = (r = e).next
+ }
+ t.previous || t.connect(r)
+ } else t.connect(r);
+ return this._startIfPossible(), this
+ }, xt.prototype.remove = function(t, e) {
+ for (var r = this._head.next; r;) r = r.match(t, e) ? r.destroy() : r.next;
+ return this._head.next || this._cancelIfNeeded(), this
+ }, xt.prototype.start = function() {
+ this.started || (this.started = !0, this._requestIfNeeded())
+ }, xt.prototype.stop = function() {
+ this.started && (this.started = !1, this._cancelIfNeeded())
+ }, xt.prototype.destroy = function() {
+ if (!this._protected) {
+ this.stop();
+ for (var t = this._head.next; t;) t = t.destroy(!0);
+ this._head.destroy(), this._head = null
+ }
+ }, xt.prototype.update = function(t) {
+ var e;
+ if (void 0 === t && (t = performance.now()), t > this.lastTime) {
+ if ((e = this.elapsedMS = t - this.lastTime) > this._maxElapsedMS && (e = this._maxElapsedMS), e *= this.speed, this._minElapsedMS && e + 1 < this._minElapsedMS) return;
+ this.deltaMS = e, this.deltaTime = this.deltaMS * M.TARGET_FPMS;
+ for (var r = this._head, n = r.next; n;) n = n.emit(this.deltaTime);
+ r.next || this._cancelIfNeeded()
+ } else this.deltaTime = this.deltaMS = this.elapsedMS = 0;
+ this.lastTime = t
+ }, wt.FPS.get = function() {
+ return 1e3 / this.elapsedMS
+ }, wt.minFPS.get = function() {
+ return 1e3 / this._maxElapsedMS
+ }, wt.minFPS.set = function(t) {
+ var e = Math.min(this.maxFPS, t),
+ r = Math.min(Math.max(0, e) / 1e3, M.TARGET_FPMS);
+ this._maxElapsedMS = 1 / r
+ }, wt.maxFPS.get = function() {
+ return this._minElapsedMS ? 1e3 / this._minElapsedMS : 1e3 * M.TARGET_FPMS
+ }, wt.maxFPS.set = function(t) {
+ if (t / 1e3 >= M.TARGET_FPMS) this._minElapsedMS = 0;
+ else {
+ var e = Math.max(this.minFPS, t),
+ r = Math.min(Math.max(1, e) / 1e3, M.TARGET_FPMS);
+ this._minElapsedMS = 1 / r
+ }
+ }, Tt.shared.get = function() {
+ if (!xt._shared) {
+ var t = xt._shared = new xt;
+ t.autoStart = !0, t._protected = !0
+ }
+ return xt._shared
+ }, Tt.system.get = function() {
+ if (!xt._system) {
+ var t = xt._system = new xt;
+ t.autoStart = !0, t._protected = !0
+ }
+ return xt._system
+ }, Object.defineProperties(xt.prototype, wt), Object.defineProperties(xt, Tt);
+ var St = function() {};
+ St.init = function(t) {
+ var e = this;
+ t = Object.assign({
+ autoStart: !0,
+ sharedTicker: !1
+ }, t), Object.defineProperty(this, "ticker", {
+ set: function(t) {
+ this._ticker && this._ticker.remove(this.render, this), (this._ticker = t) && t.add(this.render, this, _t.LOW)
+ },
+ get: function() {
+ return this._ticker
+ }
+ }), this.stop = function() {
+ e._ticker.stop()
+ }, this.start = function() {
+ e._ticker.start()
+ }, this._ticker = null, this.ticker = t.sharedTicker ? xt.shared : new xt, t.autoStart && this.start()
+ }, St.destroy = function() {
+ if (this._ticker) {
+ var t = this._ticker;
+ this.ticker = null, t.destroy()
+ }
+ };
+ var Mt = function(t, e) {
+ void 0 === t && (t = 0), void 0 === e && (e = 0), this._width = t, this._height = e, this.destroyed = !1, this.internal = !1, this.onResize = new gt("setRealSize", 2), this.onUpdate = new gt("update")
+ },
+ Et = {
+ valid: {
+ configurable: !0
+ },
+ width: {
+ configurable: !0
+ },
+ height: {
+ configurable: !0
+ }
+ };
+ Mt.prototype.bind = function(t) {
+ this.onResize.add(t), this.onUpdate.add(t), (this._width || this._height) && this.onResize.run(this._width, this._height)
+ }, Mt.prototype.unbind = function(t) {
+ this.onResize.remove(t), this.onUpdate.remove(t)
+ }, Mt.prototype.resize = function(t, e) {
+ t === this._width && e === this._height || (this._width = t, this._height = e, this.onResize.run(t, e))
+ }, Et.valid.get = function() {
+ return !!this._width && !!this._height
+ }, Mt.prototype.update = function() {
+ this.destroyed || this.onUpdate.run()
+ }, Mt.prototype.load = function() {
+ return Promise.resolve()
+ }, Et.width.get = function() {
+ return this._width
+ }, Et.height.get = function() {
+ return this._height
+ }, Mt.prototype.upload = function(t, e, r) {
+ return !1
+ }, Mt.prototype.style = function(t, e, r) {
+ return !1
+ }, Mt.prototype.dispose = function() {}, Mt.prototype.destroy = function() {
+ this.destroyed || (this.onResize.removeAll(), this.onResize = null, this.onUpdate.removeAll(), this.onUpdate = null, this.destroyed = !0, this.dispose())
+ }, Object.defineProperties(Mt.prototype, Et);
+ var At = function(e) {
+ function BaseImageResource(t) {
+ e.call(this, t.width, t.height), this.source = t
+ }
+ return e && (BaseImageResource.__proto__ = e), ((BaseImageResource.prototype = Object.create(e && e.prototype)).constructor = BaseImageResource).crossOrigin = function(t, e, r) {
+ void 0 === r && 0 !== e.indexOf("data:") ? t.crossOrigin = determineCrossOrigin(e) : !1 !== r && (t.crossOrigin = "string" == typeof r ? r : "anonymous")
+ }, BaseImageResource.prototype.upload = function(t, e, r, n) {
+ var i = t.gl,
+ o = e.realWidth,
+ a = e.realHeight;
+ return n = n || this.source, i.pixelStorei(i.UNPACK_PREMULTIPLY_ALPHA_WEBGL, e.premultiplyAlpha), e.target === i.TEXTURE_2D && r.width === o && r.height === a ? i.texSubImage2D(i.TEXTURE_2D, 0, 0, 0, e.format, e.type, n) : (r.width = o, r.height = a, i.texImage2D(e.target, 0, e.format, e.format, e.type, n)), !0
+ }, BaseImageResource.prototype.dispose = function() {
+ this.source = null
+ }, BaseImageResource
+ }(Mt),
+ Pt = function(a) {
+ function ImageResource(t, e) {
+ if (e = e || {}, !(t instanceof HTMLImageElement)) {
+ var r = new Image;
+ a.crossOrigin(r, t, e.crossorigin), r.src = t, t = r
+ }
+ a.call(this, t), this.url = t.src, this._process = null, this.preserveBitmap = !1, this.createBitmap = !1 !== e.createBitmap && M.CREATE_IMAGE_BITMAP && !!window.createImageBitmap, this.premultiplyAlpha = !1 !== e.premultiplyAlpha, this.bitmap = null, this._load = null, !1 !== e.autoLoad && this.load()
+ }
+ return a && (ImageResource.__proto__ = a), ((ImageResource.prototype = Object.create(a && a.prototype)).constructor = ImageResource).prototype.load = function(t) {
+ var n = this;
+ return void 0 !== t && (this.createBitmap = t), this._load || (this._load = new Promise(function(t) {
+ n.url = n.source.src;
+ var e = n.source,
+ r = function() {
+ n.destroyed || (e.onload = null, e.onerror = null, n.resize(e.width, e.height), n._load = null, n.createBitmap ? t(n.process()) : t(n))
+ };
+ e.complete && e.src ? r() : e.onload = r
+ })), this._load
+ }, ImageResource.prototype.process = function() {
+ var e = this;
+ return null !== this._process ? this._process : null === this.bitmap && window.createImageBitmap ? (this._process = window.createImageBitmap(this.source, 0, 0, this.source.width, this.source.height, {
+ premultiplyAlpha: this.premultiplyAlpha ? "premultiply" : "none"
+ }).then(function(t) {
+ return e.destroyed ? Promise.reject() : (e.bitmap = t, e.update(), e._process = null, Promise.resolve(e))
+ }), this._process) : Promise.resolve(this)
+ }, ImageResource.prototype.upload = function(t, e, r) {
+ if (e.premultiplyAlpha = this.premultiplyAlpha, !this.createBitmap) return a.prototype.upload.call(this, t, e, r);
+ if (!this.bitmap && (this.process(), !this.bitmap)) return !1;
+ if (a.prototype.upload.call(this, t, e, r, this.bitmap), !this.preserveBitmap) {
+ var n = !0;
+ for (var i in e._glTextures) {
+ var o = e._glTextures[i];
+ if (o !== r && o.dirtyId !== e.dirtyId) {
+ n = !1;
+ break
+ }
+ }
+ n && (this.bitmap.close && this.bitmap.close(), this.bitmap = null)
+ }
+ return !0
+ }, ImageResource.prototype.dispose = function() {
+ a.prototype.dispose.call(this), this.bitmap && (this.bitmap.close(), this.bitmap = null), this._process = null, this._load = null
+ }, ImageResource
+ }(At),
+ It = [];
+
+ function autoDetectResource(t, e) {
+ if (!t) return null;
+ var r = "";
+ if ("string" == typeof t) {
+ var n = /\.(\w{3,4})(?:$|\?|#)/i.exec(t);
+ n && (r = n[1].toLowerCase())
+ }
+ for (var i = It.length - 1; 0 <= i; --i) {
+ var o = It[i];
+ if (o.test && o.test(t, r)) return new o(t, e)
+ }
+ return new Pt(t, e)
+ }
+ var Ot = function(o) {
+ function BufferResource(t, e) {
+ var r = e || {},
+ n = r.width,
+ i = r.height;
+ if (!n || !i) throw new Error("BufferResource width or height invalid");
+ o.call(this, n, i), this.data = t
+ }
+ return o && (BufferResource.__proto__ = o), ((BufferResource.prototype = Object.create(o && o.prototype)).constructor = BufferResource).prototype.upload = function(t, e, r) {
+ var n = t.gl;
+ if (n.pixelStorei(n.UNPACK_PREMULTIPLY_ALPHA_WEBGL, e.premultiplyAlpha), r.width === e.width && r.height === e.height) n.texSubImage2D(e.target, 0, 0, 0, e.width, e.height, e.format, e.type, this.data);
+ else {
+ r.width = e.width, r.height = e.height;
+ var i = e.format;
+ 2 === t.context.webGLVersion && e.type === t.gl.FLOAT && e.format === t.gl.RGBA && (i = t.gl.RGBA32F), n.texImage2D(e.target, 0, i, e.width, e.height, 0, e.format, e.type, this.data)
+ }
+ return !0
+ }, BufferResource.prototype.dispose = function() {
+ this.data = null
+ }, BufferResource.test = function(t) {
+ return t instanceof Float32Array || t instanceof Uint8Array || t instanceof Uint32Array
+ }, BufferResource
+ }(Mt),
+ Ct = {
+ scaleMode: T.NEAREST,
+ format: _.RGBA,
+ premultiplyAlpha: !1
+ },
+ Rt = function(d) {
+ function BaseTexture(t, e) {
+ void 0 === t && (t = null), void 0 === e && (e = null), d.call(this);
+ var r = (e = e || {}).premultiplyAlpha,
+ n = e.mipmap,
+ i = e.scaleMode,
+ o = e.width,
+ a = e.height,
+ s = e.wrapMode,
+ u = e.format,
+ h = e.type,
+ c = e.target,
+ l = e.resolution,
+ f = e.resourceOptions;
+ !t || t instanceof Mt || ((t = autoDetectResource(t, f)).internal = !0), this.width = o || 0, this.height = a || 0, this.resolution = l || M.RESOLUTION, this.mipmap = void 0 !== n ? n : M.MIPMAP_TEXTURES, this.wrapMode = s || M.WRAP_MODE, this.scaleMode = void 0 !== i ? i : M.SCALE_MODE, this.format = u || _.RGBA, this.type = h || w.UNSIGNED_BYTE, this.target = c || b.TEXTURE_2D, this.premultiplyAlpha = !1 !== r, this.uid = uid(), this.touched = 0, this.isPowerOfTwo = !1, this._refreshPOT(), this._glTextures = {}, this.dirtyId = 0, this.dirtyStyleId = 0, this.cacheId = null, this.valid = 0 < o && 0 < a, this.textureCacheIds = [], this.destroyed = !1, this.resource = null, this.setResource(t)
+ }
+ d && (BaseTexture.__proto__ = d), (BaseTexture.prototype = Object.create(d && d.prototype)).constructor = BaseTexture;
+ var t = {
+ realWidth: {
+ configurable: !0
+ },
+ realHeight: {
+ configurable: !0
+ }
+ };
+ return t.realWidth.get = function() {
+ return this.width * this.resolution
+ }, t.realHeight.get = function() {
+ return this.height * this.resolution
+ }, BaseTexture.prototype.setStyle = function(t, e) {
+ var r;
+ return void 0 !== t && t !== this.scaleMode && (this.scaleMode = t, r = !0), void 0 !== e && e !== this.mipmap && (this.mipmap = e, r = !0), r && this.dirtyStyleId++, this
+ }, BaseTexture.prototype.setSize = function(t, e, r) {
+ return this.resolution = r || this.resolution, this.width = t, this.height = e, this._refreshPOT(), this.update(), this
+ }, BaseTexture.prototype.setRealSize = function(t, e, r) {
+ return this.resolution = r || this.resolution, this.width = t / this.resolution, this.height = e / this.resolution, this._refreshPOT(), this.update(), this
+ }, BaseTexture.prototype._refreshPOT = function() {
+ this.isPowerOfTwo = isPow2(this.realWidth) && isPow2(this.realHeight)
+ }, BaseTexture.prototype.setResolution = function(t) {
+ var e = this.resolution;
+ return e === t || (this.resolution = t, this.valid && (this.width = this.width * e / t, this.height = this.height * e / t, this.emit("update")), this._refreshPOT()), this
+ }, BaseTexture.prototype.setResource = function(t) {
+ if (this.resource === t) return this;
+ if (this.resource) throw new Error("Resource can be set only once");
+ return t.bind(this), this.resource = t, this
+ }, BaseTexture.prototype.update = function() {
+ this.valid ? (this.dirtyId++, this.dirtyStyleId++, this.emit("update", this)) : 0 < this.width && 0 < this.height && (this.valid = !0, this.emit("loaded", this), this.emit("update", this))
+ }, BaseTexture.prototype.destroy = function() {
+ this.resource && (this.resource.unbind(this), this.resource.internal && this.resource.destroy(), this.resource = null), this.cacheId && (delete k[this.cacheId], delete F[this.cacheId], this.cacheId = null), this.dispose(), BaseTexture.removeFromCache(this), this.textureCacheIds = null, this.destroyed = !0
+ }, BaseTexture.prototype.dispose = function() {
+ this.emit("dispose", this)
+ }, BaseTexture.from = function(t, e) {
+ var r = null;
+ r = "string" == typeof t ? t : (t._pixiId || (t._pixiId = "pixiid_" + uid()), t._pixiId);
+ var n = k[r];
+ return n || ((n = new BaseTexture(t, e)).cacheId = r, BaseTexture.addToCache(n, r)), n
+ }, BaseTexture.fromBuffer = function(t, e, r, n) {
+ t = t || new Float32Array(e * r * 4);
+ var i = new Ot(t, {
+ width: e,
+ height: r
+ }),
+ o = t instanceof Float32Array ? w.FLOAT : w.UNSIGNED_BYTE;
+ return new BaseTexture(i, Object.assign(Ct, n || {
+ width: e,
+ height: r,
+ type: o
+ }))
+ }, BaseTexture.addToCache = function(t, e) {
+ e && (-1 === t.textureCacheIds.indexOf(e) && t.textureCacheIds.push(e), k[e], k[e] = t)
+ }, BaseTexture.removeFromCache = function(t) {
+ if ("string" == typeof t) {
+ var e = k[t];
+ if (e) {
+ var r = e.textureCacheIds.indexOf(t);
+ return -1 < r && e.textureCacheIds.splice(r, 1), delete k[t], e
+ }
+ } else if (t && t.textureCacheIds) {
+ for (var n = 0; n < t.textureCacheIds.length; ++n) delete k[t.textureCacheIds[n]];
+ return t.textureCacheIds.length = 0, t
+ }
+ return null
+ }, Object.defineProperties(BaseTexture.prototype, t), BaseTexture
+ }(l.a),
+ Dt = function(s) {
+ function ArrayResource(t, e) {
+ var r;
+ e = e || {};
+ var n = t;
+ Array.isArray(t) && (n = (r = t).length), s.call(this, e.width, e.height), this.items = [], this.itemDirtyIds = [];
+ for (var i = 0; i < n; i++) {
+ var o = new Rt;
+ this.items.push(o), this.itemDirtyIds.push(-1)
+ }
+ if (this.length = n, this._load = null, r)
+ for (var a = 0; a < n; a++) this.addResourceAt(autoDetectResource(r[a], e), a)
+ }
+ return s && (ArrayResource.__proto__ = s), ((ArrayResource.prototype = Object.create(s && s.prototype)).constructor = ArrayResource).prototype.dispose = function() {
+ for (var t = 0, e = this.length; t < e; t++) this.items[t].destroy();
+ this.items = null, this.itemDirtyIds = null, this._load = null
+ }, ArrayResource.prototype.addResourceAt = function(t, e) {
+ if (!this.items[e]) throw new Error("Index " + e + " is out of bounds");
+ return t.valid && !this.valid && this.resize(t.width, t.height), this.items[e].setResource(t), this
+ }, ArrayResource.prototype.bind = function(t) {
+ s.prototype.bind.call(this, t), t.target = b.TEXTURE_2D_ARRAY;
+ for (var e = 0; e < this.length; e++) this.items[e].on("update", t.update, t)
+ }, ArrayResource.prototype.unbind = function(t) {
+ s.prototype.unbind.call(this, t);
+ for (var e = 0; e < this.length; e++) this.items[e].off("update", t.update, t)
+ }, ArrayResource.prototype.load = function() {
+ var n = this;
+ if (this._load) return this._load;
+ var i = this.items.map(function(t) {
+ return t.resource
+ }),
+ t = i.map(function(t) {
+ return t.load()
+ });
+ return this._load = Promise.all(t).then(function() {
+ var t = i[0],
+ e = t.width,
+ r = t.height;
+ return n.resize(e, r), Promise.resolve(n)
+ }), this._load
+ }, ArrayResource.prototype.upload = function(t, e, r) {
+ var n = this.length,
+ i = this.itemDirtyIds,
+ o = this.items,
+ a = t.gl;
+ r.dirtyId < 0 && a.texImage3D(a.TEXTURE_2D_ARRAY, 0, e.format, this._width, this._height, n, 0, e.format, e.type, null);
+ for (var s = 0; s < n; s++) {
+ var u = o[s];
+ i[s] < u.dirtyId && (i[s] = u.dirtyId, u.valid && a.texSubImage3D(a.TEXTURE_2D_ARRAY, 0, 0, 0, s, u.resource.width, u.resource.height, 1, e.format, e.type, u.resource.source))
+ }
+ return !0
+ }, ArrayResource
+ }(Mt),
+ Ft = function(t) {
+ function CanvasResource() {
+ t.apply(this, arguments)
+ }
+ return t && (CanvasResource.__proto__ = t), ((CanvasResource.prototype = Object.create(t && t.prototype)).constructor = CanvasResource).test = function(t) {
+ return t instanceof HTMLCanvasElement
+ }, CanvasResource
+ }(At),
+ kt = function(n) {
+ function CubeResource(t, e) {
+ if (e = e || {}, n.call(this, t, e), this.length !== CubeResource.SIDES) throw new Error("Invalid length. Got " + this.length + ", expected 6");
+ for (var r = 0; r < CubeResource.SIDES; r++) this.items[r].target = b.TEXTURE_CUBE_MAP_POSITIVE_X + r;
+ !1 !== e.autoLoad && this.load()
+ }
+ return n && (CubeResource.__proto__ = n), ((CubeResource.prototype = Object.create(n && n.prototype)).constructor = CubeResource).prototype.bind = function(t) {
+ n.prototype.bind.call(this, t), t.target = b.TEXTURE_CUBE_MAP
+ }, CubeResource.prototype.upload = function(t, e, r) {
+ for (var n = this.itemDirtyIds, i = 0; i < CubeResource.SIDES; i++) {
+ var o = this.items[i];
+ n[i] < o.dirtyId && (n[i] = o.dirtyId, o.valid && o.resource.upload(t, o, r))
+ }
+ return !0
+ }, CubeResource
+ }(Dt);
+ kt.SIDES = 6;
+ var Lt = function(r) {
+ function SVGResource(t, e) {
+ e = e || {}, r.call(this, document.createElement("canvas")), this.svg = t, this.scale = e.scale || 1, this._resolve = null, this._load = null, !1 !== e.autoLoad && this.load()
+ }
+ return r && (SVGResource.__proto__ = r), ((SVGResource.prototype = Object.create(r && r.prototype)).constructor = SVGResource).prototype.load = function() {
+ var r = this;
+ return this._load || (this._load = new Promise(function(t) {
+ r._resolve = function() {
+ r.resize(r.source.width, r.source.height), t(r)
+ }, /^\]*(?:\s(width|height)=('|")(\d*(?:\.\d+)?)(?:px)?('|"))[^>]*(?:\s(width|height)=('|")(\d*(?:\.\d+)?)(?:px)?('|"))[^>]*>/i;
+ var Nt = function(c) {
+ function VideoResource(t, e) {
+ if (e = e || {}, !(t instanceof HTMLVideoElement)) {
+ var r = document.createElement("video");
+ r.setAttribute("webkit-playsinline", ""), r.setAttribute("playsinline", ""), "string" == typeof t && (t = [t]), c.crossOrigin(r, t[0].src || t[0], e.crossorigin);
+ for (var n = 0; n < t.length; ++n) {
+ var i = document.createElement("source"),
+ o = t[n],
+ a = o.src,
+ s = o.mime,
+ u = (a = a || t[n]).split("?").shift().toLowerCase(),
+ h = u.substr(u.lastIndexOf(".") + 1);
+ s = s || "video/" + h, i.src = a, i.type = s, r.appendChild(i)
+ }
+ t = r
+ }
+ c.call(this, t), this._autoUpdate = !0, this._isAutoUpdating = !1, this._updateFPS = e.updateFPS || 0, this._msToNextUpdate = 0, this.autoPlay = !1 !== e.autoPlay, this._load = null, this._resolve = null, this._onCanPlay = this._onCanPlay.bind(this), !1 !== e.autoLoad && this.load()
+ }
+ c && (VideoResource.__proto__ = c);
+ var t = {
+ autoUpdate: {
+ configurable: !0
+ },
+ updateFPS: {
+ configurable: !0
+ }
+ };
+ return ((VideoResource.prototype = Object.create(c && c.prototype)).constructor = VideoResource).prototype.update = function(t) {
+ if (void 0 === t && (t = 0), !this.destroyed) {
+ var e = xt.shared.elapsedMS * this.source.playbackRate;
+ this._msToNextUpdate = Math.floor(this._msToNextUpdate - e), (!this._updateFPS || this._msToNextUpdate <= 0) && (c.prototype.update.call(this, t), this._msToNextUpdate = this._updateFPS ? Math.floor(1e3 / this._updateFPS) : 0)
+ }
+ }, VideoResource.prototype.load = function() {
+ var e = this;
+ if (this._load) return this._load;
+ var r = this.source;
+ return (r.readyState === r.HAVE_ENOUGH_DATA || r.readyState === r.HAVE_FUTURE_DATA) && r.width && r.height && (r.complete = !0), r.addEventListener("play", this._onPlayStart.bind(this)), r.addEventListener("pause", this._onPlayStop.bind(this)), this._isSourceReady() ? this._onCanPlay() : (r.addEventListener("canplay", this._onCanPlay), r.addEventListener("canplaythrough", this._onCanPlay)), this._load = new Promise(function(t) {
+ e.valid ? t(e) : (e._resolve = t, r.load())
+ }), this._load
+ }, VideoResource.prototype._isSourcePlaying = function() {
+ var t = this.source;
+ return 0 < t.currentTime && !1 === t.paused && !1 === t.ended && 2 < t.readyState
+ }, VideoResource.prototype._isSourceReady = function() {
+ return 3 === this.source.readyState || 4 === this.source.readyState
+ }, VideoResource.prototype._onPlayStart = function() {
+ this.valid || this._onCanPlay(), !this._isAutoUpdating && this.autoUpdate && (xt.shared.add(this.update, this), this._isAutoUpdating = !0)
+ }, VideoResource.prototype._onPlayStop = function() {
+ this._isAutoUpdating && (xt.shared.remove(this.update, this), this._isAutoUpdating = !1)
+ }, VideoResource.prototype._onCanPlay = function() {
+ var t = this.source;
+ t.removeEventListener("canplay", this._onCanPlay), t.removeEventListener("canplaythrough", this._onCanPlay);
+ var e = this.valid;
+ this.resize(t.videoWidth, t.videoHeight), !e && this._resolve && (this._resolve(this), this._resolve = null), this._isSourcePlaying() ? this._onPlayStart() : this.autoPlay && t.play()
+ }, VideoResource.prototype.dispose = function() {
+ this._isAutoUpdating && xt.shared.remove(this.update, this), this.source && (this.source.pause(), this.source.src = "", this.source.load()), c.prototype.dispose.call(this)
+ }, t.autoUpdate.get = function() {
+ return this._autoUpdate
+ }, t.autoUpdate.set = function(t) {
+ t !== this._autoUpdate && (this._autoUpdate = t, !this._autoUpdate && this._isAutoUpdating ? (xt.shared.remove(this.update, this), this._isAutoUpdating = !1) : this._autoUpdate && !this._isAutoUpdating && (xt.shared.add(this.update, this), this._isAutoUpdating = !0))
+ }, t.updateFPS.get = function() {
+ return this._updateFPS
+ }, t.updateFPS.set = function(t) {
+ t !== this._updateFPS && (this._updateFPS = t)
+ }, VideoResource.test = function(t, e) {
+ return t instanceof HTMLVideoElement || -1 < VideoResource.TYPES.indexOf(e)
+ }, Object.defineProperties(VideoResource.prototype, t), VideoResource
+ }(At);
+ Nt.TYPES = ["mp4", "m4v", "webm", "ogg", "ogv", "h264", "avi", "mov"], It.push(Pt, Ft, Nt, Lt, Ot, kt, Dt);
+ var Bt = {
+ INSTALLED: It,
+ autoDetectResource: autoDetectResource,
+ ArrayResource: Dt,
+ BufferResource: Ot,
+ CanvasResource: Ft,
+ CubeResource: kt,
+ ImageResource: Pt,
+ SVGResource: Lt,
+ VideoResource: Nt,
+ Resource: Mt,
+ BaseImageResource: At
+ },
+ Ut = function(t) {
+ this.renderer = t, this.renderer.runners.contextChange.add(this)
+ };
+ Ut.prototype.contextChange = function(t) {}, Ut.prototype.destroy = function() {
+ this.renderer.runners.contextChange.remove(this), this.renderer = null
+ };
+ var Gt = function(t) {
+ function DepthResource() {
+ t.apply(this, arguments)
+ }
+ return t && (DepthResource.__proto__ = t), ((DepthResource.prototype = Object.create(t && t.prototype)).constructor = DepthResource).prototype.upload = function(t, e, r) {
+ var n = t.gl;
+ return n.pixelStorei(n.UNPACK_PREMULTIPLY_ALPHA_WEBGL, e.premultiplyAlpha), r.width === e.width && r.height === e.height ? n.texSubImage2D(e.target, 0, 0, 0, e.width, e.height, e.format, e.type, this.data) : (r.width = e.width, r.height = e.height, n.texImage2D(e.target, 0, n.DEPTH_COMPONENT16, e.width, e.height, 0, e.format, e.type, this.data)), !0
+ }, DepthResource
+ }(Ot),
+ jt = function(t, e) {
+ this.width = Math.ceil(t || 100), this.height = Math.ceil(e || 100), this.stencil = !1, this.depth = !1, this.dirtyId = 0, this.dirtyFormat = 0, this.dirtySize = 0, this.depthTexture = null, this.colorTextures = [], this.glFramebuffers = {}, this.disposeRunner = new gt("disposeFramebuffer", 2)
+ },
+ zt = {
+ colorTexture: {
+ configurable: !0
+ }
+ };
+ zt.colorTexture.get = function() {
+ return this.colorTextures[0]
+ }, jt.prototype.addColorTexture = function(t, e) {
+ return void 0 === t && (t = 0), this.colorTextures[t] = e || new Rt(null, {
+ scaleMode: 0,
+ resolution: 1,
+ mipmap: !1,
+ width: this.width,
+ height: this.height
+ }), this.dirtyId++, this.dirtyFormat++, this
+ }, jt.prototype.addDepthTexture = function(t) {
+ return this.depthTexture = t || new Rt(new Gt(null, {
+ width: this.width,
+ height: this.height
+ }), {
+ scaleMode: 0,
+ resolution: 1,
+ width: this.width,
+ height: this.height,
+ mipmap: !1,
+ format: _.DEPTH_COMPONENT,
+ type: w.UNSIGNED_SHORT
+ }), this.dirtyId++, this.dirtyFormat++, this
+ }, jt.prototype.enableDepth = function() {
+ return this.depth = !0, this.dirtyId++, this.dirtyFormat++, this
+ }, jt.prototype.enableStencil = function() {
+ return this.stencil = !0, this.dirtyId++, this.dirtyFormat++, this
+ }, jt.prototype.resize = function(t, e) {
+ if (t = Math.ceil(t), e = Math.ceil(e), t !== this.width || e !== this.height) {
+ this.width = t, this.height = e, this.dirtyId++, this.dirtySize++;
+ for (var r = 0; r < this.colorTextures.length; r++) {
+ var n = this.colorTextures[r],
+ i = n.resolution;
+ n.setSize(t / i, e / i)
+ }
+ if (this.depthTexture) {
+ var o = this.depthTexture.resolution;
+ this.depthTexture.setSize(t / o, e / o)
+ }
+ }
+ }, jt.prototype.dispose = function() {
+ this.disposeRunner.run(this, !1)
+ }, Object.defineProperties(jt.prototype, zt);
+ var Xt = function(i) {
+ function BaseRenderTexture(t) {
+ "number" == typeof t && (t = {
+ width: arguments[0],
+ height: arguments[1],
+ scaleMode: arguments[2],
+ resolution: arguments[3]
+ });
+ i.call(this, null, t);
+ var e = t || {},
+ r = e.width,
+ n = e.height;
+ this.mipmap = !1, this.width = Math.ceil(r) || 100, this.height = Math.ceil(n) || 100, this.valid = !0, this._canvasRenderTarget = null, this.clearColor = [0, 0, 0, 0], this.framebuffer = new jt(this.width * this.resolution, this.height * this.resolution).addColorTexture(0, this).enableStencil(), this.stencilMaskStack = [], this.filterStack = [{}]
+ }
+ return i && (BaseRenderTexture.__proto__ = i), ((BaseRenderTexture.prototype = Object.create(i && i.prototype)).constructor = BaseRenderTexture).prototype.resize = function(t, e) {
+ t = Math.ceil(t), e = Math.ceil(e), this.framebuffer.resize(t * this.resolution, e * this.resolution)
+ }, BaseRenderTexture.prototype.dispose = function() {
+ this.framebuffer.dispose(), i.prototype.dispose.call(this)
+ }, BaseRenderTexture.prototype.destroy = function() {
+ i.prototype.destroy.call(this, !0), this.framebuffer = null, this.renderer = null
+ }, BaseRenderTexture
+ }(Rt),
+ Vt = function() {
+ this.x0 = 0, this.y0 = 0, this.x1 = 1, this.y1 = 0, this.x2 = 1, this.y2 = 1, this.x3 = 0, this.y3 = 1, this.uvsFloat32 = new Float32Array(8)
+ };
+ Vt.prototype.set = function(t, e, r) {
+ var n = e.width,
+ i = e.height;
+ if (r) {
+ var o = t.width / 2 / n,
+ a = t.height / 2 / i,
+ s = t.x / n + o,
+ u = t.y / i + a;
+ r = rt.add(r, rt.NW), this.x0 = s + o * rt.uX(r), this.y0 = u + a * rt.uY(r), r = rt.add(r, 2), this.x1 = s + o * rt.uX(r), this.y1 = u + a * rt.uY(r), r = rt.add(r, 2), this.x2 = s + o * rt.uX(r), this.y2 = u + a * rt.uY(r), r = rt.add(r, 2), this.x3 = s + o * rt.uX(r), this.y3 = u + a * rt.uY(r)
+ } else this.x0 = t.x / n, this.y0 = t.y / i, this.x1 = (t.x + t.width) / n, this.y1 = t.y / i, this.x2 = (t.x + t.width) / n, this.y2 = (t.y + t.height) / i, this.x3 = t.x / n, this.y3 = (t.y + t.height) / i;
+ this.uvsFloat32[0] = this.x0, this.uvsFloat32[1] = this.y0, this.uvsFloat32[2] = this.x1, this.uvsFloat32[3] = this.y1, this.uvsFloat32[4] = this.x2, this.uvsFloat32[5] = this.y2, this.uvsFloat32[6] = this.x3, this.uvsFloat32[7] = this.y3
+ };
+ var qt = new Vt,
+ Ht = function(a) {
+ function Texture(t, e, r, n, i, o) {
+ if (a.call(this), this.noFrame = !1, e || (this.noFrame = !0, e = new ot(0, 0, 1, 1)), t instanceof Texture && (t = t.baseTexture), this.baseTexture = t, this._frame = e, this.trim = n, this.valid = !1, this.requiresUpdate = !1, this._uvs = qt, this.uvMatrix = null, this.orig = r || e, this._rotate = Number(i || 0), !0 === i) this._rotate = 2;
+ else if (this._rotate % 2 != 0) throw new Error("attempt to use diamond-shaped UVs. If you are sure, set rotation manually");
+ t.valid ? (this.noFrame && (e = new ot(0, 0, t.width, t.height), t.on("update", this.onBaseTextureUpdated, this)), this.frame = e) : t.once("loaded", this.onBaseTextureUpdated, this), this.defaultAnchor = o ? new q(o.x, o.y) : new q(0, 0), this._updateID = 0, this.textureCacheIds = []
+ }
+ a && (Texture.__proto__ = a);
+ var t = {
+ frame: {
+ configurable: !0
+ },
+ rotate: {
+ configurable: !0
+ },
+ width: {
+ configurable: !0
+ },
+ height: {
+ configurable: !0
+ }
+ };
+ return ((Texture.prototype = Object.create(a && a.prototype)).constructor = Texture).prototype.update = function() {
+ this.baseTexture.update()
+ }, Texture.prototype.onBaseTextureUpdated = function(t) {
+ this._updateID++, this.noFrame ? this.frame = new ot(0, 0, t.width, t.height) : this.frame = this._frame, this.emit("update", this)
+ }, Texture.prototype.destroy = function(t) {
+ this.baseTexture && (t && (F[this.baseTexture.imageUrl] && Texture.removeFromCache(this.baseTexture.imageUrl), this.baseTexture.destroy()), this.baseTexture.off("update", this.onBaseTextureUpdated, this), this.baseTexture = null), this._frame = null, this._uvs = null, this.trim = null, this.orig = null, this.valid = !1, Texture.removeFromCache(this), this.textureCacheIds = null
+ }, Texture.prototype.clone = function() {
+ return new Texture(this.baseTexture, this.frame, this.orig, this.trim, this.rotate, this.defaultAnchor)
+ }, Texture.prototype.updateUvs = function() {
+ this._uvs === qt && (this._uvs = new Vt), this._uvs.set(this._frame, this.baseTexture, this.rotate), this._updateID++
+ }, Texture.from = function(t, e) {
+ void 0 === e && (e = {});
+ var r = null;
+ r = "string" == typeof t ? t : (t._pixiId || (t._pixiId = "pixiid_" + uid()), t._pixiId);
+ var n = F[r];
+ return n || (e.resolution || (e.resolution = getResolutionOfUrl(t)), (n = new Texture(new Rt(t, e))).baseTexture.cacheId = r, Rt.addToCache(n.baseTexture, r), Texture.addToCache(n, r)), n
+ }, Texture.fromBuffer = function(t, e, r, n) {
+ return new Texture(Rt.fromBuffer(t, e, r, n))
+ }, Texture.fromLoader = function(t, e, r) {
+ var n = new Pt(t);
+ n.url = e;
+ var i = new Texture(new Rt(n, {
+ scaleMode: M.SCALE_MODE,
+ resolution: getResolutionOfUrl(e)
+ }));
+ return r || (r = e), Rt.addToCache(i.baseTexture, r), Texture.addToCache(i, r), r !== e && (Rt.addToCache(i.baseTexture, e), Texture.addToCache(i, e)), i
+ }, Texture.addToCache = function(t, e) {
+ e && (-1 === t.textureCacheIds.indexOf(e) && t.textureCacheIds.push(e), F[e], F[e] = t)
+ }, Texture.removeFromCache = function(t) {
+ if ("string" == typeof t) {
+ var e = F[t];
+ if (e) {
+ var r = e.textureCacheIds.indexOf(t);
+ return -1 < r && e.textureCacheIds.splice(r, 1), delete F[t], e
+ }
+ } else if (t && t.textureCacheIds) {
+ for (var n = 0; n < t.textureCacheIds.length; ++n) F[t.textureCacheIds[n]] === t && delete F[t.textureCacheIds[n]];
+ return t.textureCacheIds.length = 0, t
+ }
+ return null
+ }, t.frame.get = function() {
+ return this._frame
+ }, t.frame.set = function(t) {
+ this._frame = t, this.noFrame = !1;
+ var e = t.x,
+ r = t.y,
+ n = t.width,
+ i = t.height,
+ o = e + n > this.baseTexture.width,
+ a = r + i > this.baseTexture.height;
+ if (o || a) {
+ var s = o && a ? "and" : "or",
+ u = "X: " + e + " + " + n + " = " + (e + n) + " > " + this.baseTexture.width,
+ h = "Y: " + r + " + " + i + " = " + (r + i) + " > " + this.baseTexture.height;
+ throw new Error("Texture Error: frame does not fit inside the base Texture dimensions: " + u + " " + s + " " + h)
+ }
+ this.valid = n && i && this.baseTexture.valid, this.trim || this.rotate || (this.orig = t), this.valid && this.updateUvs()
+ }, t.rotate.get = function() {
+ return this._rotate
+ }, t.rotate.set = function(t) {
+ this._rotate = t, this.valid && this.updateUvs()
+ }, t.width.get = function() {
+ return this.orig.width
+ }, t.height.get = function() {
+ return this.orig.height
+ }, Object.defineProperties(Texture.prototype, t), Texture
+ }(l.a);
+
+ function removeAllHandlers(t) {
+ t.destroy = function() {}, t.on = function() {}, t.once = function() {}, t.emit = function() {}
+ }
+ Ht.EMPTY = new Ht(new Rt), removeAllHandlers(Ht.EMPTY), removeAllHandlers(Ht.EMPTY.baseTexture), Ht.WHITE = function() {
+ var t = document.createElement("canvas");
+ t.width = 16, t.height = 16;
+ var e = t.getContext("2d");
+ return e.fillStyle = "white", e.fillRect(0, 0, 16, 16), new Ht(new Rt(new Ft(t)))
+ }(), removeAllHandlers(Ht.WHITE), removeAllHandlers(Ht.WHITE.baseTexture);
+ var Wt = function(s) {
+ function RenderTexture(t, e) {
+ var r = null;
+ if (!(t instanceof Xt)) {
+ var n = arguments[1],
+ i = arguments[2],
+ o = arguments[3],
+ a = arguments[4];
+ r = arguments[0], e = null, t = new Xt({
+ width: n,
+ height: i,
+ scaleMode: o,
+ resolution: a
+ })
+ }
+ s.call(this, t, e), this.legacyRenderer = r, this.valid = !0, this.filterFrame = null, this.filterPoolKey = null, this.updateUvs()
+ }
+ return s && (RenderTexture.__proto__ = s), ((RenderTexture.prototype = Object.create(s && s.prototype)).constructor = RenderTexture).prototype.resize = function(t, e, r) {
+ void 0 === r && (r = !0), t = Math.ceil(t), e = Math.ceil(e), this.valid = 0 < t && 0 < e, this._frame.width = this.orig.width = t, this._frame.height = this.orig.height = e, r && this.baseTexture.resize(t, e), this.updateUvs()
+ }, RenderTexture.create = function(t) {
+ return "number" == typeof t && (t = {
+ width: t,
+ height: arguments[1],
+ scaleMode: arguments[2],
+ resolution: arguments[3]
+ }), new RenderTexture(new Xt(t))
+ }, RenderTexture
+ }(Ht),
+ Yt = function(t, e, r, n, i, o, a) {
+ void 0 === r && (r = !1), void 0 === n && (n = 5126), this.buffer = t, this.size = e, this.normalized = r, this.type = n, this.stride = i, this.start = o, this.instance = a
+ };
+ Yt.prototype.destroy = function() {
+ this.buffer = null
+ }, Yt.from = function(t, e, r, n, i) {
+ return new Yt(t, e, r, n, i)
+ };
+ var Kt = 0,
+ Zt = function(t, e, r) {
+ void 0 === e && (e = !0), void 0 === r && (r = !1), this.data = t || new Float32Array(1), this._glBuffers = {}, this._updateID = 0, this.index = r, this.static = e, this.id = Kt++, this.disposeRunner = new gt("disposeBuffer", 2)
+ };
+
+ function getBufferType(t) {
+ if (4 === t.BYTES_PER_ELEMENT) return t instanceof Float32Array ? "Float32Array" : t instanceof Uint32Array ? "Uint32Array" : "Int32Array";
+ if (2 === t.BYTES_PER_ELEMENT) {
+ if (t instanceof Uint16Array) return "Uint16Array"
+ } else if (1 === t.BYTES_PER_ELEMENT && t instanceof Uint8Array) return "Uint8Array";
+ return null
+ }
+ Zt.prototype.update = function(t) {
+ this.data = t || this.data, this._updateID++
+ }, Zt.prototype.dispose = function() {
+ this.disposeRunner.run(this, !1)
+ }, Zt.prototype.destroy = function() {
+ this.dispose(), this.data = null
+ }, Zt.from = function(t) {
+ return t instanceof Array && (t = new Float32Array(t)), new Zt(t)
+ };
+ var Qt = {
+ Float32Array: Float32Array,
+ Uint32Array: Uint32Array,
+ Int32Array: Int32Array,
+ Uint8Array: Uint8Array
+ };
+ var Jt = {
+ 5126: 4,
+ 5123: 2,
+ 5121: 1
+ },
+ $t = 0,
+ te = {
+ Float32Array: Float32Array,
+ Uint32Array: Uint32Array,
+ Int32Array: Int32Array,
+ Uint8Array: Uint8Array,
+ Uint16Array: Uint16Array
+ },
+ ee = function(t, e) {
+ void 0 === t && (t = []), void 0 === e && (e = {}), this.buffers = t, this.indexBuffer = null, this.attributes = e, this.glVertexArrayObjects = {}, this.id = $t++, this.instanced = !1, this.instanceCount = 1, this._size = null, this.disposeRunner = new gt("disposeGeometry", 2), this.refCount = 0
+ };
+ ee.prototype.addAttribute = function(t, e, r, n, i, o, a, s) {
+ if (void 0 === n && (n = !1), void 0 === s && (s = !1), !e) throw new Error("You must pass a buffer when creating an attribute");
+ e.data || (e instanceof Array && (e = new Float32Array(e)), e = new Zt(e));
+ var u = t.split("|");
+ if (1 < u.length) {
+ for (var h = 0; h < u.length; h++) this.addAttribute(u[h], e, r, n, i);
+ return this
+ }
+ var c = this.buffers.indexOf(e);
+ return -1 === c && (this.buffers.push(e), c = this.buffers.length - 1), this.attributes[t] = new Yt(c, r, n, i, o, a, s), this.instanced = this.instanced || s, this
+ }, ee.prototype.getAttribute = function(t) {
+ return this.buffers[this.attributes[t].buffer]
+ }, ee.prototype.addIndex = function(t) {
+ return t.data || (t instanceof Array && (t = new Uint16Array(t)), t = new Zt(t)), t.index = !0, this.indexBuffer = t, -1 === this.buffers.indexOf(t) && this.buffers.push(t), this
+ }, ee.prototype.getIndex = function() {
+ return this.indexBuffer
+ }, ee.prototype.interleave = function() {
+ if (1 === this.buffers.length || 2 === this.buffers.length && this.indexBuffer) return this;
+ var t, e = [],
+ r = [],
+ n = new Zt;
+ for (t in this.attributes) {
+ var i = this.attributes[t],
+ o = this.buffers[i.buffer];
+ e.push(o.data), r.push(i.size * Jt[i.type] / 4), i.buffer = 0
+ }
+ for (n.data = function(t, e) {
+ for (var r = 0, n = 0, i = {}, o = 0; o < t.length; o++) n += e[o], r += t[o].length;
+ for (var a = new ArrayBuffer(4 * r), s = null, u = 0, h = 0; h < t.length; h++) {
+ var c = e[h],
+ l = t[h],
+ f = getBufferType(l);
+ i[f] || (i[f] = new Qt[f](a)), s = i[f];
+ for (var d = 0; d < l.length; d++) s[(d / c | 0) * n + u + d % c] = l[d];
+ u += c
+ }
+ return new Float32Array(a)
+ }(e, r), t = 0; t < this.buffers.length; t++) this.buffers[t] !== this.indexBuffer && this.buffers[t].destroy();
+ return this.buffers = [n], this.indexBuffer && this.buffers.push(this.indexBuffer), this
+ }, ee.prototype.getSize = function() {
+ for (var t in this.attributes) {
+ var e = this.attributes[t];
+ return this.buffers[e.buffer].data.length / (e.stride / 4 || e.size)
+ }
+ return 0
+ }, ee.prototype.dispose = function() {
+ this.disposeRunner.run(this, !1)
+ }, ee.prototype.destroy = function() {
+ this.dispose(), this.buffers = null, this.indexBuffer.destroy(), this.attributes = null
+ }, ee.prototype.clone = function() {
+ for (var t = new ee, e = 0; e < this.buffers.length; e++) t.buffers[e] = new Zt(this.buffers[e].data.slice());
+ for (var r in this.attributes) {
+ var n = this.attributes[r];
+ t.attributes[r] = new Yt(n.buffer, n.size, n.normalized, n.type, n.stride, n.start, n.instance)
+ }
+ return this.indexBuffer && (t.indexBuffer = t.buffers[this.buffers.indexOf(this.indexBuffer)], t.indexBuffer.index = !0), t
+ }, ee.merge = function(t) {
+ for (var e, r = new ee, n = [], i = [], o = [], a = 0; a < t.length; a++) {
+ e = t[a];
+ for (var s = 0; s < e.buffers.length; s++) i[s] = i[s] || 0, i[s] += e.buffers[s].data.length, o[s] = 0
+ }
+ for (var u = 0; u < e.buffers.length; u++) n[u] = new(te[getBufferType(e.buffers[u].data)])(i[u]), r.buffers[u] = new Zt(n[u]);
+ for (var h = 0; h < t.length; h++) {
+ e = t[h];
+ for (var c = 0; c < e.buffers.length; c++) n[c].set(e.buffers[c].data, o[c]), o[c] += e.buffers[c].data.length
+ }
+ if (r.attributes = e.attributes, e.indexBuffer) {
+ r.indexBuffer = r.buffers[e.buffers.indexOf(e.indexBuffer)], r.indexBuffer.index = !0;
+ for (var l = 0, f = 0, d = 0, p = 0, m = 0; m < e.buffers.length; m++)
+ if (e.buffers[m] !== e.indexBuffer) {
+ p = m;
+ break
+ }
+ for (var v in e.attributes) {
+ var g = e.attributes[v];
+ (0 | g.buffer) === p && (f += g.size * Jt[g.type] / 4)
+ }
+ for (var y = 0; y < t.length; y++) {
+ for (var _ = t[y].indexBuffer.data, b = 0; b < _.length; b++) r.indexBuffer.data[b + d] += l;
+ l += e.buffers[p].data.length / f, d += _.length
+ }
+ }
+ return r
+ };
+ var re = function(t) {
+ function Quad() {
+ t.call(this), this.addAttribute("aVertexPosition", [0, 0, 1, 0, 1, 1, 0, 1]).addIndex([0, 1, 3, 2])
+ }
+ return t && (Quad.__proto__ = t), (Quad.prototype = Object.create(t && t.prototype)).constructor = Quad
+ }(ee),
+ ne = function(t) {
+ function QuadUv() {
+ t.call(this), this.vertices = new Float32Array([-1, -1, 1, -1, 1, 1, -1, 1]), this.uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), this.vertexBuffer = new Zt(this.vertices), this.uvBuffer = new Zt(this.uvs), this.addAttribute("aVertexPosition", this.vertexBuffer).addAttribute("aTextureCoord", this.uvBuffer).addIndex([0, 1, 2, 0, 2, 3])
+ }
+ return t && (QuadUv.__proto__ = t), ((QuadUv.prototype = Object.create(t && t.prototype)).constructor = QuadUv).prototype.map = function(t, e) {
+ var r = 0,
+ n = 0;
+ return this.uvs[0] = r, this.uvs[1] = n, this.uvs[2] = r + e.width / t.width, this.uvs[3] = n, this.uvs[4] = r + e.width / t.width, this.uvs[5] = n + e.height / t.height, this.uvs[6] = r, this.uvs[7] = n + e.height / t.height, r = e.x, n = e.y, this.vertices[0] = r, this.vertices[1] = n, this.vertices[2] = r + e.width, this.vertices[3] = n, this.vertices[4] = r + e.width, this.vertices[5] = n + e.height, this.vertices[6] = r, this.vertices[7] = n + e.height, this.invalidate(), this
+ }, QuadUv.prototype.invalidate = function() {
+ return this.vertexBuffer._updateID++, this.uvBuffer._updateID++, this
+ }, QuadUv
+ }(ee);
+ var ie = 0,
+ oe = function(t, e) {
+ this.uniforms = t, this.group = !0, this.syncUniforms = {}, this.dirtyId = 0, this.id = ie++, this.static = !!e
+ };
+ oe.prototype.update = function() {
+ this.dirtyId++
+ }, oe.prototype.add = function(t, e, r) {
+ this.uniforms[t] = new oe(e, r)
+ }, oe.from = function(t, e) {
+ return new oe(t, e)
+ };
+ var ae = function() {
+ this.renderTexture = null, this.target = null, this.legacy = !1, this.resolution = 1, this.sourceFrame = new ot, this.destinationFrame = new ot, this.filters = []
+ };
+ ae.prototype.clear = function() {
+ this.target = null, this.filters = null, this.renderTexture = null
+ };
+ var se = "screen",
+ ue = function(e) {
+ function FilterSystem(t) {
+ e.call(this, t), this.defaultFilterStack = [{}], this.texturePool = {}, this.statePool = [], this.quad = new re, this.quadUv = new ne, this.tempRect = new ot, this.activeState = {}, this.globalUniforms = new oe({
+ outputFrame: this.tempRect,
+ inputSize: new Float32Array(4),
+ inputPixel: new Float32Array(4),
+ inputClamp: new Float32Array(4),
+ resolution: 1,
+ filterArea: new Float32Array(4),
+ filterClamp: new Float32Array(4)
+ }, !0), this._pixelsWidth = t.view.width, this._pixelsHeight = t.view.height
+ }
+ return e && (FilterSystem.__proto__ = e), ((FilterSystem.prototype = Object.create(e && e.prototype)).constructor = FilterSystem).prototype.push = function(t, e) {
+ for (var r = this.renderer, n = this.defaultFilterStack, i = this.statePool.pop() || new ae, o = e[0].resolution, a = e[0].padding, s = e[0].autoFit, u = e[0].legacy, h = 1; h < e.length; h++) {
+ var c = e[h];
+ o = Math.min(o, c.resolution), a = Math.max(a, c.padding), s = s || c.autoFit, u = u || c.legacy
+ }
+ 1 === n.length && (this.defaultFilterStack[0].renderTexture = r.renderTexture.current), n.push(i), i.resolution = o, i.legacy = u, i.target = t, i.sourceFrame.copyFrom(t.filterArea || t.getBounds(!0)), i.sourceFrame.pad(a), s && i.sourceFrame.fit(this.renderer.renderTexture.sourceFrame), i.sourceFrame.ceil(o), i.renderTexture = this.getOptimalFilterTexture(i.sourceFrame.width, i.sourceFrame.height, o), i.filters = e, i.destinationFrame.width = i.renderTexture.width, i.destinationFrame.height = i.renderTexture.height, i.renderTexture.filterFrame = i.sourceFrame, r.renderTexture.bind(i.renderTexture, i.sourceFrame), r.renderTexture.clear()
+ }, FilterSystem.prototype.pop = function() {
+ var t = this.defaultFilterStack,
+ e = t.pop(),
+ r = e.filters;
+ this.activeState = e;
+ var n = this.globalUniforms.uniforms;
+ n.outputFrame = e.sourceFrame, n.resolution = e.resolution;
+ var i = n.inputSize,
+ o = n.inputPixel,
+ a = n.inputClamp;
+ if (i[0] = e.destinationFrame.width, i[1] = e.destinationFrame.height, i[2] = 1 / i[0], i[3] = 1 / i[1], o[0] = i[0] * e.resolution, o[1] = i[1] * e.resolution, o[2] = 1 / o[0], o[3] = 1 / o[1], a[0] = .5 * o[2], a[1] = .5 * o[3], a[2] = e.sourceFrame.width * i[2] - .5 * o[2], a[3] = e.sourceFrame.height * i[3] - .5 * o[3], e.legacy) {
+ var s = n.filterArea;
+ s[0] = e.destinationFrame.width, s[1] = e.destinationFrame.height, s[2] = e.sourceFrame.x, s[3] = e.sourceFrame.y, n.filterClamp = n.inputClamp
+ }
+ this.globalUniforms.update();
+ var u = t[t.length - 1];
+ if (1 === r.length) r[0].apply(this, e.renderTexture, u.renderTexture, !1, e), this.returnFilterTexture(e.renderTexture);
+ else {
+ var h = e.renderTexture,
+ c = this.getOptimalFilterTexture(h.width, h.height, e.resolution);
+ c.filterFrame = h.filterFrame;
+ var l = 0;
+ for (l = 0; l < r.length - 1; ++l) {
+ r[l].apply(this, h, c, !0, e);
+ var f = h;
+ h = c, c = f
+ }
+ r[l].apply(this, h, u.renderTexture, !1, e), this.returnFilterTexture(h), this.returnFilterTexture(c)
+ }
+ e.clear(), this.statePool.push(e)
+ }, FilterSystem.prototype.applyFilter = function(t, e, r, n) {
+ var i = this.renderer;
+ i.renderTexture.bind(r, r ? r.filterFrame : null), n && i.renderTexture.clear(), t.uniforms.uSampler = e, t.uniforms.filterGlobals = this.globalUniforms, i.state.setState(t.state), i.shader.bind(t), t.legacy ? (this.quadUv.map(e._frame, e.filterFrame), i.geometry.bind(this.quadUv), i.geometry.draw(x.TRIANGLES)) : (i.geometry.bind(this.quad), i.geometry.draw(x.TRIANGLE_STRIP))
+ }, FilterSystem.prototype.calculateScreenSpaceMatrix = function(t) {
+ var e, r, n, i, o = this.activeState;
+ return e = t, r = o.sourceFrame, n = o.destinationFrame, (i = e.identity()).translate(r.x / n.width, r.y / n.height), i.scale(n.width, n.height), i
+ }, FilterSystem.prototype.calculateSpriteMatrix = function(t, e) {
+ var r, n, i, o, a, s, u, h = this.activeState;
+ return r = t, n = h.sourceFrame, i = h.destinationFrame, a = (o = e)._texture.orig, s = r.set(i.width, 0, 0, i.height, n.x, n.y), (u = o.worldTransform.copyTo(Y.TEMP_MATRIX)).invert(), s.prepend(u), s.scale(1 / a.width, 1 / a.height), s.translate(o.anchor.x, o.anchor.y), s
+ }, FilterSystem.prototype.destroy = function(t) {
+ void 0 === t && (t = !1), t ? this.texturePool = {} : this.emptyPool()
+ }, FilterSystem.prototype.getOptimalFilterTexture = function(t, e, r) {
+ void 0 === r && (r = 1);
+ var n = se;
+ e *= r, (t *= r) === this._pixelsWidth && e === this._pixelsHeight || (n = (65535 & (t = nextPow2(t))) << 16 | 65535 & (e = nextPow2(e))), this.texturePool[n] || (this.texturePool[n] = []);
+ var i = this.texturePool[n].pop();
+ return i || (i = Wt.create({
+ width: t / r,
+ height: e / r,
+ resolution: r
+ })), i.filterPoolKey = n, i
+ }, FilterSystem.prototype.getFilterTexture = function(t) {
+ var e = this.activeState.renderTexture,
+ r = this.getOptimalFilterTexture(e.width, e.height, t || e.baseTexture.resolution);
+ return r.filterFrame = e.filterFrame, r
+ }, FilterSystem.prototype.returnFilterTexture = function(t) {
+ var e = t.filterPoolKey;
+ t.filterFrame = null, this.texturePool[e].push(t)
+ }, FilterSystem.prototype.emptyPool = function() {
+ for (var t in this.texturePool) {
+ var e = this.texturePool[t];
+ if (e)
+ for (var r = 0; r < e.length; r++) e[r].destroy(!0)
+ }
+ this.texturePool = {}
+ }, FilterSystem.prototype.resize = function() {
+ var t = this.texturePool[se];
+ if (t)
+ for (var e = 0; e < t.length; e++) t[e].destroy(!0);
+ this.texturePool[se] = [], this._pixelsWidth = this.renderer.view.width, this._pixelsHeight = this.renderer.view.height
+ }, FilterSystem
+ }(Ut),
+ he = function(t) {
+ function ObjectRenderer() {
+ t.apply(this, arguments)
+ }
+ return t && (ObjectRenderer.__proto__ = t), ((ObjectRenderer.prototype = Object.create(t && t.prototype)).constructor = ObjectRenderer).prototype.start = function() {}, ObjectRenderer.prototype.stop = function() {
+ this.flush()
+ }, ObjectRenderer.prototype.flush = function() {}, ObjectRenderer.prototype.render = function(t) {}, ObjectRenderer
+ }(Ut),
+ ce = function(e) {
+ function BatchSystem(t) {
+ e.call(this, t), this.emptyRenderer = new he(t), this.currentRenderer = this.emptyRenderer
+ }
+ return e && (BatchSystem.__proto__ = e), ((BatchSystem.prototype = Object.create(e && e.prototype)).constructor = BatchSystem).prototype.setObjectRenderer = function(t) {
+ this.currentRenderer !== t && (this.currentRenderer.stop(), this.currentRenderer = t, this.currentRenderer.start())
+ }, BatchSystem.prototype.flush = function() {
+ this.setObjectRenderer(this.emptyRenderer)
+ }, BatchSystem.prototype.reset = function() {
+ this.setObjectRenderer(this.emptyRenderer)
+ }, BatchSystem
+ }(Ut);
+ M.PREFER_ENV = h.a.any ? v.WEBGL : v.WEBGL2;
+ var le = 0,
+ fe = function(e) {
+ function ContextSystem(t) {
+ e.call(this, t), this.webGLVersion = 1, this.extensions = {}, this.handleContextLost = this.handleContextLost.bind(this), this.handleContextRestored = this.handleContextRestored.bind(this), t.view.addEventListener("webglcontextlost", this.handleContextLost, !1), t.view.addEventListener("webglcontextrestored", this.handleContextRestored, !1)
+ }
+ e && (ContextSystem.__proto__ = e), (ContextSystem.prototype = Object.create(e && e.prototype)).constructor = ContextSystem;
+ var t = {
+ isLost: {
+ configurable: !0
+ }
+ };
+ return t.isLost.get = function() {
+ return !this.gl || this.gl.isContextLost()
+ }, ContextSystem.prototype.contextChange = function(t) {
+ (this.gl = t).isContextLost() && t.getExtension("WEBGL_lose_context") && t.getExtension("WEBGL_lose_context").restoreContext()
+ }, ContextSystem.prototype.initFromContext = function(t) {
+ this.gl = t, this.validateContext(t), this.renderer.gl = t, this.renderer.CONTEXT_UID = le++, this.renderer.runners.contextChange.run(t)
+ }, ContextSystem.prototype.initFromOptions = function(t) {
+ var e = this.createContext(this.renderer.view, t);
+ this.initFromContext(e)
+ }, ContextSystem.prototype.createContext = function(t, e) {
+ var r;
+ if (M.PREFER_ENV >= v.WEBGL2 && (r = t.getContext("webgl2", e)), r) this.webGLVersion = 2;
+ else if (this.webGLVersion = 1, !(r = t.getContext("webgl", e) || t.getContext("experimental-webgl", e))) throw new Error("This browser does not support WebGL. Try using the canvas renderer");
+ return this.gl = r, this.getExtensions(), r
+ }, ContextSystem.prototype.getExtensions = function() {
+ var t = this.gl;
+ 1 === this.webGLVersion && Object.assign(this.extensions, {
+ drawBuffers: t.getExtension("WEBGL_draw_buffers"),
+ depthTexture: t.getExtension("WEBKIT_WEBGL_depth_texture"),
+ floatTexture: t.getExtension("OES_texture_float"),
+ loseContext: t.getExtension("WEBGL_lose_context"),
+ vertexArrayObject: t.getExtension("OES_vertex_array_object") || t.getExtension("MOZ_OES_vertex_array_object") || t.getExtension("WEBKIT_OES_vertex_array_object")
+ })
+ }, ContextSystem.prototype.handleContextLost = function(t) {
+ t.preventDefault()
+ }, ContextSystem.prototype.handleContextRestored = function() {
+ this.renderer.runners.contextChange.run(this.gl)
+ }, ContextSystem.prototype.destroy = function() {
+ var t = this.renderer.view;
+ t.removeEventListener("webglcontextlost", this.handleContextLost), t.removeEventListener("webglcontextrestored", this.handleContextRestored), this.gl.useProgram(null), this.extensions.loseContext && this.extensions.loseContext.loseContext()
+ }, ContextSystem.prototype.postrender = function() {
+ this.gl.flush()
+ }, ContextSystem.prototype.validateContext = function(t) {
+ t.getContextAttributes().stencil
+ }, Object.defineProperties(ContextSystem.prototype, t), ContextSystem
+ }(Ut),
+ de = function(e) {
+ function FramebufferSystem(t) {
+ e.call(this, t), this.managedFramebuffers = [], this.unknownFramebuffer = new jt(10, 10)
+ }
+ e && (FramebufferSystem.__proto__ = e);
+ var t = {
+ size: {
+ configurable: !0
+ }
+ };
+ return ((FramebufferSystem.prototype = Object.create(e && e.prototype)).constructor = FramebufferSystem).prototype.contextChange = function() {
+ var t = this.gl = this.renderer.gl;
+ if (this.CONTEXT_UID = this.renderer.CONTEXT_UID, this.current = this.unknownFramebuffer, this.viewport = new ot, this.hasMRT = !0, this.writeDepthTexture = !0, this.disposeAll(!0), 1 === this.renderer.context.webGLVersion) {
+ var e = this.renderer.context.extensions.drawBuffers,
+ r = this.renderer.context.extensions.depthTexture;
+ M.PREFER_ENV === v.WEBGL_LEGACY && (r = e = null), t.drawBuffers = e ? function(t) {
+ return e.drawBuffersWEBGL(t)
+ } : (this.hasMRT = !1, function() {}), r || (this.writeDepthTexture = !1)
+ }
+ }, FramebufferSystem.prototype.bind = function(t, e) {
+ var r = this.gl;
+ if (t) {
+ var n = t.glFramebuffers[this.CONTEXT_UID] || this.initFramebuffer(t);
+ this.current !== t && (this.current = t, r.bindFramebuffer(r.FRAMEBUFFER, n.framebuffer)), n.dirtyId !== t.dirtyId && (n.dirtyId = t.dirtyId, n.dirtyFormat !== t.dirtyFormat ? (n.dirtyFormat = t.dirtyFormat, this.updateFramebuffer(t)) : n.dirtySize !== t.dirtySize && (n.dirtySize = t.dirtySize, this.resizeFramebuffer(t)));
+ for (var i = 0; i < t.colorTextures.length; i++) t.colorTextures[i].texturePart ? this.renderer.texture.unbind(t.colorTextures[i].texture) : this.renderer.texture.unbind(t.colorTextures[i]);
+ t.depthTexture && this.renderer.texture.unbind(t.depthTexture), e ? this.setViewport(e.x, e.y, e.width, e.height) : this.setViewport(0, 0, t.width, t.height)
+ } else this.current && (this.current = null, r.bindFramebuffer(r.FRAMEBUFFER, null)), e ? this.setViewport(e.x, e.y, e.width, e.height) : this.setViewport(0, 0, this.renderer.width, this.renderer.height)
+ }, FramebufferSystem.prototype.setViewport = function(t, e, r, n) {
+ var i = this.viewport;
+ i.width === r && i.height === n && i.x === t && i.y === e || (i.x = t, i.y = e, i.width = r, i.height = n, this.gl.viewport(t, e, r, n))
+ }, t.size.get = function() {
+ return this.current ? {
+ x: 0,
+ y: 0,
+ width: this.current.width,
+ height: this.current.height
+ } : {
+ x: 0,
+ y: 0,
+ width: this.renderer.width,
+ height: this.renderer.height
+ }
+ }, FramebufferSystem.prototype.clear = function(t, e, r, n) {
+ var i = this.gl;
+ i.clearColor(t, e, r, n), i.clear(i.COLOR_BUFFER_BIT | i.DEPTH_BUFFER_BIT)
+ }, FramebufferSystem.prototype.initFramebuffer = function(t) {
+ var e = {
+ framebuffer: this.gl.createFramebuffer(),
+ stencil: null,
+ dirtyId: 0,
+ dirtyFormat: 0,
+ dirtySize: 0
+ };
+ return t.glFramebuffers[this.CONTEXT_UID] = e, this.managedFramebuffers.push(t), t.disposeRunner.add(this), e
+ }, FramebufferSystem.prototype.resizeFramebuffer = function(t) {
+ var e = this.gl,
+ r = t.glFramebuffers[this.CONTEXT_UID];
+ r.stencil && (e.bindRenderbuffer(e.RENDERBUFFER, r.stencil), e.renderbufferStorage(e.RENDERBUFFER, e.DEPTH_STENCIL, t.width, t.height));
+ for (var n = t.colorTextures, i = 0; i < n.length; i++) this.renderer.texture.bind(n[i], 0);
+ t.depthTexture && this.renderer.texture.bind(t.depthTexture, 0)
+ }, FramebufferSystem.prototype.updateFramebuffer = function(t) {
+ var e = this.gl,
+ r = t.glFramebuffers[this.CONTEXT_UID],
+ n = t.colorTextures.length;
+ e.drawBuffers || (n = Math.min(n, 1));
+ for (var i = [], o = 0; o < n; o++) {
+ var a = t.colorTextures[o];
+ a.texturePart ? (this.renderer.texture.bind(a.texture, 0), e.framebufferTexture2D(e.FRAMEBUFFER, e.COLOR_ATTACHMENT0 + o, e.TEXTURE_CUBE_MAP_NEGATIVE_X + a.side, a.texture._glTextures[this.CONTEXT_UID].texture, 0)) : (this.renderer.texture.bind(a, 0), e.framebufferTexture2D(e.FRAMEBUFFER, e.COLOR_ATTACHMENT0 + o, e.TEXTURE_2D, a._glTextures[this.CONTEXT_UID].texture, 0)), i.push(e.COLOR_ATTACHMENT0 + o)
+ }
+ if ((1 < i.length && e.drawBuffers(i), t.depthTexture) && this.writeDepthTexture) {
+ var s = t.depthTexture;
+ this.renderer.texture.bind(s, 0), e.framebufferTexture2D(e.FRAMEBUFFER, e.DEPTH_ATTACHMENT, e.TEXTURE_2D, s._glTextures[this.CONTEXT_UID].texture, 0)
+ }
+ r.stencil || !t.stencil && !t.depth || (r.stencil = e.createRenderbuffer(), e.bindRenderbuffer(e.RENDERBUFFER, r.stencil), t.depthTexture || e.framebufferRenderbuffer(e.FRAMEBUFFER, e.DEPTH_STENCIL_ATTACHMENT, e.RENDERBUFFER, r.stencil), e.renderbufferStorage(e.RENDERBUFFER, e.DEPTH_STENCIL, t.width, t.height))
+ }, FramebufferSystem.prototype.disposeFramebuffer = function(t, e) {
+ var r = t.glFramebuffers[this.CONTEXT_UID],
+ n = this.gl;
+ if (r) {
+ delete t.glFramebuffers[this.CONTEXT_UID];
+ var i = this.managedFramebuffers.indexOf(t);
+ 0 <= i && this.managedFramebuffers.splice(i, 1), t.disposeRunner.remove(this), e || (n.deleteFramebuffer(r.framebuffer), r.stencil && n.deleteRenderbuffer(r.stencil))
+ }
+ }, FramebufferSystem.prototype.disposeAll = function(t) {
+ var e = this.managedFramebuffers;
+ this.managedFramebuffers = [];
+ for (var r = 0; r < e.count; r++) this.disposeFramebuffer(e[r], t)
+ }, FramebufferSystem.prototype.reset = function() {
+ this.current = this.unknownFramebuffer, this.viewport = new ot
+ }, Object.defineProperties(FramebufferSystem.prototype, t), FramebufferSystem
+ }(Ut),
+ pe = function(t) {
+ this.buffer = t, this.updateID = -1, this.byteLength = -1, this.refCount = 0
+ },
+ me = {
+ 5126: 4,
+ 5123: 2,
+ 5121: 1
+ },
+ ve = function(e) {
+ function GeometrySystem(t) {
+ e.call(this, t), this._activeGeometry = null, this._activeVao = null, this.hasVao = !0, this.hasInstance = !0, this.boundBuffers = {}, this.managedGeometries = {}, this.managedBuffers = {}
+ }
+ return e && (GeometrySystem.__proto__ = e), ((GeometrySystem.prototype = Object.create(e && e.prototype)).constructor = GeometrySystem).prototype.contextChange = function() {
+ this.disposeAll(!0);
+ var t = this.gl = this.renderer.gl;
+ if (this.CONTEXT_UID = this.renderer.CONTEXT_UID, !t.createVertexArray) {
+ var e = this.renderer.context.extensions.vertexArrayObject;
+ M.PREFER_ENV === v.WEBGL_LEGACY && (e = null), t.deleteVertexArray = e ? (t.createVertexArray = function() {
+ return e.createVertexArrayOES()
+ }, t.bindVertexArray = function(t) {
+ return e.bindVertexArrayOES(t)
+ }, function(t) {
+ return e.deleteVertexArrayOES(t)
+ }) : (this.hasVao = !1, t.createVertexArray = function() {}, t.bindVertexArray = function() {}, function() {})
+ }
+ if (!t.vertexAttribDivisor) {
+ var o = t.getExtension("ANGLE_instanced_arrays");
+ o ? (t.vertexAttribDivisor = function(t, e) {
+ return o.vertexAttribDivisorANGLE(t, e)
+ }, t.drawElementsInstanced = function(t, e, r, n, i) {
+ return o.drawElementsInstancedANGLE(t, e, r, n, i)
+ }, t.drawArraysInstanced = function(t, e, r, n) {
+ return o.drawArraysInstancedANGLE(t, e, r, n)
+ }) : this.hasInstance = !1
+ }
+ }, GeometrySystem.prototype.bind = function(t, e) {
+ e = e || this.renderer.shader.shader;
+ var r = this.gl,
+ n = t.glVertexArrayObjects[this.CONTEXT_UID];
+ n || ((this.managedGeometries[t.id] = t).disposeRunner.add(this), t.glVertexArrayObjects[this.CONTEXT_UID] = n = {});
+ var i = n[e.program.id] || this.initGeometryVao(t, e.program);
+ this._activeGeometry = t, this._activeVao !== i && (this._activeVao = i, this.hasVao ? r.bindVertexArray(i) : this.activateVao(t, e.program)), this.updateBuffers()
+ }, GeometrySystem.prototype.reset = function() {
+ this.unbind()
+ }, GeometrySystem.prototype.updateBuffers = function() {
+ for (var t = this._activeGeometry, e = this.gl, r = 0; r < t.buffers.length; r++) {
+ var n = t.buffers[r],
+ i = n._glBuffers[this.CONTEXT_UID];
+ if (n._updateID !== i.updateID) {
+ i.updateID = n._updateID;
+ var o = n.index ? e.ELEMENT_ARRAY_BUFFER : e.ARRAY_BUFFER;
+ if (e.bindBuffer(o, i.buffer), (this._boundBuffer = i).byteLength >= n.data.byteLength) e.bufferSubData(o, 0, n.data);
+ else {
+ var a = n.static ? e.STATIC_DRAW : e.DYNAMIC_DRAW;
+ i.byteLength = n.data.byteLength, e.bufferData(o, n.data, a)
+ }
+ }
+ }
+ }, GeometrySystem.prototype.checkCompatibility = function(t, e) {
+ var r = t.attributes,
+ n = e.attributeData;
+ for (var i in n)
+ if (!r[i]) throw new Error('shader and geometry incompatible, geometry missing the "' + i + '" attribute')
+ }, GeometrySystem.prototype.getSignature = function(t, e) {
+ var r = t.attributes,
+ n = e.attributeData,
+ i = ["g", t.id];
+ for (var o in r) n[o] && i.push(o);
+ return i.join("-")
+ }, GeometrySystem.prototype.initGeometryVao = function(t, e) {
+ this.checkCompatibility(t, e);
+ var r = this.gl,
+ n = this.CONTEXT_UID,
+ i = this.getSignature(t, e),
+ o = t.glVertexArrayObjects[this.CONTEXT_UID],
+ a = o[i];
+ if (a) return o[e.id] = a;
+ var s = t.buffers,
+ u = t.attributes,
+ h = {},
+ c = {};
+ for (var l in s) h[l] = 0, c[l] = 0;
+ for (var f in u) !u[f].size && e.attributeData[f] ? u[f].size = e.attributeData[f].size : u[f].size, h[u[f].buffer] += u[f].size * me[u[f].type];
+ for (var d in u) {
+ var p = u[d],
+ m = p.size;
+ void 0 === p.stride && (h[p.buffer] === m * me[p.type] ? p.stride = 0 : p.stride = h[p.buffer]), void 0 === p.start && (p.start = c[p.buffer], c[p.buffer] += m * me[p.type])
+ }
+ a = r.createVertexArray(), r.bindVertexArray(a);
+ for (var v = 0; v < s.length; v++) {
+ var g = s[v];
+ g._glBuffers[n] || (g._glBuffers[n] = new pe(r.createBuffer()), (this.managedBuffers[g.id] = g).disposeRunner.add(this)), g._glBuffers[n].refCount++
+ }
+ return this.activateVao(t, e), r.bindVertexArray(this._activeVao), o[e.id] = a, o[i] = a
+ }, GeometrySystem.prototype.disposeBuffer = function(t, e) {
+ if (this.managedBuffers[t.id]) {
+ delete this.managedBuffers[t.id];
+ var r = t._glBuffers[this.CONTEXT_UID],
+ n = this.gl;
+ t.disposeRunner.remove(this), r && (e || n.deleteBuffer(r.buffer), delete t._glBuffers[this.CONTEXT_UID])
+ }
+ }, GeometrySystem.prototype.disposeGeometry = function(t, e) {
+ if (this.managedGeometries[t.id]) {
+ delete this.managedGeometries[t.id];
+ var r = t.glVertexArrayObjects[this.CONTEXT_UID],
+ n = this.gl,
+ i = t.buffers;
+ if (t.disposeRunner.remove(this), r) {
+ for (var o = 0; o < i.length; o++) {
+ var a = i[o]._glBuffers[this.CONTEXT_UID];
+ a.refCount--, 0 !== a.refCount || e || this.disposeBuffer(i[o], e)
+ }
+ if (!e)
+ for (var s in r) "g" === s[0] && n.deleteVertexArray(r[s]);
+ delete t.glVertexArrayObjects[this.CONTEXT_UID]
+ }
+ }
+ }, GeometrySystem.prototype.disposeAll = function(t) {
+ for (var e = Object.keys(this.managedGeometries), r = 0; r < e.length; r++) this.disposeGeometry(this.managedGeometries[e[r]], t);
+ e = Object.keys(this.managedBuffers);
+ for (var n = 0; n < e.length; n++) this.disposeBuffer(this.managedBuffers[e[n]], t)
+ }, GeometrySystem.prototype.activateVao = function(t, e) {
+ var r = this.gl,
+ n = this.CONTEXT_UID,
+ i = t.buffers,
+ o = t.attributes;
+ t.indexBuffer && r.bindBuffer(r.ELEMENT_ARRAY_BUFFER, t.indexBuffer._glBuffers[n].buffer);
+ var a = null;
+ for (var s in o) {
+ var u = o[s],
+ h = i[u.buffer]._glBuffers[n];
+ if (e.attributeData[s]) {
+ a !== h && (r.bindBuffer(r.ARRAY_BUFFER, h.buffer), a = h);
+ var c = e.attributeData[s].location;
+ if (r.enableVertexAttribArray(c), r.vertexAttribPointer(c, u.size, u.type || r.FLOAT, u.normalized, u.stride, u.start), u.instance) {
+ if (!this.hasInstance) throw new Error("geometry error, GPU Instancing is not supported on this device");
+ r.vertexAttribDivisor(c, 1)
+ }
+ }
+ }
+ }, GeometrySystem.prototype.draw = function(t, e, r, n) {
+ var i = this.gl,
+ o = this._activeGeometry;
+ return o.indexBuffer ? o.instanced ? i.drawElementsInstanced(t, e || o.indexBuffer.data.length, i.UNSIGNED_SHORT, 2 * (r || 0), n || 1) : i.drawElements(t, e || o.indexBuffer.data.length, i.UNSIGNED_SHORT, 2 * (r || 0)) : o.instanced ? i.drawArraysInstanced(t, r, e || o.getSize(), n || 1) : i.drawArrays(t, r, e || o.getSize()), this
+ }, GeometrySystem.prototype.unbind = function() {
+ this.gl.bindVertexArray(null), this._activeVao = null, this._activeGeometry = null
+ }, GeometrySystem
+ }(Ut);
+
+ function compileProgram(t, e, r, n) {
+ var i = compileShader(t, t.VERTEX_SHADER, e),
+ o = compileShader(t, t.FRAGMENT_SHADER, r),
+ a = t.createProgram();
+ if (t.attachShader(a, i), t.attachShader(a, o), n)
+ for (var s in n) t.bindAttribLocation(a, n[s], s);
+ return t.linkProgram(a), t.getProgramParameter(a, t.LINK_STATUS) || (t.getProgramInfoLog(a), t.deleteProgram(a), a = null), t.deleteShader(i), t.deleteShader(o), a
+ }
+
+ function compileShader(t, e, r) {
+ var n = t.createShader(e);
+ return t.shaderSource(n, r), t.compileShader(n), t.getShaderParameter(n, t.COMPILE_STATUS) ? n : null
+ }
+
+ function core_es_defaultValue(t, e) {
+ switch (t) {
+ case "float":
+ return 0;
+ case "vec2":
+ return new Float32Array(2 * e);
+ case "vec3":
+ return new Float32Array(3 * e);
+ case "vec4":
+ return new Float32Array(4 * e);
+ case "int":
+ case "sampler2D":
+ case "sampler2DArray":
+ return 0;
+ case "ivec2":
+ return new Int32Array(2 * e);
+ case "ivec3":
+ return new Int32Array(3 * e);
+ case "ivec4":
+ return new Int32Array(4 * e);
+ case "bool":
+ return !1;
+ case "bvec2":
+ return booleanArray(2 * e);
+ case "bvec3":
+ return booleanArray(3 * e);
+ case "bvec4":
+ return booleanArray(4 * e);
+ case "mat2":
+ return new Float32Array([1, 0, 0, 1]);
+ case "mat3":
+ return new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);
+ case "mat4":
+ return new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
+ }
+ return null
+ }
+
+ function booleanArray(t) {
+ for (var e = new Array(t), r = 0; r < e.length; r++) e[r] = !1;
+ return e
+ }
+
+ function setPrecision(t, e) {
+ return "precision" !== t.substring(0, 9) ? "precision " + e + " float;\n" + t : t
+ }
+ var ge = {
+ float: 1,
+ vec2: 2,
+ vec3: 3,
+ vec4: 4,
+ int: 1,
+ ivec2: 2,
+ ivec3: 3,
+ ivec4: 4,
+ bool: 1,
+ bvec2: 2,
+ bvec3: 3,
+ bvec4: 4,
+ mat2: 4,
+ mat3: 9,
+ mat4: 16,
+ sampler2D: 1
+ };
+ var ye = null,
+ _e = {
+ FLOAT: "float",
+ FLOAT_VEC2: "vec2",
+ FLOAT_VEC3: "vec3",
+ FLOAT_VEC4: "vec4",
+ INT: "int",
+ INT_VEC2: "ivec2",
+ INT_VEC3: "ivec3",
+ INT_VEC4: "ivec4",
+ BOOL: "bool",
+ BOOL_VEC2: "bvec2",
+ BOOL_VEC3: "bvec3",
+ BOOL_VEC4: "bvec4",
+ FLOAT_MAT2: "mat2",
+ FLOAT_MAT3: "mat3",
+ FLOAT_MAT4: "mat4",
+ SAMPLER_2D: "sampler2D",
+ SAMPLER_CUBE: "samplerCube",
+ SAMPLER_2D_ARRAY: "sampler2DArray"
+ };
+
+ function mapType(t, e) {
+ if (!ye) {
+ var r = Object.keys(_e);
+ ye = {};
+ for (var n = 0; n < r.length; ++n) {
+ var i = r[n];
+ ye[t[i]] = _e[i]
+ }
+ }
+ return ye[e]
+ }
+ var be = {
+ float: "\n if(cv !== v)\n {\n cv.v = v;\n gl.uniform1f(location, v)\n }",
+ vec2: "\n if(cv[0] !== v[0] || cv[1] !== v[1])\n {\n cv[0] = v[0];\n cv[1] = v[1];\n gl.uniform2f(location, v[0], v[1])\n }",
+ vec3: "\n if(cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2])\n {\n cv[0] = v[0];\n cv[1] = v[1];\n cv[2] = v[2];\n\n gl.uniform3f(location, v[0], v[1], v[2])\n }",
+ vec4: "gl.uniform4f(location, v[0], v[1], v[2], v[3])",
+ int: "gl.uniform1i(location, v)",
+ ivec2: "gl.uniform2i(location, v[0], v[1])",
+ ivec3: "gl.uniform3i(location, v[0], v[1], v[2])",
+ ivec4: "gl.uniform4i(location, v[0], v[1], v[2], v[3])",
+ bool: "gl.uniform1i(location, v)",
+ bvec2: "gl.uniform2i(location, v[0], v[1])",
+ bvec3: "gl.uniform3i(location, v[0], v[1], v[2])",
+ bvec4: "gl.uniform4i(location, v[0], v[1], v[2], v[3])",
+ mat2: "gl.uniformMatrix2fv(location, false, v)",
+ mat3: "gl.uniformMatrix3fv(location, false, v)",
+ mat4: "gl.uniformMatrix4fv(location, false, v)",
+ sampler2D: "gl.uniform1i(location, v)",
+ samplerCube: "gl.uniform1i(location, v)",
+ sampler2DArray: "gl.uniform1i(location, v)"
+ },
+ xe = {
+ float: "gl.uniform1fv(location, v)",
+ vec2: "gl.uniform2fv(location, v)",
+ vec3: "gl.uniform3fv(location, v)",
+ vec4: "gl.uniform4fv(location, v)",
+ mat4: "gl.uniformMatrix4fv(location, false, v)",
+ mat3: "gl.uniformMatrix3fv(location, false, v)",
+ mat2: "gl.uniformMatrix2fv(location, false, v)",
+ int: "gl.uniform1iv(location, v)",
+ ivec2: "gl.uniform2iv(location, v)",
+ ivec3: "gl.uniform3iv(location, v)",
+ ivec4: "gl.uniform4iv(location, v)",
+ bool: "gl.uniform1iv(location, v)",
+ bvec2: "gl.uniform2iv(location, v)",
+ bvec3: "gl.uniform3iv(location, v)",
+ bvec4: "gl.uniform4iv(location, v)",
+ sampler2D: "gl.uniform1iv(location, v)",
+ samplerCube: "gl.uniform1iv(location, v)",
+ sampler2DArray: "gl.uniform1iv(location, v)"
+ };
+ var we = null;
+ var Te, Se = ["precision mediump float;", "void main(void){", "float test = 0.1;", "%forloop%", "gl_FragColor = vec4(0.0);", "}"].join("\n");
+
+ function checkMaxIfStatementsInShader(t, e) {
+ if (0 === t) throw new Error("Invalid value of `0` passed to `checkMaxIfStatementsInShader`");
+ for (var r = e.createShader(e.FRAGMENT_SHADER);;) {
+ var n = Se.replace(/%forloop%/gi, generateIfTestSrc(t));
+ if (e.shaderSource(r, n), e.compileShader(r), e.getShaderParameter(r, e.COMPILE_STATUS)) break;
+ t = t / 2 | 0
+ }
+ return t
+ }
+
+ function generateIfTestSrc(t) {
+ for (var e = "", r = 0; r < t; ++r) 0 < r && (e += "\nelse "), r < t - 1 && (e += "if(test == " + r + ".0){}");
+ return e
+ }
+ var Me = 0,
+ Ee = {},
+ Ae = function Program(t, e, r) {
+ void 0 === r && (r = "pixi-shader"), this.id = Me++, this.vertexSrc = t || Program.defaultVertexSrc, this.fragmentSrc = e || Program.defaultFragmentSrc, this.vertexSrc = this.vertexSrc.trim(), this.fragmentSrc = this.fragmentSrc.trim(), "#version" !== this.vertexSrc.substring(0, 8) && (r = r.replace(/\s+/g, "-"), Ee[r] ? (Ee[r]++, r += "-" + Ee[r]) : Ee[r] = 1, this.vertexSrc = "#define SHADER_NAME " + r + "\n" + this.vertexSrc, this.fragmentSrc = "#define SHADER_NAME " + r + "\n" + this.fragmentSrc, this.vertexSrc = setPrecision(this.vertexSrc, M.PRECISION_VERTEX), this.fragmentSrc = setPrecision(this.fragmentSrc, M.PRECISION_FRAGMENT)), this.extractData(this.vertexSrc, this.fragmentSrc), this.glPrograms = {}, this.syncUniforms = null
+ },
+ Pe = {
+ defaultVertexSrc: {
+ configurable: !0
+ },
+ defaultFragmentSrc: {
+ configurable: !0
+ }
+ };
+ Ae.prototype.extractData = function(t, e) {
+ var r = function() {
+ if (we) return we;
+ var t, e = document.createElement("canvas");
+ if (M.PREFER_ENV >= v.WEBGL2 && (t = e.getContext("webgl2", {})), !t) {
+ if (!(t = e.getContext("webgl", {}) || e.getContext("experimental-webgl", {}))) throw new Error("This browser does not support WebGL. Try using the canvas renderer");
+ t.getExtension("WEBGL_draw_buffers")
+ }
+ return we = t
+ }();
+ if (r) {
+ var n = compileProgram(r, t, e);
+ this.attributeData = this.getAttributeData(n, r), this.uniformData = this.getUniformData(n, r), r.deleteProgram(n)
+ } else this.uniformData = {}, this.attributeData = {}
+ }, Ae.prototype.getAttributeData = function(t, e) {
+ for (var r, n = {}, i = [], o = e.getProgramParameter(t, e.ACTIVE_ATTRIBUTES), a = 0; a < o; a++) {
+ var s = e.getActiveAttrib(t, a),
+ u = mapType(e, s.type),
+ h = {
+ type: u,
+ name: s.name,
+ size: (r = u, ge[r]),
+ location: 0
+ };
+ n[s.name] = h, i.push(h)
+ }
+ i.sort(function(t, e) {
+ return t.name > e.name ? 1 : -1
+ });
+ for (var c = 0; c < i.length; c++) i[c].location = c;
+ return n
+ }, Ae.prototype.getUniformData = function(t, e) {
+ for (var r = {}, n = e.getProgramParameter(t, e.ACTIVE_UNIFORMS), i = 0; i < n; i++) {
+ var o = e.getActiveUniform(t, i),
+ a = o.name.replace(/\[.*?\]/, ""),
+ s = o.name.match(/\[.*?\]/, ""),
+ u = mapType(e, o.type);
+ r[a] = {
+ type: u,
+ size: o.size,
+ isArray: s,
+ value: core_es_defaultValue(u, o.size)
+ }
+ }
+ return r
+ }, Pe.defaultVertexSrc.get = function() {
+ return "attribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void){\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n vTextureCoord = aTextureCoord;\n}\n"
+ }, Pe.defaultFragmentSrc.get = function() {
+ return "varying vec2 vTextureCoord;\n\nuniform sampler2D uSampler;\n\nvoid main(void){\n gl_FragColor *= texture2D(uSampler, vTextureCoord);\n}"
+ }, Ae.from = function(t, e, r) {
+ var n = t + e,
+ i = D[n];
+ return i || (D[n] = i = new Ae(t, e, r)), i
+ }, Object.defineProperties(Ae, Pe);
+ var Ie = function(t, e) {
+ for (var r in this.program = t, this.uniformGroup = e ? e instanceof oe ? e : new oe(e) : new oe({}), t.uniformData) this.uniformGroup.uniforms[r] instanceof Array && (this.uniformGroup.uniforms[r] = new Float32Array(this.uniformGroup.uniforms[r]))
+ },
+ Oe = {
+ uniforms: {
+ configurable: !0
+ }
+ };
+ Ie.prototype.checkUniformExists = function(t, e) {
+ if (e.uniforms[t]) return !0;
+ for (var r in e.uniforms) {
+ var n = e.uniforms[r];
+ if (n.group && this.checkUniformExists(t, n)) return !0
+ }
+ return !1
+ }, Ie.prototype.destroy = function() {
+ this.uniformGroup = null
+ }, Oe.uniforms.get = function() {
+ return this.uniformGroup.uniforms
+ }, Ie.from = function(t, e, r) {
+ var n = Ae.from(t, e);
+ return new Ie(n, r)
+ }, Object.defineProperties(Ie.prototype, Oe);
+ var Ce = function() {
+ this.data = 0, this.blendMode = y.NORMAL, this.polygonOffset = 0, this.blend = !0
+ },
+ Re = {
+ blend: {
+ configurable: !0
+ },
+ offsets: {
+ configurable: !0
+ },
+ culling: {
+ configurable: !0
+ },
+ depthTest: {
+ configurable: !0
+ },
+ clockwiseFrontFace: {
+ configurable: !0
+ },
+ blendMode: {
+ configurable: !0
+ },
+ polygonOffset: {
+ configurable: !0
+ }
+ };
+ Re.blend.get = function() {
+ return !!(1 & this.data)
+ }, Re.blend.set = function(t) {
+ !!(1 & this.data) !== t && (this.data ^= 1)
+ }, Re.offsets.get = function() {
+ return !!(2 & this.data)
+ }, Re.offsets.set = function(t) {
+ !!(2 & this.data) !== t && (this.data ^= 2)
+ }, Re.culling.get = function() {
+ return !!(4 & this.data)
+ }, Re.culling.set = function(t) {
+ !!(4 & this.data) !== t && (this.data ^= 4)
+ }, Re.depthTest.get = function() {
+ return !!(8 & this.data)
+ }, Re.depthTest.set = function(t) {
+ !!(8 & this.data) !== t && (this.data ^= 8)
+ }, Re.clockwiseFrontFace.get = function() {
+ return !!(16 & this.data)
+ }, Re.clockwiseFrontFace.set = function(t) {
+ !!(16 & this.data) !== t && (this.data ^= 16)
+ }, Re.blendMode.get = function() {
+ return this._blendMode
+ }, Re.blendMode.set = function(t) {
+ this.blend = t !== y.NONE, this._blendMode = t
+ }, Re.polygonOffset.get = function() {
+ return this._polygonOffset
+ }, Re.polygonOffset.set = function(t) {
+ this.offsets = !!t, this._polygonOffset = t
+ }, Ce.for2d = function() {
+ var t = new Ce;
+ return t.depthTest = !1, t.blend = !0, t
+ }, Object.defineProperties(Ce.prototype, Re);
+ var De = function(i) {
+ function Filter(t, e, r) {
+ var n = Ae.from(t || Filter.defaultVertexSrc, e || Filter.defaultFragmentSrc);
+ i.call(this, n, r), this.padding = 0, this.resolution = M.FILTER_RESOLUTION, this.enabled = !0, this.autoFit = !0, this.legacy = !!this.program.attributeData.aTextureCoord, this.state = new Ce
+ }
+ i && (Filter.__proto__ = i);
+ var t = {
+ blendMode: {
+ configurable: !0
+ }
+ },
+ e = {
+ defaultVertexSrc: {
+ configurable: !0
+ },
+ defaultFragmentSrc: {
+ configurable: !0
+ }
+ };
+ return ((Filter.prototype = Object.create(i && i.prototype)).constructor = Filter).prototype.apply = function(t, e, r, n, i, o) {
+ t.applyFilter(this, e, r, n, i, o)
+ }, t.blendMode.get = function() {
+ return this.state.blendMode
+ }, t.blendMode.set = function(t) {
+ this.state.blendMode = t
+ }, e.defaultVertexSrc.get = function() {
+ return "attribute vec2 aVertexPosition;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n\nuniform vec4 inputSize;\nuniform vec4 outputFrame;\n\nvec4 filterVertexPosition( void )\n{\n vec2 position = aVertexPosition * max(outputFrame.zw, vec2(0.)) + outputFrame.xy;\n\n return vec4((projectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0);\n}\n\nvec2 filterTextureCoord( void )\n{\n return aVertexPosition * (outputFrame.zw * inputSize.zw);\n}\n\nvoid main(void)\n{\n gl_Position = filterVertexPosition();\n vTextureCoord = filterTextureCoord();\n}\n"
+ }, e.defaultFragmentSrc.get = function() {
+ return "varying vec2 vTextureCoord;\n\nuniform sampler2D uSampler;\n\nvoid main(void){\n gl_FragColor = texture2D(uSampler, vTextureCoord);\n}\n"
+ }, Object.defineProperties(Filter.prototype, t), Object.defineProperties(Filter, e), Filter
+ }(Ie);
+ De.SOURCE_KEY_MAP = {};
+ var Fe = new Y,
+ ke = function(t, e) {
+ this._texture = t, this.mapCoord = new Y, this.uClampFrame = new Float32Array(4), this.uClampOffset = new Float32Array(2), this._updateID = -1, this.clampOffset = 0, this.clampMargin = void 0 === e ? .5 : e, this.isSimple = !1
+ },
+ Le = {
+ texture: {
+ configurable: !0
+ }
+ };
+ Le.texture.get = function() {
+ return this._texture
+ }, Le.texture.set = function(t) {
+ this._texture = t, this._updateID = -1
+ }, ke.prototype.multiplyUvs = function(t, e) {
+ void 0 === e && (e = t);
+ for (var r = this.mapCoord, n = 0; n < t.length; n += 2) {
+ var i = t[n],
+ o = t[n + 1];
+ e[n] = i * r.a + o * r.c + r.tx, e[n + 1] = i * r.b + o * r.d + r.ty
+ }
+ return e
+ }, ke.prototype.update = function(t) {
+ var e = this._texture;
+ if (!e || !e.valid) return !1;
+ if (!t && this._updateID === e._updateID) return !1;
+ this._updateID = e._updateID;
+ var r = e._uvs;
+ this.mapCoord.set(r.x1 - r.x0, r.y1 - r.y0, r.x3 - r.x0, r.y3 - r.y0, r.x0, r.y0);
+ var n = e.orig,
+ i = e.trim;
+ i && (Fe.set(n.width / i.width, 0, 0, n.height / i.height, -i.x / i.width, -i.y / i.height), this.mapCoord.append(Fe));
+ var o = e.baseTexture,
+ a = this.uClampFrame,
+ s = this.clampMargin / o.resolution,
+ u = this.clampOffset;
+ return a[0] = (e._frame.x + s + u) / o.width, a[1] = (e._frame.y + s + u) / o.height, a[2] = (e._frame.x + e._frame.width - s + u) / o.width, a[3] = (e._frame.y + e._frame.height - s + u) / o.height, this.uClampOffset[0] = u / o.realWidth, this.uClampOffset[1] = u / o.realHeight, this.isSimple = e._frame.width === o.width && e._frame.height === o.height && 0 === e.rotate, !0
+ }, Object.defineProperties(ke.prototype, Le);
+ var Ne = function(r) {
+ function SpriteMaskFilter(t) {
+ var e = new Y;
+ r.call(this, "attribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\nuniform mat3 otherMatrix;\n\nvarying vec2 vMaskCoord;\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n\n vTextureCoord = aTextureCoord;\n vMaskCoord = ( otherMatrix * vec3( aTextureCoord, 1.0) ).xy;\n}\n", "varying vec2 vMaskCoord;\nvarying vec2 vTextureCoord;\n\nuniform sampler2D uSampler;\nuniform sampler2D mask;\nuniform float alpha;\nuniform float npmAlpha;\nuniform vec4 maskClamp;\n\nvoid main(void)\n{\n float clip = step(3.5,\n step(maskClamp.x, vMaskCoord.x) +\n step(maskClamp.y, vMaskCoord.y) +\n step(vMaskCoord.x, maskClamp.z) +\n step(vMaskCoord.y, maskClamp.w));\n\n vec4 original = texture2D(uSampler, vTextureCoord);\n vec4 masky = texture2D(mask, vMaskCoord);\n float alphaMul = 1.0 - npmAlpha * (1.0 - masky.a);\n\n original *= (alphaMul * masky.r * alpha * clip);\n\n gl_FragColor = original;\n}\n"), t.renderable = !1, this.maskSprite = t, this.maskMatrix = e
+ }
+ return r && (SpriteMaskFilter.__proto__ = r), ((SpriteMaskFilter.prototype = Object.create(r && r.prototype)).constructor = SpriteMaskFilter).prototype.apply = function(t, e, r, n) {
+ var i = this.maskSprite,
+ o = this.maskSprite.texture;
+ o.valid && (o.transform || (o.transform = new ke(o, 0)), o.transform.update(), this.uniforms.npmAlpha = o.baseTexture.premultiplyAlpha ? 0 : 1, this.uniforms.mask = o, this.uniforms.otherMatrix = t.calculateSpriteMatrix(this.maskMatrix, i).prepend(o.transform.mapCoord), this.uniforms.alpha = i.worldAlpha, this.uniforms.maskClamp = o.transform.uClampFrame, t.applyFilter(this, e, r, n))
+ }, SpriteMaskFilter
+ }(De),
+ Be = function(e) {
+ function MaskSystem(t) {
+ e.call(this, t), this.scissor = !1, this.scissorData = null, this.scissorRenderTarget = null, this.enableScissor = !1, this.alphaMaskPool = [], this.alphaMaskIndex = 0
+ }
+ return e && (MaskSystem.__proto__ = e), ((MaskSystem.prototype = Object.create(e && e.prototype)).constructor = MaskSystem).prototype.push = function(t, e) {
+ if (e.isSprite) this.pushSpriteMask(t, e);
+ else if (this.enableScissor && !this.scissor && this.renderer._activeRenderTarget.root && !this.renderer.stencil.stencilMaskStack.length && e.isFastRect()) {
+ var r = e.worldTransform,
+ n = Math.atan2(r.b, r.a);
+ (n = Math.round(n * (180 / Math.PI))) % 90 ? this.pushStencilMask(e) : this.pushScissorMask(t, e)
+ } else this.pushStencilMask(e)
+ }, MaskSystem.prototype.pop = function(t, e) {
+ e.isSprite ? this.popSpriteMask(t, e) : this.enableScissor && !this.renderer.stencil.stencilMaskStack.length ? this.popScissorMask(t, e) : this.popStencilMask(t, e)
+ }, MaskSystem.prototype.pushSpriteMask = function(t, e) {
+ var r = this.alphaMaskPool[this.alphaMaskIndex];
+ r || (r = this.alphaMaskPool[this.alphaMaskIndex] = [new Ne(e)]), r[0].resolution = this.renderer.resolution, r[0].maskSprite = e;
+ var n = t.filterArea;
+ t.filterArea = e.getBounds(!0), this.renderer.filter.push(t, r), t.filterArea = n, this.alphaMaskIndex++
+ }, MaskSystem.prototype.popSpriteMask = function() {
+ this.renderer.filter.pop(), this.alphaMaskIndex--
+ }, MaskSystem.prototype.pushStencilMask = function(t) {
+ this.renderer.batch.flush(), this.renderer.stencil.pushStencil(t)
+ }, MaskSystem.prototype.popStencilMask = function() {
+ this.renderer.stencil.popStencil()
+ }, MaskSystem.prototype.pushScissorMask = function(t, e) {
+ e.renderable = !0;
+ var r = this.renderer._activeRenderTarget,
+ n = e.getBounds();
+ n.fit(r.size), e.renderable = !1, this.renderer.gl.enable(this.renderer.gl.SCISSOR_TEST);
+ var i = this.renderer.resolution;
+ this.renderer.gl.scissor(n.x * i, (r.root ? r.size.height - n.y - n.height : n.y) * i, n.width * i, n.height * i), this.scissorRenderTarget = r, this.scissorData = e, this.scissor = !0
+ }, MaskSystem.prototype.popScissorMask = function() {
+ this.scissorRenderTarget = null, this.scissorData = null, this.scissor = !1;
+ var t = this.renderer.gl;
+ t.disable(t.SCISSOR_TEST)
+ }, MaskSystem
+ }(Ut),
+ Ue = function(e) {
+ function StencilSystem(t) {
+ e.call(this, t), this.stencilMaskStack = []
+ }
+ return e && (StencilSystem.__proto__ = e), ((StencilSystem.prototype = Object.create(e && e.prototype)).constructor = StencilSystem).prototype.setMaskStack = function(t) {
+ var e = this.renderer.gl;
+ t.length !== this.stencilMaskStack.length && (0 === t.length ? e.disable(e.STENCIL_TEST) : e.enable(e.STENCIL_TEST)), this.stencilMaskStack = t
+ }, StencilSystem.prototype.pushStencil = function(t) {
+ var e = this.renderer.gl,
+ r = this.stencilMaskStack.length;
+ 0 === r && e.enable(e.STENCIL_TEST), this.stencilMaskStack.push(t), e.colorMask(!1, !1, !1, !1), e.stencilFunc(e.EQUAL, r, this._getBitwiseMask()), e.stencilOp(e.KEEP, e.KEEP, e.INCR), t.renderable = !0, t.render(this.renderer), this.renderer.batch.flush(), t.renderable = !1, this._useCurrent()
+ }, StencilSystem.prototype.popStencil = function() {
+ var t = this.renderer.gl,
+ e = this.stencilMaskStack.pop();
+ 0 === this.stencilMaskStack.length ? (t.disable(t.STENCIL_TEST), t.clear(t.STENCIL_BUFFER_BIT), t.clearStencil(0)) : (t.colorMask(!1, !1, !1, !1), t.stencilOp(t.KEEP, t.KEEP, t.DECR), e.renderable = !0, e.render(this.renderer), this.renderer.batch.flush(), e.renderable = !1, this._useCurrent())
+ }, StencilSystem.prototype._useCurrent = function() {
+ var t = this.renderer.gl;
+ t.colorMask(!0, !0, !0, !0), t.stencilFunc(t.EQUAL, this.stencilMaskStack.length, this._getBitwiseMask()), t.stencilOp(t.KEEP, t.KEEP, t.KEEP)
+ }, StencilSystem.prototype._getBitwiseMask = function() {
+ return (1 << this.stencilMaskStack.length) - 1
+ }, StencilSystem.prototype.destroy = function() {
+ e.prototype.destroy.call(this, this), this.stencilMaskStack = null
+ }, StencilSystem
+ }(Ut),
+ Ge = function(e) {
+ function ProjectionSystem(t) {
+ e.call(this, t), this.destinationFrame = null, this.sourceFrame = null, this.defaultFrame = null, this.projectionMatrix = new Y, this.transform = null
+ }
+ return e && (ProjectionSystem.__proto__ = e), ((ProjectionSystem.prototype = Object.create(e && e.prototype)).constructor = ProjectionSystem).prototype.update = function(t, e, r, n) {
+ this.destinationFrame = t || this.destinationFrame || this.defaultFrame, this.sourceFrame = e || this.sourceFrame || t, this.calculateProjection(this.destinationFrame, this.sourceFrame, r, n), this.transform && this.projectionMatrix.append(this.transform);
+ var i = this.renderer;
+ i.globalUniforms.uniforms.projectionMatrix = this.projectionMatrix, i.globalUniforms.update(), i.shader.shader && i.shader.syncUniformGroup(i.shader.shader.uniforms.globals)
+ }, ProjectionSystem.prototype.calculateProjection = function(t, e, r, n) {
+ var i = this.projectionMatrix;
+ i.ty = n ? (i.a = 1 / t.width * 2 * r, i.d = -1 / t.height * 2 * r, i.tx = -1 - e.x * i.a, 1 - e.y * i.d) : (i.a = 1 / t.width * 2 * r, i.d = 1 / t.height * 2 * r, i.tx = -1 - e.x * i.a, -1 - e.y * i.d)
+ }, ProjectionSystem.prototype.setTransform = function() {}, ProjectionSystem
+ }(Ut),
+ je = new ot,
+ ze = function(e) {
+ function RenderTextureSystem(t) {
+ e.call(this, t), this.clearColor = t._backgroundColorRgba, this.defaultMaskStack = [], this.current = null, this.sourceFrame = new ot, this.destinationFrame = new ot
+ }
+ return e && (RenderTextureSystem.__proto__ = e), ((RenderTextureSystem.prototype = Object.create(e && e.prototype)).constructor = RenderTextureSystem).prototype.bind = function(t, e, r) {
+ void 0 === t && (t = null), this.current = t;
+ var n, i = this.renderer;
+ if (t) {
+ var o = t.baseTexture;
+ n = o.resolution, r || (je.width = o.realWidth, je.height = o.realHeight, r = je), e || (e = r), this.renderer.framebuffer.bind(o.framebuffer, r), this.renderer.projection.update(r, e, n, !1), this.renderer.stencil.setMaskStack(o.stencilMaskStack)
+ } else n = this.renderer.resolution, r || (je.width = i.width, je.height = i.height, r = je), e || (e = r), i.framebuffer.bind(null, r), this.renderer.projection.update(r, e, n, !0), this.renderer.stencil.setMaskStack(this.defaultMaskStack);
+ this.sourceFrame.copyFrom(e), this.destinationFrame.x = r.x / n, this.destinationFrame.y = r.y / n, this.destinationFrame.width = r.width / n, this.destinationFrame.height = r.height / n
+ }, RenderTextureSystem.prototype.clear = function(t) {
+ t = this.current ? t || this.current.baseTexture.clearColor : t || this.clearColor, this.renderer.framebuffer.clear(t[0], t[1], t[2], t[3])
+ }, RenderTextureSystem.prototype.resize = function() {
+ this.bind(null)
+ }, RenderTextureSystem.prototype.reset = function() {
+ this.bind(null)
+ }, RenderTextureSystem
+ }(Ut),
+ Xe = function(t, e) {
+ this.program = t, this.uniformData = e, this.uniformGroups = {}
+ };
+ Xe.prototype.destroy = function() {
+ this.uniformData = null, this.uniformGroups = null, this.program = null
+ };
+ var Ve = 0,
+ qe = function(e) {
+ function ShaderSystem(t) {
+ e.call(this, t), this.systemCheck(), this.gl = null, this.shader = null, this.program = null, this.cache = {}, this.id = Ve++
+ }
+ return e && (ShaderSystem.__proto__ = e), ((ShaderSystem.prototype = Object.create(e && e.prototype)).constructor = ShaderSystem).prototype.systemCheck = function() {
+ if (! function() {
+ if ("boolean" == typeof Te) return Te;
+ try {
+ var t = new Function("param1", "param2", "param3", "return param1[param2] === param3;");
+ Te = !0 === t({
+ a: "b"
+ }, "a", "b")
+ } catch (t) {
+ Te = !1
+ }
+ return Te
+ }()) throw new Error("Current environment does not allow unsafe-eval, please use @pixi/unsafe-eval module to enable support.")
+ }, ShaderSystem.prototype.contextChange = function(t) {
+ this.gl = t
+ }, ShaderSystem.prototype.bind = function(t, e) {
+ t.uniforms.globals = this.renderer.globalUniforms;
+ var r = t.program,
+ n = r.glPrograms[this.renderer.CONTEXT_UID] || this.generateShader(t);
+ return this.shader = t, this.program !== r && (this.program = r, this.gl.useProgram(n.program)), e || this.syncUniformGroup(t.uniformGroup), n
+ }, ShaderSystem.prototype.setUniforms = function(t) {
+ var e = this.shader.program,
+ r = e.glPrograms[this.renderer.CONTEXT_UID];
+ e.syncUniforms(r.uniformData, t, this.renderer)
+ }, ShaderSystem.prototype.syncUniformGroup = function(t) {
+ var e = this.getglProgram();
+ t.static && t.dirtyId === e.uniformGroups[t.id] || (e.uniformGroups[t.id] = t.dirtyId, this.syncUniforms(t, e))
+ }, ShaderSystem.prototype.syncUniforms = function(t, e) {
+ (t.syncUniforms[this.shader.program.id] || this.createSyncGroups(t))(e.uniformData, t.uniforms, this.renderer)
+ }, ShaderSystem.prototype.createSyncGroups = function(t) {
+ var e = this.getSignature(t, this.shader.program.uniformData);
+ return this.cache[e] || (this.cache[e] = function(t, e) {
+ var r = 0,
+ n = "var v = null;\n var cv = null\n var gl = renderer.gl";
+ for (var i in t.uniforms) {
+ var o = e[i];
+ o ? "float" === o.type && 1 === o.size ? n += "\n if(uv." + i + " !== ud." + i + ".value)\n {\n ud." + i + ".value = uv." + i + "\n gl.uniform1f(ud." + i + ".location, uv." + i + ")\n }\n" : "sampler2D" !== o.type && "samplerCube" !== o.type && "sampler2DArray" !== o.type || 1 !== o.size || o.isArray ? "mat3" === o.type && 1 === o.size ? void 0 !== t.uniforms[i].a ? n += "\n gl.uniformMatrix3fv(ud." + i + ".location, false, uv." + i + ".toArray(true));\n \n" : n += "\n gl.uniformMatrix3fv(ud." + i + ".location, false, uv." + i + ");\n \n" : "vec2" === o.type && 1 === o.size ? void 0 !== t.uniforms[i].x ? n += "\n cv = ud." + i + ".value;\n v = uv." + i + ";\n\n if(cv[0] !== v.x || cv[1] !== v.y)\n {\n cv[0] = v.x;\n cv[1] = v.y;\n gl.uniform2f(ud." + i + ".location, v.x, v.y);\n }\n" : n += "\n cv = ud." + i + ".value;\n v = uv." + i + ";\n\n if(cv[0] !== v[0] || cv[1] !== v[1])\n {\n cv[0] = v[0];\n cv[1] = v[1];\n gl.uniform2f(ud." + i + ".location, v[0], v[1]);\n }\n \n" : "vec4" === o.type && 1 === o.size ? void 0 !== t.uniforms[i].width ? n += "\n cv = ud." + i + ".value;\n v = uv." + i + ";\n\n if(cv[0] !== v.x || cv[1] !== v.y || cv[2] !== v.width || cv[3] !== v.height)\n {\n cv[0] = v.x;\n cv[1] = v.y;\n cv[2] = v.width;\n cv[3] = v.height;\n gl.uniform4f(ud." + i + ".location, v.x, v.y, v.width, v.height)\n }\n" : n += "\n cv = ud." + i + ".value;\n v = uv." + i + ";\n\n if(cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3])\n {\n cv[0] = v[0];\n cv[1] = v[1];\n cv[2] = v[2];\n cv[3] = v[3];\n\n gl.uniform4f(ud." + i + ".location, v[0], v[1], v[2], v[3])\n }\n \n" : n += "\n cv = ud." + i + ".value;\n v = uv." + i + ";\n " + (1 === o.size ? be : xe)[o.type].replace("location", "ud." + i + ".location") + ";\n" : (n += "\n renderer.texture.bind(uv." + i + ", " + r + ");\n\n if(ud." + i + ".value !== " + r + ")\n {\n ud." + i + ".value = " + r + ";\n gl.uniform1i(ud." + i + ".location, " + r + ");\n; // eslint-disable-line max-len\n }\n", r++) : t.uniforms[i].group && (n += "\n renderer.shader.syncUniformGroup(uv." + i + ");\n ")
+ }
+ return new Function("ud", "uv", "renderer", n)
+ }(t, this.shader.program.uniformData)), t.syncUniforms[this.shader.program.id] = this.cache[e], t.syncUniforms[this.shader.program.id]
+ }, ShaderSystem.prototype.getSignature = function(t, e) {
+ var r = t.uniforms,
+ n = [];
+ for (var i in r) n.push(i), e[i] && n.push(e[i].type);
+ return n.join("-")
+ }, ShaderSystem.prototype.getglProgram = function() {
+ return this.shader ? this.shader.program.glPrograms[this.renderer.CONTEXT_UID] : null
+ }, ShaderSystem.prototype.generateShader = function(t) {
+ var e = this.gl,
+ r = t.program,
+ n = {};
+ for (var i in r.attributeData) n[i] = r.attributeData[i].location;
+ var o = compileProgram(e, r.vertexSrc, r.fragmentSrc, n),
+ a = {};
+ for (var s in r.uniformData) {
+ var u = r.uniformData[s];
+ a[s] = {
+ location: e.getUniformLocation(o, s),
+ value: core_es_defaultValue(u.type, u.size)
+ }
+ }
+ var h = new Xe(o, a);
+ return r.glPrograms[this.renderer.CONTEXT_UID] = h
+ }, ShaderSystem.prototype.reset = function() {
+ this.program = null, this.shader = null
+ }, ShaderSystem.prototype.destroy = function() {
+ this.destroyed = !0
+ }, ShaderSystem
+ }(Ut);
+ var He = function(e) {
+ function StateSystem(t) {
+ e.call(this, t), this.gl = null, this.stateId = 0, this.polygonOffset = 0, this.blendMode = y.NONE, this._blendEq = !1, this.map = [], this.map[0] = this.setBlend, this.map[1] = this.setOffset, this.map[2] = this.setCullFace, this.map[3] = this.setDepthTest, this.map[4] = this.setFrontFace, this.checks = [], this.defaultState = new Ce, this.defaultState.blend = !0, this.defaultState.depth = !0
+ }
+ return e && (StateSystem.__proto__ = e), ((StateSystem.prototype = Object.create(e && e.prototype)).constructor = StateSystem).prototype.contextChange = function(t) {
+ var e, r;
+ this.gl = t, this.blendModes = (e = t, void 0 === r && (r = []), r[y.NORMAL] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.ADD] = [e.ONE, e.DST_ALPHA, e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.MULTIPLY] = [e.DST_COLOR, e.ONE_MINUS_SRC_ALPHA, e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.SCREEN] = [e.ONE, e.ONE_MINUS_SRC_COLOR, e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.OVERLAY] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.DARKEN] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.LIGHTEN] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.COLOR_DODGE] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.COLOR_BURN] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.HARD_LIGHT] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.SOFT_LIGHT] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.DIFFERENCE] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.EXCLUSION] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.HUE] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.SATURATION] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.COLOR] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.LUMINOSITY] = [e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.NONE] = [0, 0], r[y.NORMAL_NPM] = [e.SRC_ALPHA, e.ONE_MINUS_SRC_ALPHA, e.ONE, e.ONE_MINUS_SRC_ALPHA], r[y.ADD_NPM] = [e.SRC_ALPHA, e.DST_ALPHA, e.ONE, e.DST_ALPHA], r[y.SCREEN_NPM] = [e.SRC_ALPHA, e.ONE_MINUS_SRC_COLOR, e.ONE, e.ONE_MINUS_SRC_COLOR], r[y.SRC_IN] = [e.DST_ALPHA, e.ZERO], r[y.SRC_OUT] = [e.ONE_MINUS_DST_ALPHA, e.ZERO], r[y.SRC_ATOP] = [e.DST_ALPHA, e.ONE_MINUS_SRC_ALPHA], r[y.DST_OVER] = [e.ONE_MINUS_DST_ALPHA, e.ONE], r[y.DST_IN] = [e.ZERO, e.SRC_ALPHA], r[y.DST_OUT] = [e.ZERO, e.ONE_MINUS_SRC_ALPHA], r[y.DST_ATOP] = [e.ONE_MINUS_DST_ALPHA, e.SRC_ALPHA], r[y.SUBTRACT] = [e.ONE, e.ONE, e.ONE, e.ONE, e.FUNC_REVERSE_SUBTRACT, e.FUNC_ADD], r), this.setState(this.defaultState), this.reset()
+ }, StateSystem.prototype.setState = function(t) {
+ if (t = t || this.defaultState, this.stateId !== t.data) {
+ for (var e = this.stateId ^ t.data, r = 0; e;) 1 & e && this.map[r].call(this, !!(t.data & 1 << r)), e >>= 1, r++;
+ this.stateId = t.data
+ }
+ for (var n = 0; n < this.checks.length; n++) this.checks[n](this, t)
+ }, StateSystem.prototype.forceState = function(t) {
+ t = t || this.defaultState;
+ for (var e = 0; e < this.map.length; e++) this.map[e].call(this, !!(t.data & 1 << e));
+ for (var r = 0; r < this.checks.length; r++) this.checks[r](this, t);
+ this.stateId = t.data
+ }, StateSystem.prototype.setBlend = function(t) {
+ this.updateCheck(StateSystem.checkBlendMode, t), this.gl[t ? "enable" : "disable"](this.gl.BLEND)
+ }, StateSystem.prototype.setOffset = function(t) {
+ this.gl[t ? "enable" : "disable"](this.gl.POLYGON_OFFSET_FILL)
+ }, StateSystem.prototype.setDepthTest = function(t) {
+ this.gl[t ? "enable" : "disable"](this.gl.DEPTH_TEST)
+ }, StateSystem.prototype.setCullFace = function(t) {
+ this.gl[t ? "enable" : "disable"](this.gl.CULL_FACE)
+ }, StateSystem.prototype.setFrontFace = function(t) {
+ this.gl.frontFace(this.gl[t ? "CW" : "CCW"])
+ }, StateSystem.prototype.setBlendMode = function(t) {
+ if (t !== this.blendMode) {
+ this.blendMode = t;
+ var e = this.blendModes[t],
+ r = this.gl;
+ 2 === e.length ? r.blendFunc(e[0], e[1]) : r.blendFuncSeparate(e[0], e[1], e[2], e[3]), 6 === e.length ? (this._blendEq = !0, r.blendEquationSeparate(e[4], e[5])) : this._blendEq && (this._blendEq = !1, r.blendEquationSeparate(r.FUNC_ADD, r.FUNC_ADD))
+ }
+ }, StateSystem.prototype.setPolygonOffset = function(t, e) {
+ this.gl.polygonOffset(t, e)
+ }, StateSystem.prototype.reset = function() {
+ this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, !1), this.forceState(0), this._blendEq = !0, this.blendMode = -1, this.setBlendMode(0)
+ }, StateSystem.prototype.updateCheck = function(t, e) {
+ var r = this.checks.indexOf(t);
+ e && -1 === r ? this.checks.push(t) : e || -1 === r || this.checks.splice(r, 1)
+ }, StateSystem.checkBlendMode = function(t, e) {
+ t.setBlendMode(e.blendMode)
+ }, StateSystem
+ }(Ut),
+ We = function(e) {
+ function TextureGCSystem(t) {
+ e.call(this, t), this.count = 0, this.checkCount = 0, this.maxIdle = M.GC_MAX_IDLE, this.checkCountMax = M.GC_MAX_CHECK_COUNT, this.mode = M.GC_MODE
+ }
+ return e && (TextureGCSystem.__proto__ = e), ((TextureGCSystem.prototype = Object.create(e && e.prototype)).constructor = TextureGCSystem).prototype.postrender = function() {
+ this.count++, this.mode !== A.MANUAL && (this.checkCount++, this.checkCount > this.checkCountMax && (this.checkCount = 0, this.run()))
+ }, TextureGCSystem.prototype.run = function() {
+ for (var t = this.renderer.texture, e = t.managedTextures, r = !1, n = 0; n < e.length; n++) {
+ var i = e[n];
+ !i.framebuffer && this.count - i.touched > this.maxIdle && (t.destroyTexture(i, !0), r = !(e[n] = null))
+ }
+ if (r) {
+ for (var o = 0, a = 0; a < e.length; a++) null !== e[a] && (e[o++] = e[a]);
+ e.length = o
+ }
+ }, TextureGCSystem.prototype.unload = function(t) {
+ var e = this.renderer.textureSystem;
+ t._texture && t._texture._glRenderTargets && e.destroyTexture(t._texture);
+ for (var r = t.children.length - 1; 0 <= r; r--) this.unload(t.children[r])
+ }, TextureGCSystem
+ }(Ut),
+ Ye = function(t) {
+ this.texture = t, this.width = -1, this.height = -1, this.dirtyId = -1, this.dirtyStyleId = -1, this.mipmap = !1, this.wrapMode = 33071
+ },
+ Ke = function(e) {
+ function TextureSystem(t) {
+ e.call(this, t), this.boundTextures = [], this.currentLocation = -1, this.managedTextures = [], this._unknownBoundTextures = !1, this.unknownTexture = new Rt
+ }
+ return e && (TextureSystem.__proto__ = e), ((TextureSystem.prototype = Object.create(e && e.prototype)).constructor = TextureSystem).prototype.contextChange = function() {
+ var t = this.gl = this.renderer.gl;
+ this.CONTEXT_UID = this.renderer.CONTEXT_UID, this.webGLVersion = this.renderer.context.webGLVersion;
+ var e = t.getParameter(t.MAX_TEXTURE_IMAGE_UNITS);
+ this.boundTextures.length = e;
+ for (var r = 0; r < e; r++) this.boundTextures[r] = null;
+ this.emptyTextures = {};
+ var n = new Ye(t.createTexture());
+ t.bindTexture(t.TEXTURE_2D, n.texture), t.texImage2D(t.TEXTURE_2D, 0, t.RGBA, 1, 1, 0, t.RGBA, t.UNSIGNED_BYTE, new Uint8Array(4)), this.emptyTextures[t.TEXTURE_2D] = n, this.emptyTextures[t.TEXTURE_CUBE_MAP] = new Ye(t.createTexture()), t.bindTexture(t.TEXTURE_CUBE_MAP, this.emptyTextures[t.TEXTURE_CUBE_MAP].texture);
+ for (var i = 0; i < 6; i++) t.texImage2D(t.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, t.RGBA, 1, 1, 0, t.RGBA, t.UNSIGNED_BYTE, null);
+ t.texParameteri(t.TEXTURE_CUBE_MAP, t.TEXTURE_MAG_FILTER, t.LINEAR), t.texParameteri(t.TEXTURE_CUBE_MAP, t.TEXTURE_MIN_FILTER, t.LINEAR);
+ for (var o = 0; o < this.boundTextures.length; o++) this.bind(null, o)
+ }, TextureSystem.prototype.bind = function(t, e) {
+ void 0 === e && (e = 0);
+ var r = this.gl;
+ if (t) {
+ if ((t = t.baseTexture || t).valid) {
+ t.touched = this.renderer.textureGC.count;
+ var n = t._glTextures[this.CONTEXT_UID] || this.initTexture(t);
+ this.currentLocation !== e && (this.currentLocation = e, r.activeTexture(r.TEXTURE0 + e)), this.boundTextures[e] !== t && r.bindTexture(t.target, n.texture), n.dirtyId !== t.dirtyId && this.updateTexture(t), this.boundTextures[e] = t
+ }
+ } else this.currentLocation !== e && (this.currentLocation = e, r.activeTexture(r.TEXTURE0 + e)), r.bindTexture(r.TEXTURE_2D, this.emptyTextures[r.TEXTURE_2D].texture), this.boundTextures[e] = null
+ }, TextureSystem.prototype.reset = function() {
+ this._unknownBoundTextures = !0, this.currentLocation = -1;
+ for (var t = 0; t < this.boundTextures.length; t++) this.boundTextures[t] = this.unknownTexture
+ }, TextureSystem.prototype.unbind = function(t) {
+ var e = this.gl,
+ r = this.boundTextures;
+ if (this._unknownBoundTextures) {
+ this._unknownBoundTextures = !1;
+ for (var n = 0; n < r.length; n++) r[n] === this.unknownTexture && this.bind(null, n)
+ }
+ for (var i = 0; i < r.length; i++) r[i] === t && (this.currentLocation !== i && (e.activeTexture(e.TEXTURE0 + i), this.currentLocation = i), e.bindTexture(e.TEXTURE_2D, this.emptyTextures[t.target].texture), r[i] = null)
+ }, TextureSystem.prototype.initTexture = function(t) {
+ var e = new Ye(this.gl.createTexture());
+ return e.dirtyId = -1, t._glTextures[this.CONTEXT_UID] = e, this.managedTextures.push(t), t.on("dispose", this.destroyTexture, this), e
+ }, TextureSystem.prototype.updateTexture = function(t) {
+ var e = t._glTextures[this.CONTEXT_UID],
+ r = this.renderer;
+ if (t.resource && t.resource.upload(r, t, e));
+ else {
+ var n = t.realWidth,
+ i = t.realHeight,
+ o = r.gl;
+ (e.width !== n || e.height !== i || e.dirtyId < 0) && (e.width = n, e.height = i, o.texImage2D(t.target, 0, t.format, n, i, 0, t.format, t.type, null))
+ }
+ t.dirtyStyleId !== e.dirtyStyleId && this.updateTextureStyle(t), e.dirtyId = t.dirtyId
+ }, TextureSystem.prototype.destroyTexture = function(t, e) {
+ var r = this.gl;
+ if ((t = t.baseTexture || t)._glTextures[this.renderer.CONTEXT_UID] && (this.unbind(t), r.deleteTexture(t._glTextures[this.renderer.CONTEXT_UID].texture), t.off("dispose", this.destroyTexture, this), delete t._glTextures[this.renderer.CONTEXT_UID], !e)) {
+ var n = this.managedTextures.indexOf(t); - 1 !== n && removeItems(this.managedTextures, n, 1)
+ }
+ }, TextureSystem.prototype.updateTextureStyle = function(t) {
+ var e = t._glTextures[this.CONTEXT_UID];
+ e && (t.mipmap !== E.POW2 && 2 === this.webGLVersion || t.isPowerOfTwo ? (e.mipmap = 1 <= t.mipmap, e.wrapMode = t.wrapMode) : (e.mipmap = 0, e.wrapMode = S.CLAMP), t.resource && t.resource.style(this.renderer, t, e) || this.setStyle(t, e), e.dirtyStyleId = t.dirtyStyleId)
+ }, TextureSystem.prototype.setStyle = function(t, e) {
+ var r = this.gl;
+ e.mipmap && r.generateMipmap(t.target), r.texParameteri(t.target, r.TEXTURE_WRAP_S, e.wrapMode), r.texParameteri(t.target, r.TEXTURE_WRAP_T, e.wrapMode), e.mipmap ? r.texParameteri(t.target, r.TEXTURE_MIN_FILTER, t.scaleMode ? r.LINEAR_MIPMAP_LINEAR : r.NEAREST_MIPMAP_NEAREST) : r.texParameteri(t.target, r.TEXTURE_MIN_FILTER, t.scaleMode ? r.LINEAR : r.NEAREST), r.texParameteri(t.target, r.TEXTURE_MAG_FILTER, t.scaleMode ? r.LINEAR : r.NEAREST)
+ }, TextureSystem
+ }(Ut),
+ Ze = {
+ FilterSystem: ue,
+ BatchSystem: ce,
+ ContextSystem: fe,
+ FramebufferSystem: de,
+ GeometrySystem: ve,
+ MaskSystem: Be,
+ StencilSystem: Ue,
+ ProjectionSystem: Ge,
+ RenderTextureSystem: ze,
+ ShaderSystem: qe,
+ StateSystem: He,
+ TextureGCSystem: We,
+ TextureSystem: Ke
+ },
+ Qe = new Y,
+ Je = function(r) {
+ function AbstractRenderer(t, e) {
+ r.call(this), (e = Object.assign({}, M.RENDER_OPTIONS, e)).roundPixels && (M.ROUND_PIXELS = e.roundPixels, deprecation(0, "Renderer roundPixels option is deprecated, please use PIXI.settings.ROUND_PIXELS", 2)), this.options = e, this.type = g.UNKNOWN, this.screen = new ot(0, 0, e.width, e.height), this.view = e.view || document.createElement("canvas"), this.resolution = e.resolution || M.RESOLUTION, this.transparent = e.transparent, this.autoDensity = e.autoDensity || e.autoResize || !1, this.preserveDrawingBuffer = e.preserveDrawingBuffer, this.clearBeforeRender = e.clearBeforeRender, this._backgroundColor = 0, this._backgroundColorRgba = [0, 0, 0, 0], this._backgroundColorString = "#000000", this.backgroundColor = e.backgroundColor || this._backgroundColor, this._tempDisplayObjectParent = new pt, this._lastObjectRendered = this._tempDisplayObjectParent, this.plugins = {}
+ }
+ r && (AbstractRenderer.__proto__ = r);
+ var t = {
+ width: {
+ configurable: !0
+ },
+ height: {
+ configurable: !0
+ },
+ backgroundColor: {
+ configurable: !0
+ }
+ };
+ return ((AbstractRenderer.prototype = Object.create(r && r.prototype)).constructor = AbstractRenderer).prototype.initPlugins = function(t) {
+ for (var e in t) this.plugins[e] = new t[e](this)
+ }, t.width.get = function() {
+ return this.view.width
+ }, t.height.get = function() {
+ return this.view.height
+ }, AbstractRenderer.prototype.resize = function(t, e) {
+ this.screen.width = t, this.screen.height = e, this.view.width = t * this.resolution, this.view.height = e * this.resolution, this.autoDensity && (this.view.style.width = t + "px", this.view.style.height = e + "px")
+ }, AbstractRenderer.prototype.generateTexture = function(t, e, r, n) {
+ 0 === (n = n || t.getLocalBounds()).width && (n.width = 1), 0 === n.height && (n.height = 1);
+ var i = Wt.create(0 | n.width, 0 | n.height, e, r);
+ return Qe.tx = -n.x, Qe.ty = -n.y, this.render(t, i, !1, Qe, !!t.parent), i
+ }, AbstractRenderer.prototype.destroy = function(t) {
+ for (var e in this.plugins) this.plugins[e].destroy(), this.plugins[e] = null;
+ t && this.view.parentNode && this.view.parentNode.removeChild(this.view), this.plugins = null, this.type = g.UNKNOWN, this.view = null, this.screen = null, this.resolution = 0, this.transparent = !1, this.autoDensity = !1, this.blendModes = null, this.options = null, this.preserveDrawingBuffer = !1, this.clearBeforeRender = !1, this._backgroundColor = 0, this._backgroundColorRgba = null, this._backgroundColorString = null, this._tempDisplayObjectParent = null, this._lastObjectRendered = null
+ }, t.backgroundColor.get = function() {
+ return this._backgroundColor
+ }, t.backgroundColor.set = function(t) {
+ this._backgroundColor = t, this._backgroundColorString = hex2string(t), hex2rgb(t, this._backgroundColorRgba)
+ }, Object.defineProperties(AbstractRenderer.prototype, t), AbstractRenderer
+ }(l.a),
+ $e = function(r) {
+ function Renderer(t) {
+ void 0 === t && (t = {}), r.call(this, "WebGL", t), t = this.options, this.type = g.WEBGL, this.gl = null, this.CONTEXT_UID = 0, this.runners = {
+ destroy: new gt("destroy"),
+ contextChange: new gt("contextChange", 1),
+ reset: new gt("reset"),
+ update: new gt("update"),
+ postrender: new gt("postrender"),
+ prerender: new gt("prerender"),
+ resize: new gt("resize", 2)
+ }, this.globalUniforms = new oe({
+ projectionMatrix: new Y
+ }, !0), this.addSystem(Be, "mask").addSystem(fe, "context").addSystem(He, "state").addSystem(qe, "shader").addSystem(Ke, "texture").addSystem(ve, "geometry").addSystem(de, "framebuffer").addSystem(Ue, "stencil").addSystem(Ge, "projection").addSystem(We, "textureGC").addSystem(ue, "filter").addSystem(ze, "renderTexture").addSystem(ce, "batch"), this.initPlugins(Renderer.__plugins), t.context ? this.context.initFromContext(t.context) : this.context.initFromOptions({
+ alpha: this.transparent,
+ antialias: t.antialias,
+ premultipliedAlpha: this.transparent && "notMultiplied" !== this.transparent,
+ stencil: !0,
+ preserveDrawingBuffer: t.preserveDrawingBuffer,
+ powerPreference: this.options.powerPreference
+ }), this.renderingToScreen = !0, sayHello(2 === this.context.webGLVersion ? "WebGL 2" : "WebGL 1"), this.resize(this.options.width, this.options.height)
+ }
+ return r && (Renderer.__proto__ = r), ((Renderer.prototype = Object.create(r && r.prototype)).constructor = Renderer).create = function(t) {
+ if (isWebGLSupported()) return new Renderer(t);
+ throw new Error('WebGL unsupported in this browser, use "pixi.js-legacy" for fallback canvas2d support.')
+ }, Renderer.prototype.addSystem = function(t, e) {
+ e || (e = t.name);
+ var r = new t(this);
+ if (this[e]) throw new Error('Whoops! The name "' + e + '" is already in use');
+ for (var n in this[e] = r, this.runners) this.runners[n].add(r);
+ return this
+ }, Renderer.prototype.render = function(t, e, r, n, i) {
+ if (this.renderingToScreen = !e, this.runners.prerender.run(), this.emit("prerender"), !this.context.isLost) {
+ if (e || (this._lastObjectRendered = t), !i) {
+ var o = t.parent;
+ t.parent = this._tempDisplayObjectParent, t.updateTransform(), t.parent = o
+ }
+ this.renderTexture.bind(e), this.batch.currentRenderer.start(), (void 0 !== r ? r : this.clearBeforeRender) && this.renderTexture.clear(), t.render(this), this.batch.currentRenderer.flush(), e && e.baseTexture.update(), this.runners.postrender.run(), this.emit("postrender")
+ }
+ }, Renderer.prototype.resize = function(t, e) {
+ r.prototype.resize.call(this, t, e), this.runners.resize.run(t, e)
+ }, Renderer.prototype.reset = function() {
+ return this.runners.reset.run(), this
+ }, Renderer.prototype.clear = function() {
+ this.framebuffer.bind(), this.framebuffer.clear()
+ }, Renderer.prototype.destroy = function(t) {
+ this.runners.destroy.run(), r.prototype.destroy.call(this, t), this.gl = null
+ }, Renderer.registerPlugin = function(t, e) {
+ (Renderer.__plugins = Renderer.__plugins || {})[t] = e
+ }, Renderer
+ }(Je);
+
+ function autoDetectRenderer(t) {
+ return $e.create(t)
+ }
+ var tr = "attribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n vTextureCoord = aTextureCoord;\n}",
+ er = "attribute vec2 aVertexPosition;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n\nuniform vec4 inputSize;\nuniform vec4 outputFrame;\n\nvec4 filterVertexPosition( void )\n{\n vec2 position = aVertexPosition * max(outputFrame.zw, vec2(0.)) + outputFrame.xy;\n\n return vec4((projectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0);\n}\n\nvec2 filterTextureCoord( void )\n{\n return aVertexPosition * (outputFrame.zw * inputSize.zw);\n}\n\nvoid main(void)\n{\n gl_Position = filterVertexPosition();\n vTextureCoord = filterTextureCoord();\n}\n",
+ rr = function(t) {
+ function CubeTexture() {
+ t.apply(this, arguments)
+ }
+ return t && (CubeTexture.__proto__ = t), ((CubeTexture.prototype = Object.create(t && t.prototype)).constructor = CubeTexture).from = function(t, e) {
+ return new CubeTexture(new kt(t, e))
+ }, CubeTexture
+ }(Rt),
+ nr = function(e) {
+ function BatchGeometry(t) {
+ void 0 === t && (t = !1), e.call(this), this._buffer = new Zt(null, t, !1), this._indexBuffer = new Zt(null, t, !0), this.addAttribute("aVertexPosition", this._buffer, 2, !1, w.FLOAT).addAttribute("aTextureCoord", this._buffer, 2, !1, w.FLOAT).addAttribute("aColor", this._buffer, 4, !0, w.UNSIGNED_BYTE).addAttribute("aTextureId", this._buffer, 1, !0, w.FLOAT).addIndex(this._indexBuffer)
+ }
+ return e && (BatchGeometry.__proto__ = e), (BatchGeometry.prototype = Object.create(e && e.prototype)).constructor = BatchGeometry
+ }(ee),
+ ir = function() {
+ this.textures = [], this.ids = [], this.blend = 0, this.textureCount = 0, this.start = 0, this.size = 0, this.type = 4
+ },
+ or = function(t) {
+ this.vertices = new ArrayBuffer(t), this.float32View = new Float32Array(this.vertices), this.uint32View = new Uint32Array(this.vertices)
+ };
+ or.prototype.destroy = function() {
+ this.vertices = null, this.float32View = null, this.uint32View = null
+ };
+ var ar = ["varying vec2 vTextureCoord;", "varying vec4 vColor;", "varying float vTextureId;", "uniform sampler2D uSamplers[%count%];", "void main(void){", "vec4 color;", "%forloop%", "gl_FragColor = color * vColor;", "}"].join("\n"),
+ sr = {},
+ ur = {};
+
+ function generateMultiTextureShader(t, e) {
+ if (!ur[e]) {
+ for (var r = new Int32Array(e), n = 0; n < e; n++) r[n] = n;
+ sr[e] = oe.from({
+ uSamplers: r
+ }, !0);
+ var i = ar;
+ i = (i = i.replace(/%count%/gi, e)).replace(/%forloop%/gi, function(t) {
+ var e = "";
+ e += "\n", e += "\n";
+ for (var r = 0; r < t; r++) 0 < r && (e += "\nelse "), r < t - 1 && (e += "if(vTextureId < " + r + ".5)"), e += "\n{", e += "\n\tcolor = texture2D(uSamplers[" + r + "], vTextureCoord);", e += "\n}";
+ return e += "\n", e += "\n"
+ }(e)), ur[e] = new Ae("precision highp float;\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec4 aColor;\nattribute float aTextureId;\n\nuniform mat3 projectionMatrix;\nuniform mat3 translationMatrix;\nuniform vec4 tint;\n\nvarying vec2 vTextureCoord;\nvarying vec4 vColor;\nvarying float vTextureId;\n\nvoid main(void){\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n\n vTextureCoord = aTextureCoord;\n vTextureId = aTextureId;\n vColor = aColor * tint;\n}\n", i)
+ }
+ var o = {
+ tint: new Float32Array([1, 1, 1, 1]),
+ translationMatrix: new Y,
+ default: sr[e]
+ };
+ return new Ie(ur[e], o)
+ }
+ var hr = 0,
+ cr = function(r) {
+ function BatchRenderer(t) {
+ r.call(this, t), this.vertSize = 6, this.vertByteSize = 4 * this.vertSize, this.size = 8e3, this.currentSize = 0, this.currentIndexSize = 0, this.attributeBuffers = {}, this.aBuffers = {}, this.iBuffers = {}, this.onlySprites = !1, this.shader = null, this.currentIndex = 0, this.groups = [];
+ for (var e = 0; e < this.size / 4; e++) this.groups[e] = new ir;
+ this.elements = [], this.vaos = [], this.vaoMax = 2, this.vertexCount = 0, this.renderer.on("prerender", this.onPrerender, this), this.state = Ce.for2d()
+ }
+ return r && (BatchRenderer.__proto__ = r), ((BatchRenderer.prototype = Object.create(r && r.prototype)).constructor = BatchRenderer).prototype.contextChange = function() {
+ var t = this.renderer.gl;
+ M.PREFER_ENV === v.WEBGL_LEGACY ? this.MAX_TEXTURES = 1 : (this.MAX_TEXTURES = Math.min(t.getParameter(t.MAX_TEXTURE_IMAGE_UNITS), M.SPRITE_MAX_TEXTURES), this.MAX_TEXTURES = checkMaxIfStatementsInShader(this.MAX_TEXTURES, t)), this.shader = generateMultiTextureShader(0, this.MAX_TEXTURES);
+ for (var e = 0; e < this.vaoMax; e++) this.vaos[e] = new nr
+ }, BatchRenderer.prototype.onPrerender = function() {
+ this.vertexCount = 0
+ }, BatchRenderer.prototype.render = function(t) {
+ t._texture.valid && (this.currentSize + t.vertexData.length / 2 > this.size && this.flush(), this.elements[this.currentIndex++] = t, this.currentSize += t.vertexData.length / 2, this.currentIndexSize += t.indices.length)
+ }, BatchRenderer.prototype.getIndexBuffer = function(t) {
+ var e = nextPow2(Math.ceil(t / 12)),
+ r = log2(e),
+ n = 12 * e;
+ this.iBuffers.length <= r && (this.iBuffers.length = r + 1);
+ var i = this.iBuffers[r];
+ return i || (this.iBuffers[r] = i = new Uint16Array(n)), i
+ }, BatchRenderer.prototype.getAttributeBuffer = function(t) {
+ var e = nextPow2(Math.ceil(t / 8)),
+ r = log2(e),
+ n = 8 * e;
+ this.aBuffers.length <= r && (this.iBuffers.length = r + 1);
+ var i = this.aBuffers[n];
+ return i || (this.aBuffers[n] = i = new or(n * this.vertByteSize)), i
+ }, BatchRenderer.prototype.flush = function() {
+ if (0 !== this.currentSize) {
+ var t, e, r, n = this.renderer.gl,
+ i = this.MAX_TEXTURES,
+ o = this.getAttributeBuffer(this.currentSize),
+ a = this.getIndexBuffer(this.currentIndexSize),
+ s = this.elements,
+ u = this.groups,
+ h = o.float32View,
+ c = o.uint32View,
+ l = this.renderer.textureGC.count,
+ f = 0,
+ d = 0,
+ p = 0,
+ m = 0,
+ v = u[0],
+ g = -1;
+ for (v.textureCount = 0, v.start = 0, v.blend = g, hr++, r = 0; r < this.currentIndex; ++r) {
+ var y = s[r];
+ s[r] = null, t = y._texture.baseTexture;
+ var _ = C[t.premultiplyAlpha ? 1 : 0][y.blendMode];
+ g !== _ && (g = _, e = null, m = i, hr++), e !== t && (e = t)._enabled !== hr && (m === i && (hr++, m = 0, v.size = d - v.start, (v = u[p++]).textureCount = 0, v.blend = g, v.start = d), t.touched = l, t._enabled = hr, t._id = m, v.textures[v.textureCount++] = t, m++), this.packGeometry(y, h, c, a, f, d), f += y.vertexData.length / 2 * this.vertSize, d += y.indices.length
+ }
+ v.size = d - v.start, M.CAN_UPLOAD_SAME_BUFFER ? (this.vaos[this.vertexCount]._buffer.update(o.vertices, 0), this.vaos[this.vertexCount]._indexBuffer.update(a, 0), this.renderer.geometry.updateBuffers()) : (this.vaoMax <= this.vertexCount && (this.vaoMax++, this.vaos[this.vertexCount] = new nr), this.vaos[this.vertexCount]._buffer.update(o.vertices, 0), this.vaos[this.vertexCount]._indexBuffer.update(a, 0), this.renderer.geometry.bind(this.vaos[this.vertexCount]), this.renderer.geometry.updateBuffers(), this.vertexCount++);
+ var b = this.renderer.texture,
+ x = this.renderer.state;
+ for (r = 0; r < p; r++) {
+ for (var w = u[r], T = w.textureCount, S = 0; S < T; S++) b.bind(w.textures[S], S), w.textures[S] = null;
+ x.setBlendMode(w.blend), n.drawElements(w.type, w.size, n.UNSIGNED_SHORT, 2 * w.start)
+ }
+ this.currentIndex = 0, this.currentSize = 0, this.currentIndexSize = 0
+ }
+ }, BatchRenderer.prototype.packGeometry = function(t, e, r, n, i, o) {
+ for (var a = i / this.vertSize, s = t.uvs, u = t.indices, h = t.vertexData, c = t._texture.baseTexture._id, l = Math.min(t.worldAlpha, 1), f = l < 1 && t._texture.baseTexture.premultiplyAlpha ? premultiplyTint(t._tintRGB, l) : t._tintRGB + (255 * l << 24), d = 0; d < h.length; d += 2) e[i++] = h[d], e[i++] = h[d + 1], e[i++] = s[d], e[i++] = s[d + 1], r[i++] = f, e[i++] = c;
+ for (var p = 0; p < u.length; p++) n[o++] = a + u[p]
+ }, BatchRenderer.prototype.start = function() {
+ this.renderer.state.setState(this.state), this.renderer.shader.bind(this.shader), M.CAN_UPLOAD_SAME_BUFFER && this.renderer.geometry.bind(this.vaos[this.vertexCount])
+ }, BatchRenderer.prototype.stop = function() {
+ this.flush()
+ }, BatchRenderer.prototype.destroy = function() {
+ for (var t = 0; t < this.vaoMax; t++) this.vaos[t] && this.vaos[t].destroy();
+ this.indexBuffer && this.indexBuffer.destroy(), this.renderer.off("prerender", this.onPrerender, this), this.shader && (this.shader.destroy(), this.shader = null), this.vaos = null, this.indexBuffer = null, this.indices = null, this.sprites = null, r.prototype.destroy.call(this)
+ }, BatchRenderer
+ }(he),
+ lr = new ot,
+ fr = function(t) {
+ (this.renderer = t).extract = this
+ };
+ fr.prototype.image = function(t) {
+ var e = new Image;
+ return e.src = this.base64(t), e
+ }, fr.prototype.base64 = function(t) {
+ return this.canvas(t).toDataURL()
+ }, fr.prototype.canvas = function(t) {
+ var e, r, n, i = this.renderer,
+ o = !1,
+ a = !1;
+ t && (t instanceof Wt ? n = t : (n = this.renderer.generateTexture(t), a = !0)), n ? (e = n.baseTexture.resolution, r = n.frame, o = !1, i.renderTexture.bind(n)) : (e = this.renderer.resolution, o = !0, (r = lr).width = this.renderer.width, r.height = this.renderer.height, i.renderTexture.bind(null));
+ var s = r.width * e,
+ u = r.height * e,
+ h = new L(s, u, 1),
+ c = new Uint8Array(4 * s * u),
+ l = i.gl;
+ l.readPixels(r.x * e, r.y * e, s, u, l.RGBA, l.UNSIGNED_BYTE, c);
+ var f = h.context.getImageData(0, 0, s, u);
+ return f.data.set(c), h.context.putImageData(f, 0, 0), o && (h.context.scale(1, -1), h.context.drawImage(h.canvas, 0, -u)), a && n.destroy(!0), h.canvas
+ }, fr.prototype.pixels = function(t) {
+ var e, r, n, i = this.renderer,
+ o = !1;
+ t && (t instanceof Wt ? n = t : (n = this.renderer.generateTexture(t), o = !0)), n ? (e = n.baseTexture.resolution, r = n.frame, i.renderTexture.bind(n)) : (e = i.resolution, (r = lr).width = i.width, r.height = i.height, i.renderTexture.bind(null));
+ var a = r.width * e,
+ s = r.height * e,
+ u = new Uint8Array(4 * a * s),
+ h = i.gl;
+ return h.readPixels(r.x * e, r.y * e, a, s, h.RGBA, h.UNSIGNED_BYTE, u), o && n.destroy(!0), u
+ }, fr.prototype.destroy = function() {
+ this.renderer.extract = null, this.renderer = null
+ };
+ var dr = function() {
+ this.global = new q, this.target = null, this.originalEvent = null, this.identifier = null, this.isPrimary = !1, this.button = 0, this.buttons = 0, this.width = 0, this.height = 0, this.tiltX = 0, this.tiltY = 0, this.pointerType = null, this.pressure = 0, this.rotationAngle = 0, this.twist = 0, this.tangentialPressure = 0
+ },
+ pr = {
+ pointerId: {
+ configurable: !0
+ }
+ };
+ pr.pointerId.get = function() {
+ return this.identifier
+ }, dr.prototype.getLocalPosition = function(t, e, r) {
+ return t.worldTransform.applyInverse(r || this.global, e)
+ }, dr.prototype.copyEvent = function(t) {
+ t.isPrimary && (this.isPrimary = !0), this.button = t.button, this.buttons = Number.isInteger(t.buttons) ? t.buttons : t.which, this.width = t.width, this.height = t.height, this.tiltX = t.tiltX, this.tiltY = t.tiltY, this.pointerType = t.pointerType, this.pressure = t.pressure, this.rotationAngle = t.rotationAngle, this.twist = t.twist || 0, this.tangentialPressure = t.tangentialPressure || 0
+ }, dr.prototype.reset = function() {
+ this.isPrimary = !1
+ }, Object.defineProperties(dr.prototype, pr);
+ var mr = function() {
+ this.stopped = !1, this.target = null, this.currentTarget = null, this.type = null, this.data = null
+ };
+ mr.prototype.stopPropagation = function() {
+ this.stopped = !0
+ }, mr.prototype.reset = function() {
+ this.stopped = !1, this.currentTarget = null, this.target = null
+ };
+ var vr = function InteractionTrackingData(t) {
+ this._pointerId = t, this._flags = InteractionTrackingData.FLAGS.NONE
+ },
+ gr = {
+ pointerId: {
+ configurable: !0
+ },
+ flags: {
+ configurable: !0
+ },
+ none: {
+ configurable: !0
+ },
+ over: {
+ configurable: !0
+ },
+ rightDown: {
+ configurable: !0
+ },
+ leftDown: {
+ configurable: !0
+ }
+ };
+ vr.prototype._doSet = function(t, e) {
+ this._flags = e ? this._flags | t : this._flags & ~t
+ }, gr.pointerId.get = function() {
+ return this._pointerId
+ }, gr.flags.get = function() {
+ return this._flags
+ }, gr.flags.set = function(t) {
+ this._flags = t
+ }, gr.none.get = function() {
+ return this._flags === this.constructor.FLAGS.NONE
+ }, gr.over.get = function() {
+ return 0 != (this._flags & this.constructor.FLAGS.OVER)
+ }, gr.over.set = function(t) {
+ this._doSet(this.constructor.FLAGS.OVER, t)
+ }, gr.rightDown.get = function() {
+ return 0 != (this._flags & this.constructor.FLAGS.RIGHT_DOWN)
+ }, gr.rightDown.set = function(t) {
+ this._doSet(this.constructor.FLAGS.RIGHT_DOWN, t)
+ }, gr.leftDown.get = function() {
+ return 0 != (this._flags & this.constructor.FLAGS.LEFT_DOWN)
+ }, gr.leftDown.set = function(t) {
+ this._doSet(this.constructor.FLAGS.LEFT_DOWN, t)
+ }, Object.defineProperties(vr.prototype, gr), vr.FLAGS = Object.freeze({
+ NONE: 0,
+ OVER: 1,
+ LEFT_DOWN: 2,
+ RIGHT_DOWN: 4
+ });
+ var yr = {
+ interactive: !1,
+ interactiveChildren: !0,
+ hitArea: null,
+ get buttonMode() {
+ return "pointer" === this.cursor
+ },
+ set buttonMode(t) {
+ t ? this.cursor = "pointer" : "pointer" === this.cursor && (this.cursor = null)
+ },
+ cursor: null,
+ get trackedPointers() {
+ return void 0 === this._trackedPointers && (this._trackedPointers = {}), this._trackedPointers
+ },
+ _trackedPointers: void 0
+ };
+ dt.mixin(yr);
+ var _r = {
+ target: null,
+ data: {
+ global: null
+ }
+ },
+ br = function(r) {
+ function InteractionManager(t, e) {
+ r.call(this), e = e || {}, this.renderer = t, this.autoPreventDefault = void 0 === e.autoPreventDefault || e.autoPreventDefault, this.interactionFrequency = e.interactionFrequency || 10, this.mouse = new dr, this.mouse.identifier = 1, this.mouse.global.set(-999999), this.activeInteractionData = {}, this.activeInteractionData[1] = this.mouse, this.interactionDataPool = [], this.eventData = new mr, this.interactionDOMElement = null, this.moveWhenInside = !1, this.eventsAdded = !1, this.mouseOverRenderer = !1, this.supportsTouchEvents = "ontouchstart" in window, this.supportsPointerEvents = !!window.PointerEvent, this.onPointerUp = this.onPointerUp.bind(this), this.processPointerUp = this.processPointerUp.bind(this), this.onPointerCancel = this.onPointerCancel.bind(this), this.processPointerCancel = this.processPointerCancel.bind(this), this.onPointerDown = this.onPointerDown.bind(this), this.processPointerDown = this.processPointerDown.bind(this), this.onPointerMove = this.onPointerMove.bind(this), this.processPointerMove = this.processPointerMove.bind(this), this.onPointerOut = this.onPointerOut.bind(this), this.processPointerOverOut = this.processPointerOverOut.bind(this), this.onPointerOver = this.onPointerOver.bind(this), this.cursorStyles = {
+ default: "inherit",
+ pointer: "pointer"
+ }, this.currentCursorMode = null, this.cursor = null, this._tempPoint = new q, this.resolution = 1, this.setTargetElement(this.renderer.view, this.renderer.resolution)
+ }
+ return r && (InteractionManager.__proto__ = r), ((InteractionManager.prototype = Object.create(r && r.prototype)).constructor = InteractionManager).prototype.hitTest = function(t, e) {
+ return _r.target = null, _r.data.global = t, e || (e = this.renderer._lastObjectRendered), this.processInteractive(_r, e, null, !0), _r.target
+ }, InteractionManager.prototype.setTargetElement = function(t, e) {
+ void 0 === e && (e = 1), this.removeEvents(), this.interactionDOMElement = t, this.resolution = e, this.addEvents()
+ }, InteractionManager.prototype.addEvents = function() {
+ this.interactionDOMElement && (xt.system.add(this.update, this, _t.INTERACTION), window.navigator.msPointerEnabled ? (this.interactionDOMElement.style["-ms-content-zooming"] = "none", this.interactionDOMElement.style["-ms-touch-action"] = "none") : this.supportsPointerEvents && (this.interactionDOMElement.style["touch-action"] = "none"), this.supportsPointerEvents ? (window.document.addEventListener("pointermove", this.onPointerMove, !0), this.interactionDOMElement.addEventListener("pointerdown", this.onPointerDown, !0), this.interactionDOMElement.addEventListener("pointerleave", this.onPointerOut, !0), this.interactionDOMElement.addEventListener("pointerover", this.onPointerOver, !0), window.addEventListener("pointercancel", this.onPointerCancel, !0), window.addEventListener("pointerup", this.onPointerUp, !0)) : (window.document.addEventListener("mousemove", this.onPointerMove, !0), this.interactionDOMElement.addEventListener("mousedown", this.onPointerDown, !0), this.interactionDOMElement.addEventListener("mouseout", this.onPointerOut, !0), this.interactionDOMElement.addEventListener("mouseover", this.onPointerOver, !0), window.addEventListener("mouseup", this.onPointerUp, !0)), this.supportsTouchEvents && (this.interactionDOMElement.addEventListener("touchstart", this.onPointerDown, !0), this.interactionDOMElement.addEventListener("touchcancel", this.onPointerCancel, !0), this.interactionDOMElement.addEventListener("touchend", this.onPointerUp, !0), this.interactionDOMElement.addEventListener("touchmove", this.onPointerMove, !0)), this.eventsAdded = !0)
+ }, InteractionManager.prototype.removeEvents = function() {
+ this.interactionDOMElement && (xt.system.remove(this.update, this), window.navigator.msPointerEnabled ? (this.interactionDOMElement.style["-ms-content-zooming"] = "", this.interactionDOMElement.style["-ms-touch-action"] = "") : this.supportsPointerEvents && (this.interactionDOMElement.style["touch-action"] = ""), this.supportsPointerEvents ? (window.document.removeEventListener("pointermove", this.onPointerMove, !0), this.interactionDOMElement.removeEventListener("pointerdown", this.onPointerDown, !0), this.interactionDOMElement.removeEventListener("pointerleave", this.onPointerOut, !0), this.interactionDOMElement.removeEventListener("pointerover", this.onPointerOver, !0), window.removeEventListener("pointercancel", this.onPointerCancel, !0), window.removeEventListener("pointerup", this.onPointerUp, !0)) : (window.document.removeEventListener("mousemove", this.onPointerMove, !0), this.interactionDOMElement.removeEventListener("mousedown", this.onPointerDown, !0), this.interactionDOMElement.removeEventListener("mouseout", this.onPointerOut, !0), this.interactionDOMElement.removeEventListener("mouseover", this.onPointerOver, !0), window.removeEventListener("mouseup", this.onPointerUp, !0)), this.supportsTouchEvents && (this.interactionDOMElement.removeEventListener("touchstart", this.onPointerDown, !0), this.interactionDOMElement.removeEventListener("touchcancel", this.onPointerCancel, !0), this.interactionDOMElement.removeEventListener("touchend", this.onPointerUp, !0), this.interactionDOMElement.removeEventListener("touchmove", this.onPointerMove, !0)), this.interactionDOMElement = null, this.eventsAdded = !1)
+ }, InteractionManager.prototype.update = function(t) {
+ if (this._deltaTime += t, !(this._deltaTime < this.interactionFrequency) && (this._deltaTime = 0, this.interactionDOMElement))
+ if (this.didMove) this.didMove = !1;
+ else {
+ for (var e in this.cursor = null, this.activeInteractionData)
+ if (this.activeInteractionData.hasOwnProperty(e)) {
+ var r = this.activeInteractionData[e];
+ if (r.originalEvent && "touch" !== r.pointerType) {
+ var n = this.configureInteractionEventForDOMEvent(this.eventData, r.originalEvent, r);
+ this.processInteractive(n, this.renderer._lastObjectRendered, this.processPointerOverOut, !0)
+ }
+ }
+ this.setCursorMode(this.cursor)
+ }
+ }, InteractionManager.prototype.setCursorMode = function(t) {
+ if (t = t || "default", this.currentCursorMode !== t) {
+ this.currentCursorMode = t;
+ var e = this.cursorStyles[t];
+ if (e) switch (typeof e) {
+ case "string":
+ this.interactionDOMElement.style.cursor = e;
+ break;
+ case "function":
+ e(t);
+ break;
+ case "object":
+ Object.assign(this.interactionDOMElement.style, e)
+ } else "string" != typeof t || Object.prototype.hasOwnProperty.call(this.cursorStyles, t) || (this.interactionDOMElement.style.cursor = t)
+ }
+ }, InteractionManager.prototype.dispatchEvent = function(t, e, r) {
+ r.stopped || (r.currentTarget = t, r.type = e, t.emit(e, r), t[e] && t[e](r))
+ }, InteractionManager.prototype.mapPositionToPoint = function(t, e, r) {
+ var n;
+ n = this.interactionDOMElement.parentElement ? this.interactionDOMElement.getBoundingClientRect() : {
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0
+ };
+ var i = 1 / this.resolution;
+ t.x = (e - n.left) * (this.interactionDOMElement.width / n.width) * i, t.y = (r - n.top) * (this.interactionDOMElement.height / n.height) * i
+ }, InteractionManager.prototype.processInteractive = function(t, e, r, n, i) {
+ if (!e || !e.visible) return !1;
+ var o = t.data.global,
+ a = !1,
+ s = i = e.interactive || i,
+ u = !0;
+ if (e.hitArea ? (n && (e.worldTransform.applyInverse(o, this._tempPoint), e.hitArea.contains(this._tempPoint.x, this._tempPoint.y) ? a = !0 : u = n = !1), s = !1) : e._mask && n && (e._mask.containsPoint && e._mask.containsPoint(o) || (u = n = !1)), u && e.interactiveChildren && e.children)
+ for (var h = e.children, c = h.length - 1; 0 <= c; c--) {
+ var l = h[c],
+ f = this.processInteractive(t, l, r, n, s);
+ if (f) {
+ if (!l.parent) continue;
+ s = !1, f && (t.target && (n = !1), a = !0)
+ }
+ }
+ return i && (n && !t.target && !e.hitArea && e.containsPoint && e.containsPoint(o) && (a = !0), e.interactive && (a && !t.target && (t.target = e), r && r(t, e, !!a))), a
+ }, InteractionManager.prototype.onPointerDown = function(t) {
+ if (!this.supportsTouchEvents || "touch" !== t.pointerType) {
+ var e = this.normalizeToPointerData(t);
+ if (this.autoPreventDefault && e[0].isNormalized)(t.cancelable || !("cancelable" in t)) && t.preventDefault();
+ for (var r = e.length, n = 0; n < r; n++) {
+ var i = e[n],
+ o = this.getInteractionDataForPointerId(i),
+ a = this.configureInteractionEventForDOMEvent(this.eventData, i, o);
+ if (a.data.originalEvent = t, this.processInteractive(a, this.renderer._lastObjectRendered, this.processPointerDown, !0), this.emit("pointerdown", a), "touch" === i.pointerType) this.emit("touchstart", a);
+ else if ("mouse" === i.pointerType || "pen" === i.pointerType) {
+ var s = 2 === i.button;
+ this.emit(s ? "rightdown" : "mousedown", this.eventData)
+ }
+ }
+ }
+ }, InteractionManager.prototype.processPointerDown = function(t, e, r) {
+ var n = t.data,
+ i = t.data.identifier;
+ if (r)
+ if (e.trackedPointers[i] || (e.trackedPointers[i] = new vr(i)), this.dispatchEvent(e, "pointerdown", t), "touch" === n.pointerType) this.dispatchEvent(e, "touchstart", t);
+ else if ("mouse" === n.pointerType || "pen" === n.pointerType) {
+ var o = 2 === n.button;
+ o ? e.trackedPointers[i].rightDown = !0 : e.trackedPointers[i].leftDown = !0, this.dispatchEvent(e, o ? "rightdown" : "mousedown", t)
+ }
+ }, InteractionManager.prototype.onPointerComplete = function(t, e, r) {
+ for (var n = this.normalizeToPointerData(t), i = n.length, o = t.target !== this.interactionDOMElement ? "outside" : "", a = 0; a < i; a++) {
+ var s = n[a],
+ u = this.getInteractionDataForPointerId(s),
+ h = this.configureInteractionEventForDOMEvent(this.eventData, s, u);
+ if (h.data.originalEvent = t, this.processInteractive(h, this.renderer._lastObjectRendered, r, e || !o), this.emit(e ? "pointercancel" : "pointerup" + o, h), "mouse" === s.pointerType || "pen" === s.pointerType) {
+ var c = 2 === s.button;
+ this.emit(c ? "rightup" + o : "mouseup" + o, h)
+ } else "touch" === s.pointerType && (this.emit(e ? "touchcancel" : "touchend" + o, h), this.releaseInteractionDataForPointerId(s.pointerId, u))
+ }
+ }, InteractionManager.prototype.onPointerCancel = function(t) {
+ this.supportsTouchEvents && "touch" === t.pointerType || this.onPointerComplete(t, !0, this.processPointerCancel)
+ }, InteractionManager.prototype.processPointerCancel = function(t, e) {
+ var r = t.data,
+ n = t.data.identifier;
+ void 0 !== e.trackedPointers[n] && (delete e.trackedPointers[n], this.dispatchEvent(e, "pointercancel", t), "touch" === r.pointerType && this.dispatchEvent(e, "touchcancel", t))
+ }, InteractionManager.prototype.onPointerUp = function(t) {
+ this.supportsTouchEvents && "touch" === t.pointerType || this.onPointerComplete(t, !1, this.processPointerUp)
+ }, InteractionManager.prototype.processPointerUp = function(t, e, r) {
+ var n = t.data,
+ i = t.data.identifier,
+ o = e.trackedPointers[i],
+ a = "touch" === n.pointerType,
+ s = "mouse" === n.pointerType || "pen" === n.pointerType,
+ u = !1;
+ if (s) {
+ var h = 2 === n.button,
+ c = vr.FLAGS,
+ l = h ? c.RIGHT_DOWN : c.LEFT_DOWN,
+ f = void 0 !== o && o.flags & l;
+ r ? (this.dispatchEvent(e, h ? "rightup" : "mouseup", t), f && (this.dispatchEvent(e, h ? "rightclick" : "click", t), u = !0)) : f && this.dispatchEvent(e, h ? "rightupoutside" : "mouseupoutside", t), o && (h ? o.rightDown = !1 : o.leftDown = !1)
+ }
+ r ? (this.dispatchEvent(e, "pointerup", t), a && this.dispatchEvent(e, "touchend", t), o && (s && !u || this.dispatchEvent(e, "pointertap", t), a && (this.dispatchEvent(e, "tap", t), o.over = !1))) : o && (this.dispatchEvent(e, "pointerupoutside", t), a && this.dispatchEvent(e, "touchendoutside", t)), o && o.none && delete e.trackedPointers[i]
+ }, InteractionManager.prototype.onPointerMove = function(t) {
+ if (!this.supportsTouchEvents || "touch" !== t.pointerType) {
+ var e = this.normalizeToPointerData(t);
+ "mouse" !== e[0].pointerType && "pen" !== e[0].pointerType || (this.didMove = !0, this.cursor = null);
+ for (var r = e.length, n = 0; n < r; n++) {
+ var i = e[n],
+ o = this.getInteractionDataForPointerId(i),
+ a = this.configureInteractionEventForDOMEvent(this.eventData, i, o);
+ a.data.originalEvent = t;
+ var s = "touch" !== i.pointerType || this.moveWhenInside;
+ this.processInteractive(a, this.renderer._lastObjectRendered, this.processPointerMove, s), this.emit("pointermove", a), "touch" === i.pointerType && this.emit("touchmove", a), "mouse" !== i.pointerType && "pen" !== i.pointerType || this.emit("mousemove", a)
+ }
+ "mouse" === e[0].pointerType && this.setCursorMode(this.cursor)
+ }
+ }, InteractionManager.prototype.processPointerMove = function(t, e, r) {
+ var n = t.data,
+ i = "touch" === n.pointerType,
+ o = "mouse" === n.pointerType || "pen" === n.pointerType;
+ o && this.processPointerOverOut(t, e, r), this.moveWhenInside && !r || (this.dispatchEvent(e, "pointermove", t), i && this.dispatchEvent(e, "touchmove", t), o && this.dispatchEvent(e, "mousemove", t))
+ }, InteractionManager.prototype.onPointerOut = function(t) {
+ if (!this.supportsTouchEvents || "touch" !== t.pointerType) {
+ var e = this.normalizeToPointerData(t)[0];
+ "mouse" === e.pointerType && (this.mouseOverRenderer = !1, this.setCursorMode(null));
+ var r = this.getInteractionDataForPointerId(e),
+ n = this.configureInteractionEventForDOMEvent(this.eventData, e, r);
+ n.data.originalEvent = e, this.processInteractive(n, this.renderer._lastObjectRendered, this.processPointerOverOut, !1), this.emit("pointerout", n), "mouse" === e.pointerType || "pen" === e.pointerType ? this.emit("mouseout", n) : this.releaseInteractionDataForPointerId(r.identifier)
+ }
+ }, InteractionManager.prototype.processPointerOverOut = function(t, e, r) {
+ var n = t.data,
+ i = t.data.identifier,
+ o = "mouse" === n.pointerType || "pen" === n.pointerType,
+ a = e.trackedPointers[i];
+ r && !a && (a = e.trackedPointers[i] = new vr(i)), void 0 !== a && (r && this.mouseOverRenderer ? (a.over || (a.over = !0, this.dispatchEvent(e, "pointerover", t), o && this.dispatchEvent(e, "mouseover", t)), o && null === this.cursor && (this.cursor = e.cursor)) : a.over && (a.over = !1, this.dispatchEvent(e, "pointerout", this.eventData), o && this.dispatchEvent(e, "mouseout", t), a.none && delete e.trackedPointers[i]))
+ }, InteractionManager.prototype.onPointerOver = function(t) {
+ var e = this.normalizeToPointerData(t)[0],
+ r = this.getInteractionDataForPointerId(e),
+ n = this.configureInteractionEventForDOMEvent(this.eventData, e, r);
+ "mouse" === (n.data.originalEvent = e).pointerType && (this.mouseOverRenderer = !0), this.emit("pointerover", n), "mouse" !== e.pointerType && "pen" !== e.pointerType || this.emit("mouseover", n)
+ }, InteractionManager.prototype.getInteractionDataForPointerId = function(t) {
+ var e, r = t.pointerId;
+ return 1 === r || "mouse" === t.pointerType ? e = this.mouse : this.activeInteractionData[r] ? e = this.activeInteractionData[r] : ((e = this.interactionDataPool.pop() || new dr).identifier = r, this.activeInteractionData[r] = e), e.copyEvent(t), e
+ }, InteractionManager.prototype.releaseInteractionDataForPointerId = function(t) {
+ var e = this.activeInteractionData[t];
+ e && (delete this.activeInteractionData[t], e.reset(), this.interactionDataPool.push(e))
+ }, InteractionManager.prototype.configureInteractionEventForDOMEvent = function(t, e, r) {
+ return t.data = r, this.mapPositionToPoint(r.global, e.clientX, e.clientY), "touch" === e.pointerType && (e.globalX = r.global.x, e.globalY = r.global.y), r.originalEvent = e, t.reset(), t
+ }, InteractionManager.prototype.normalizeToPointerData = function(t) {
+ var e = [];
+ if (this.supportsTouchEvents && t instanceof TouchEvent)
+ for (var r = 0, n = t.changedTouches.length; r < n; r++) {
+ var i = t.changedTouches[r];
+ void 0 === i.button && (i.button = t.touches.length ? 1 : 0), void 0 === i.buttons && (i.buttons = t.touches.length ? 1 : 0), void 0 === i.isPrimary && (i.isPrimary = 1 === t.touches.length && "touchstart" === t.type), void 0 === i.width && (i.width = i.radiusX || 1), void 0 === i.height && (i.height = i.radiusY || 1), void 0 === i.tiltX && (i.tiltX = 0), void 0 === i.tiltY && (i.tiltY = 0), void 0 === i.pointerType && (i.pointerType = "touch"), void 0 === i.pointerId && (i.pointerId = i.identifier || 0), void 0 === i.pressure && (i.pressure = i.force || .5), void 0 === i.twist && (i.twist = 0), void 0 === i.tangentialPressure && (i.tangentialPressure = 0), void 0 === i.layerX && (i.layerX = i.offsetX = i.clientX), void 0 === i.layerY && (i.layerY = i.offsetY = i.clientY), i.isNormalized = !0, e.push(i)
+ } else !(t instanceof MouseEvent) || this.supportsPointerEvents && t instanceof window.PointerEvent || (void 0 === t.isPrimary && (t.isPrimary = !0), void 0 === t.width && (t.width = 1), void 0 === t.height && (t.height = 1), void 0 === t.tiltX && (t.tiltX = 0), void 0 === t.tiltY && (t.tiltY = 0), void 0 === t.pointerType && (t.pointerType = "mouse"), void 0 === t.pointerId && (t.pointerId = 1), void 0 === t.pressure && (t.pressure = .5), void 0 === t.twist && (t.twist = 0), void 0 === t.tangentialPressure && (t.tangentialPressure = 0), t.isNormalized = !0), e.push(t);
+ return e
+ }, InteractionManager.prototype.destroy = function() {
+ this.removeEvents(), this.removeAllListeners(), this.renderer = null, this.mouse = null, this.eventData = null, this.interactionDOMElement = null, this.onPointerDown = null, this.processPointerDown = null, this.onPointerUp = null, this.processPointerUp = null, this.onPointerCancel = null, this.processPointerCancel = null, this.onPointerMove = null, this.processPointerMove = null, this.onPointerOut = null, this.processPointerOverOut = null, this.onPointerOver = null, this._tempPoint = null
+ }, InteractionManager
+ }(l.a),
+ xr = {
+ adaptive: !0,
+ maxLength: 10,
+ minSegments: 8,
+ maxSegments: 2048,
+ _segmentsCount: function(t, e) {
+ if (void 0 === e && (e = 20), !this.adaptive) return e;
+ var r = Math.ceil(t / this.maxLength);
+ return r < this.minSegments ? r = this.minSegments : r > this.maxSegments && (r = this.maxSegments), r
+ }
+ },
+ wr = function() {
+ this.reset()
+ };
+ wr.prototype.clone = function() {
+ var t = new wr;
+ return t.color = this.color, t.alpha = this.alpha, t.texture = this.texture, t.matrix = this.matrix, t.visible = this.visible, t
+ }, wr.prototype.reset = function() {
+ this.color = 16777215, this.alpha = 1, this.texture = Ht.WHITE, this.matrix = null, this.visible = !1
+ }, wr.prototype.destroy = function() {
+ this.texture = null, this.matrix = null
+ };
+ var Tr = function(t, e, r, n) {
+ void 0 === e && (e = null), void 0 === r && (r = null), void 0 === n && (n = null), this.shape = t, this.lineStyle = r, this.fillStyle = e, this.matrix = n, this.type = t.type, this.points = [], this.holes = []
+ };
+ Tr.prototype.clone = function() {
+ return new Tr(this.shape, this.fillStyle, this.lineStyle, this.matrix)
+ }, Tr.prototype.destroy = function() {
+ this.shape = null, this.holes.length = 0, this.holes = null, this.points.length = 0, this.points = null, this.lineStyle = null, this.fillStyle = null
+ };
+ var Sr = {
+ build: function(t) {
+ var e, r, n = t.shape,
+ i = t.points,
+ o = n.x,
+ a = n.y;
+ if (i.length = 0, r = t.type === W.CIRC ? (e = n.radius, n.radius) : (e = n.width, n.height), 0 !== e && 0 !== r) {
+ var s = Math.floor(30 * Math.sqrt(n.radius)) || Math.floor(15 * Math.sqrt(n.width + n.height));
+ s /= 2.3;
+ for (var u = 2 * Math.PI / s, h = 0; h < s; h++) i.push(o + Math.sin(u * h) * e, a + Math.cos(u * h) * r);
+ i.push(i[0], i[1])
+ }
+ },
+ triangulate: function(t, e) {
+ var r = t.points,
+ n = e.points,
+ i = e.indices,
+ o = n.length / 2,
+ a = o;
+ n.push(t.shape.x, t.shape.y);
+ for (var s = 0; s < r.length; s += 2) n.push(r[s], r[s + 1]), i.push(o++, a, o)
+ }
+ };
+
+ function buildLine(t, e) {
+ t.lineStyle.native ? function(t, e) {
+ var r = 0,
+ n = t.points || t.shape.points;
+ if (0 === n.length) return;
+ var i = e.points,
+ o = e.indices,
+ a = n.length / 2,
+ s = i.length / 2;
+ for (r = 1; r < a; r++) {
+ var u = n[2 * (r - 1)],
+ h = n[2 * (r - 1) + 1],
+ c = n[2 * r],
+ l = n[2 * r + 1];
+ i.push(u, h), i.push(c, l), o.push(s++, s++)
+ }
+ }(t, e) : function(t, e) {
+ var r = t.shape,
+ n = t.points || r.points.slice();
+ if (0 === n.length) return;
+ var i = t.lineStyle,
+ o = new q(n[0], n[1]),
+ a = new q(n[n.length - 2], n[n.length - 1]),
+ s = r.type !== W.POLY || r.closeStroke,
+ u = o.x === a.x && o.y === a.y;
+ if (s) {
+ n = n.slice(), u && (n.pop(), n.pop(), a.set(n[n.length - 2], n[n.length - 1]));
+ var h = a.x + .5 * (o.x - a.x),
+ c = a.y + .5 * (o.y - a.y);
+ n.unshift(h, c), n.push(h, c)
+ }
+ var l = e.points,
+ f = n.length / 2,
+ d = n.length,
+ p = l.length / 2,
+ m = i.width / 2,
+ v = n[0],
+ g = n[1],
+ y = n[2],
+ _ = n[3],
+ b = 0,
+ x = 0,
+ w = -(g - _),
+ T = v - y,
+ S = 0,
+ M = 0,
+ E = 0,
+ A = 0,
+ P = Math.sqrt(w * w + T * T);
+ w /= P, T /= P, w *= m, T *= m;
+ var I = i.alignment,
+ O = 2 * (1 - I),
+ C = 2 * I;
+ l.push(v - w * O, g - T * O), l.push(v + w * C, g + T * C);
+ for (var R = 1; R < f - 1; ++R) {
+ v = n[2 * (R - 1)], g = n[2 * (R - 1) + 1], y = n[2 * R], _ = n[2 * R + 1], b = n[2 * (R + 1)], x = n[2 * (R + 1) + 1], w = -(g - _), T = v - y, P = Math.sqrt(w * w + T * T), w /= P, T /= P, w *= m, T *= m, S = -(_ - x), M = y - b, P = Math.sqrt(S * S + M * M), S /= P, M /= P;
+ var D = -T + g - (-T + _),
+ F = -w + y - (-w + v),
+ k = (-w + v) * (-T + _) - (-w + y) * (-T + g),
+ L = -(M *= m) + x - (-M + _),
+ N = -(S *= m) + y - (-S + b),
+ B = (-S + b) * (-M + _) - (-S + y) * (-M + x),
+ U = D * N - L * F;
+ if (Math.abs(U) < .1) U += 10.1, l.push(y - w * O, _ - T * O), l.push(y + w * C, _ + T * C);
+ else {
+ var G = (F * B - N * k) / U,
+ j = (L * k - D * B) / U,
+ z = (G - y) * (G - y) + (j - _) * (j - _);
+ 196 * m * m < z ? (E = w - S, A = T - M, P = Math.sqrt(E * E + A * A), E /= P, A /= P, E *= m, A *= m, l.push(y - E * O, _ - A * O), l.push(y + E * C, _ + A * C), l.push(y - E * C * O, _ - A * O), d++) : (l.push(y + (G - y) * O, _ + (j - _) * O), l.push(y - (G - y) * C, _ - (j - _) * C))
+ }
+ }
+ v = n[2 * (f - 2)], g = n[2 * (f - 2) + 1], y = n[2 * (f - 1)], _ = n[2 * (f - 1) + 1], w = -(g - _), T = v - y, P = Math.sqrt(w * w + T * T), w /= P, T /= P, w *= m, T *= m, l.push(y - w * O, _ - T * O), l.push(y + w * C, _ + T * C);
+ for (var X = e.indices, V = 0; V < d - 2; ++V) X.push(p, p + 1, p + 2), p++
+ }(t, e)
+ }
+ var Mr = {
+ build: function(t) {
+ t.points = t.shape.points.slice()
+ },
+ triangulate: function(t, e) {
+ var r = t.points,
+ n = t.holes,
+ i = e.points,
+ o = e.indices;
+ if (6 <= r.length) {
+ for (var a = [], s = 0; s < n.length; s++) {
+ var u = n[s];
+ a.push(r.length / 2), r = r.concat(u.points)
+ }
+ var h = d()(r, a, 2);
+ if (!h) return;
+ for (var c = i.length / 2, l = 0; l < h.length; l += 3) o.push(h[l] + c), o.push(h[l + 1] + c), o.push(h[l + 2] + c);
+ for (var f = 0; f < r.length; f++) i.push(r[f])
+ }
+ }
+ },
+ Er = {
+ build: function(t) {
+ var e = t.shape,
+ r = t.points,
+ n = e.x,
+ i = e.y,
+ o = e.width,
+ a = e.height,
+ s = e.radius;
+ r.length = 0, r.push(n, i + s), quadraticBezierCurve(n, i + a - s, n, i + a, n + s, i + a, r), quadraticBezierCurve(n + o - s, i + a, n + o, i + a, n + o, i + a - s, r), quadraticBezierCurve(n + o, i + s, n + o, i, n + o - s, i, r), quadraticBezierCurve(n + s, i, n, i, n, i + s + 1e-10, r)
+ },
+ triangulate: function(t, e) {
+ for (var r = t.points, n = e.points, i = e.indices, o = n.length / 2, a = d()(r, null, 2), s = 0, u = a.length; s < u; s += 3) i.push(a[s] + o), i.push(a[s + 1] + o), i.push(a[s + 2] + o);
+ for (var h = 0, c = r.length; h < c; h++) n.push(r[h], r[++h])
+ }
+ };
+
+ function getPt(t, e, r) {
+ return t + (e - t) * r
+ }
+
+ function quadraticBezierCurve(t, e, r, n, i, o, a) {
+ void 0 === a && (a = []);
+ for (var s = a, u = 0, h = 0, c = 0, l = 0, f = 0, d = 0, p = 0, m = 0; p <= 20; ++p) u = getPt(t, r, m = p / 20), h = getPt(e, n, m), c = getPt(r, i, m), l = getPt(n, o, m), f = getPt(u, c, m), d = getPt(h, l, m), s.push(f, d);
+ return s
+ }
+ var Ar = [],
+ Pr = [],
+ Ir = 0,
+ Or = {};
+ Or[W.POLY] = Mr, Or[W.CIRC] = Sr, Or[W.ELIP] = Sr, Or[W.RECT] = {
+ build: function(t) {
+ var e = t.shape,
+ r = e.x,
+ n = e.y,
+ i = e.width,
+ o = e.height,
+ a = t.points;
+ a.length = 0, a.push(r, n, r + i, n, r + i, n + o, r, n + o)
+ },
+ triangulate: function(t, e) {
+ var r = t.points,
+ n = e.points,
+ i = n.length / 2;
+ n.push(r[0], r[1], r[2], r[3], r[6], r[7], r[4], r[5]), e.indices.push(i, i + 1, i + 2, i + 1, i + 2, i + 3)
+ }
+ }, Or[W.RREC] = Er;
+ var Cr = function() {
+ this.style = null, this.size = 0, this.start = 0, this.attribStart = 0, this.attribSize = 0
+ },
+ Rr = function(r) {
+ function GraphicsGeometry() {
+ r.call(this), this.points = [], this.colors = [], this.uvs = [], this.indices = [], this.textureIds = [], this.graphicsData = [], this.dirty = 0, this.batchDirty = -1, this.cacheDirty = -1, this.clearDirty = 0, this.drawCalls = [], this.batches = [], this.shapeIndex = 0, this._bounds = new ft, this.boundsDirty = -1, this.boundsPadding = 0, this.batchable = !1, this.indicesUint16 = null, this.uvsFloat32 = null
+ }
+ r && (GraphicsGeometry.__proto__ = r), (GraphicsGeometry.prototype = Object.create(r && r.prototype)).constructor = GraphicsGeometry;
+ var t = {
+ bounds: {
+ configurable: !0
+ }
+ };
+ return t.bounds.get = function() {
+ return this.boundsDirty !== this.dirty && (this.boundsDirty = this.dirty, this.calculateBounds()), this._bounds
+ }, GraphicsGeometry.prototype.clear = function() {
+ if (0 < this.graphicsData.length) {
+ this.boundsDirty = -1, this.dirty++, this.clearDirty++, this.batchDirty++, this.graphicsData.length = 0, this.shapeIndex = 0, this.points.length = 0, this.colors.length = 0, this.uvs.length = 0, this.indices.length = 0;
+ for (var t = this.textureIds.length = 0; t < this.drawCalls.length; t++) this.drawCalls[t].textures.length = 0, Pr.push(this.drawCalls[t]);
+ for (var e = this.drawCalls.length = 0; e < this.batches.length; e++) {
+ var r = this.batches[e];
+ r.start = 0, r.attribStart = 0, r.style = null, Ar.push(r)
+ }
+ this.batches.length = 0
+ }
+ return this
+ }, GraphicsGeometry.prototype.drawShape = function(t, e, r, n) {
+ var i = new Tr(t, e, r, n);
+ return this.graphicsData.push(i), this.dirty++, this
+ }, GraphicsGeometry.prototype.drawHole = function(t, e) {
+ if (!this.graphicsData.length) return null;
+ var r = new Tr(t, null, null, e),
+ n = this.graphicsData[this.graphicsData.length - 1];
+ return r.lineStyle = n.lineStyle, n.holes.push(r), this.dirty++, r
+ }, GraphicsGeometry.prototype.destroy = function(t) {
+ r.prototype.destroy.call(this, t);
+ for (var e = 0; e < this.graphicsData.length; ++e) this.graphicsData[e].destroy();
+ this.points.length = 0, this.points = null, this.colors.length = 0, this.colors = null, this.uvs.length = 0, this.uvs = null, this.indices.length = 0, this.indices = null, this.indexBuffer.destroy(), this.indexBuffer = null, this.graphicsData.length = 0, this.graphicsData = null, this.drawCalls.length = 0, this.drawCalls = null, this.batches.length = 0, this.batches = null, this._bounds = null
+ }, GraphicsGeometry.prototype.containsPoint = function(t) {
+ for (var e = this.graphicsData, r = 0; r < e.length; ++r) {
+ var n = e[r];
+ if (n.fillStyle.visible && (n.shape && n.shape.contains(t.x, t.y))) {
+ if (n.holes)
+ for (var i = 0; i < n.holes.length; i++) {
+ if (n.holes[i].shape.contains(t.x, t.y)) return !1
+ }
+ return !0
+ }
+ }
+ return !1
+ }, GraphicsGeometry.prototype.updateBatches = function() {
+ if (this.dirty !== this.cacheDirty && 0 !== this.graphicsData.length) {
+ if (this.dirty !== this.cacheDirty)
+ for (var t = 0; t < this.graphicsData.length; t++) {
+ var e = this.graphicsData[t];
+ if (e.fillStyle && !e.fillStyle.texture.baseTexture.valid) return;
+ if (e.lineStyle && !e.lineStyle.texture.baseTexture.valid) return
+ }
+ this.cacheDirty = this.dirty;
+ var r = this.uvs,
+ n = this.batches.pop() || Ar.pop() || new Cr;
+ n.style = n.style || this.graphicsData[0].fillStyle || this.graphicsData[0].lineStyle;
+ var i = n.style.texture.baseTexture,
+ o = n.style.color + n.style.alpha;
+ this.batches.push(n);
+ for (var a = this.shapeIndex; a < this.graphicsData.length; a++) {
+ this.shapeIndex++;
+ var s = this.graphicsData[a],
+ u = Or[s.type],
+ h = s.fillStyle,
+ c = s.lineStyle;
+ u.build(s), s.matrix && this.transformPoints(s.points, s.matrix);
+ for (var l = 0; l < 2; l++) {
+ var f = 0 === l ? h : c;
+ if (f.visible) {
+ var d = f.texture.baseTexture;
+ if (i !== d || f.color + f.alpha !== o) {
+ d.wrapMode = 10497, i = d, o = f.color + f.alpha;
+ var p = this.indices.length,
+ m = this.points.length / 2;
+ n.size = p - n.start, n.attribSize = m - n.attribStart, 0 < n.size && (n = Ar.pop() || new Cr, this.batches.push(n)), n.style = f, n.start = p, n.attribStart = m
+ }
+ var v = this.points.length / 2;
+ if (0 === l) s.holes.length ? (this.processHoles(s.holes), Mr.triangulate(s, this)) : u.triangulate(s, this);
+ else {
+ buildLine(s, this);
+ for (var g = 0; g < s.holes.length; g++) buildLine(s.holes[g], this)
+ }
+ var y = this.points.length / 2 - v;
+ this.addUvs(this.points, r, f.texture, v, y, f.matrix)
+ }
+ }
+ }
+ var _ = this.indices.length,
+ b = this.points.length / 2;
+ if (n.size = _ - n.start, n.attribSize = b - n.attribStart, this.indicesUint16 = new Uint16Array(this.indices), this.batchable = this.isBatchable(), this.batchable) {
+ this.batchDirty++, this.uvsFloat32 = new Float32Array(this.uvs);
+ for (var x = 0; x < this.batches.length; x++)
+ for (var w = this.batches[x], T = 0; T < w.size; T++) {
+ var S = w.start + T;
+ this.indicesUint16[S] = this.indicesUint16[S] - w.attribStart
+ }
+ } else this.buildDrawCalls()
+ }
+ }, GraphicsGeometry.prototype.isBatchable = function() {
+ for (var t = this.batches, e = 0; e < t.length; e++)
+ if (t[e].style.native) return !1;
+ return this.points.length < 2 * GraphicsGeometry.BATCHABLE_SIZE
+ }, GraphicsGeometry.prototype.buildDrawCalls = function() {
+ Ir++;
+ for (var t = 0; t < this.drawCalls.length; t++) this.drawCalls[t].textures.length = 0, Pr.push(this.drawCalls[t]);
+ this.drawCalls.length = 0;
+ var e = this.uvs,
+ r = this.colors,
+ n = this.textureIds,
+ i = Pr.pop() || new ir;
+ i.textureCount = 0, i.start = 0, i.size = 0, i.type = x.TRIANGLES;
+ var o = 0,
+ a = null,
+ s = 0,
+ u = !1,
+ h = x.TRIANGLES,
+ c = 0;
+ this.drawCalls.push(i);
+ for (var l = 0; l < this.batches.length; l++) {
+ var f = this.batches[l],
+ d = f.style,
+ p = d.texture.baseTexture;
+ u !== d.native && (h = (u = d.native) ? x.LINES : x.TRIANGLES, a = null, o = 8, Ir++), a !== p && (a = p)._enabled !== Ir && (8 === o && (Ir++, (o = 0) < i.size && (i = Pr.pop() || new ir, this.drawCalls.push(i)), i.start = c, i.size = 0, i.textureCount = 0, i.type = h), p.touched = 1, p._enabled = Ir, p._id = o, p.wrapMode = 10497, i.textures[i.textureCount++] = p, o++), i.size += f.size, c += f.size, s = p._id, this.addColors(r, d.color, d.alpha, f.attribSize), this.addTextureIds(n, s, f.attribSize)
+ }
+ for (var m = this.points, v = new ArrayBuffer(3 * m.length * 4), g = new Float32Array(v), y = new Uint32Array(v), _ = 0, b = 0; b < m.length / 2; b++) g[_++] = m[2 * b], g[_++] = m[2 * b + 1], g[_++] = e[2 * b], g[_++] = e[2 * b + 1], y[_++] = r[b], g[_++] = n[b];
+ this._buffer.update(v), this._indexBuffer.update(this.indicesUint16)
+ }, GraphicsGeometry.prototype.processHoles = function(t) {
+ for (var e = 0; e < t.length; e++) {
+ var r = t[e];
+ Or[r.type].build(r), r.matrix && this.transformPoints(r.points, r.matrix)
+ }
+ }, GraphicsGeometry.prototype.calculateBounds = function() {
+ var t = 1 / 0,
+ e = -1 / 0,
+ r = 1 / 0,
+ n = -1 / 0;
+ if (this.graphicsData.length)
+ for (var i = null, o = 0, a = 0, s = 0, u = 0, h = 0; h < this.graphicsData.length; h++) {
+ var c = this.graphicsData[h],
+ l = c.type,
+ f = c.lineStyle ? c.lineStyle.width : 0;
+ if (i = c.shape, l === W.RECT || l === W.RREC) o = i.x - f / 2, a = i.y - f / 2, t = o < t ? o : t, e = e < o + (s = i.width + f) ? o + s : e, r = a < r ? a : r, n = n < a + (u = i.height + f) ? a + u : n;
+ else if (l === W.CIRC) o = i.x, a = i.y, t = o - (s = i.radius + f / 2) < t ? o - s : t, e = e < o + s ? o + s : e, r = a - (u = i.radius + f / 2) < r ? a - u : r, n = n < a + u ? a + u : n;
+ else if (l === W.ELIP) o = i.x, a = i.y, t = o - (s = i.width + f / 2) < t ? o - s : t, e = e < o + s ? o + s : e, r = a - (u = i.height + f / 2) < r ? a - u : r, n = n < a + u ? a + u : n;
+ else
+ for (var d = i.points, p = 0, m = 0, v = 0, g = 0, y = 0, _ = 0, b = 0, x = 0, w = 0; w + 2 < d.length; w += 2) o = d[w], a = d[w + 1], p = d[w + 2], m = d[w + 3], v = Math.abs(p - o), g = Math.abs(m - a), u = f, (s = Math.sqrt(v * v + g * g)) < 1e-9 || (t = (b = (p + o) / 2) - (y = (u / s * g + v) / 2) < t ? b - y : t, e = e < b + y ? b + y : e, r = (x = (m + a) / 2) - (_ = (u / s * v + g) / 2) < r ? x - _ : r, n = n < x + _ ? x + _ : n)
+ } else n = r = e = t = 0;
+ var T = this.boundsPadding;
+ this._bounds.minX = t - T, this._bounds.maxX = e + T, this._bounds.minY = r - T, this._bounds.maxY = n + T
+ }, GraphicsGeometry.prototype.transformPoints = function(t, e) {
+ for (var r = 0; r < t.length / 2; r++) {
+ var n = t[2 * r],
+ i = t[2 * r + 1];
+ t[2 * r] = e.a * n + e.c * i + e.tx, t[2 * r + 1] = e.b * n + e.d * i + e.ty
+ }
+ }, GraphicsGeometry.prototype.addColors = function(t, e, r, n) {
+ for (var i = premultiplyTint((e >> 16) + (65280 & e) + ((255 & e) << 16), r); 0 < n--;) t.push(i)
+ }, GraphicsGeometry.prototype.addTextureIds = function(t, e, r) {
+ for (; 0 < r--;) t.push(e)
+ }, GraphicsGeometry.prototype.addUvs = function(t, e, r, n, i, o) {
+ for (var a = 0, s = e.length, u = r.frame; a < i;) {
+ var h = t[2 * (n + a)],
+ c = t[2 * (n + a) + 1];
+ if (o) {
+ var l = o.a * h + o.c * c + o.tx;
+ c = o.b * h + o.d * c + o.ty, h = l
+ }
+ a++, e.push(h / u.width, c / u.height)
+ }
+ var f = r.baseTexture;
+ (u.width < f.width || u.height < f.height) && this.adjustUvs(e, r, s, i)
+ }, GraphicsGeometry.prototype.adjustUvs = function(t, e, r, n) {
+ for (var i = e.baseTexture, o = r + 2 * n, a = e.frame, s = a.width / i.width, u = a.height / i.height, h = a.x / a.width, c = a.y / a.width, l = Math.floor(t[r] + 1e-6), f = Math.floor(t[r + 1] + 1e-6), d = r + 2; d < o; d += 2) l = Math.min(l, Math.floor(t[d] + 1e-6)), f = Math.min(f, Math.floor(t[d + 1] + 1e-6));
+ h -= l, c -= f;
+ for (var p = r; p < o; p += 2) t[p] = (t[p] + h) * s, t[p + 1] = (t[p + 1] + c) * u
+ }, Object.defineProperties(GraphicsGeometry.prototype, t), GraphicsGeometry
+ }(nr);
+ Rr.BATCHABLE_SIZE = 100;
+ var Dr = function(t) {
+ function LineStyle() {
+ t.apply(this, arguments)
+ }
+ return t && (LineStyle.__proto__ = t), ((LineStyle.prototype = Object.create(t && t.prototype)).constructor = LineStyle).prototype.clone = function() {
+ var t = new LineStyle;
+ return t.color = this.color, t.alpha = this.alpha, t.texture = this.texture, t.matrix = this.matrix, t.visible = this.visible, t.width = this.width, t.alignment = this.alignment, t.native = this.native, t
+ }, LineStyle.prototype.reset = function() {
+ t.prototype.reset.call(this), this.color = 0, this.width = 0, this.alignment = .5, this.native = !1
+ }, LineStyle
+ }(wr),
+ Fr = function() {};
+ Fr.curveLength = function(t, e, r, n, i, o, a, s) {
+ for (var u = 0, h = 0, c = 0, l = 0, f = 0, d = 0, p = 0, m = 0, v = 0, g = 0, y = 0, _ = t, b = e, x = 1; x <= 10; ++x) g = _ - (m = (p = (d = (f = 1 - (h = x / 10)) * f) * f) * t + 3 * d * h * r + 3 * f * (c = h * h) * i + (l = c * h) * a), y = b - (v = p * e + 3 * d * h * n + 3 * f * c * o + l * s), _ = m, b = v, u += Math.sqrt(g * g + y * y);
+ return u
+ }, Fr.curveTo = function(t, e, r, n, i, o, a) {
+ var s = a[a.length - 2],
+ u = a[a.length - 1];
+ a.length -= 2;
+ var h = xr._segmentsCount(Fr.curveLength(s, u, t, e, r, n, i, o)),
+ c = 0,
+ l = 0,
+ f = 0,
+ d = 0,
+ p = 0;
+ a.push(s, u);
+ for (var m = 1, v = 0; m <= h; ++m) f = (l = (c = 1 - (v = m / h)) * c) * c, p = (d = v * v) * v, a.push(f * s + 3 * l * v * t + 3 * c * d * r + p * i, f * u + 3 * l * v * e + 3 * c * d * n + p * o)
+ };
+ var kr = function() {};
+ kr.curveLength = function(t, e, r, n, i, o) {
+ var a = t - 2 * r + i,
+ s = e - 2 * n + o,
+ u = 2 * r - 2 * t,
+ h = 2 * n - 2 * e,
+ c = 4 * (a * a + s * s),
+ l = 4 * (a * u + s * h),
+ f = u * u + h * h,
+ d = 2 * Math.sqrt(c + l + f),
+ p = Math.sqrt(c),
+ m = 2 * c * p,
+ v = 2 * Math.sqrt(f),
+ g = l / p;
+ return (m * d + p * l * (d - v) + (4 * f * c - l * l) * Math.log((2 * p + g + d) / (g + v))) / (4 * m)
+ }, kr.curveTo = function(t, e, r, n, i) {
+ for (var o = i[i.length - 2], a = i[i.length - 1], s = xr._segmentsCount(kr.curveLength(o, a, t, e, r, n)), u = 0, h = 0, c = 1; c <= s; ++c) {
+ var l = c / s;
+ u = o + (t - o) * l, h = a + (e - a) * l, i.push(u + (t + (r - t) * l - u) * l, h + (e + (n - e) * l - h) * l)
+ }
+ };
+ var Lr = function() {};
+ Lr.curveTo = function(t, e, r, n, i, o) {
+ var a = o[o.length - 2],
+ s = o[o.length - 1] - e,
+ u = a - t,
+ h = n - e,
+ c = r - t,
+ l = Math.abs(s * c - u * h);
+ if (l < 1e-8 || 0 === i) return o[o.length - 2] === t && o[o.length - 1] === e || o.push(t, e), null;
+ var f = s * s + u * u,
+ d = h * h + c * c,
+ p = s * h + u * c,
+ m = i * Math.sqrt(f) / l,
+ v = i * Math.sqrt(d) / l,
+ g = m * p / f,
+ y = v * p / d,
+ _ = m * c + v * u,
+ b = m * h + v * s,
+ x = u * (v + g),
+ w = s * (v + g),
+ T = c * (m + y),
+ S = h * (m + y);
+ return {
+ cx: _ + t,
+ cy: b + e,
+ radius: i,
+ startAngle: Math.atan2(w - b, x - _),
+ endAngle: Math.atan2(S - b, T - _),
+ anticlockwise: c * s < u * h
+ }
+ }, Lr.arc = function(t, e, r, n, i, o, a, s, u) {
+ for (var h = a - o, c = xr._segmentsCount(Math.abs(h) * i, 40 * Math.ceil(Math.abs(h) / X)), l = h / (2 * c), f = 2 * l, d = Math.cos(l), p = Math.sin(l), m = c - 1, v = m % 1 / m, g = 0; g <= m; ++g) {
+ var y = l + o + f * (g + v * g),
+ _ = Math.cos(y),
+ b = -Math.sin(y);
+ u.push((d * _ + p * b) * i + r, (d * -b + p * _) * i + n)
+ }
+ };
+ var Nr = function(d) {
+ function Star(t, e, r, n, i, o) {
+ i = i || n / 2;
+ for (var a = -1 * Math.PI / 2 + o, s = 2 * r, u = X / s, h = [], c = 0; c < s; c++) {
+ var l = c % 2 ? i : n,
+ f = c * u + a;
+ h.push(t + l * Math.cos(f), e + l * Math.sin(f))
+ }
+ d.call(this, h)
+ }
+ return d && (Star.__proto__ = d), (Star.prototype = Object.create(d && d.prototype)).constructor = Star
+ }(ct),
+ Br = new Float32Array(3),
+ Ur = null,
+ Gr = function(e) {
+ function Graphics(t) {
+ void 0 === t && (t = null), e.call(this), this.geometry = t || new Rr, this.geometry.refCount++, this.shader = null, this.state = Ce.for2d(), this._fillStyle = new wr, this._lineStyle = new Dr, this._matrix = null, this._holeMode = !1, this.currentPath = null, this.batches = [], this.batchTint = -1, this.vertexData = null, this._transformID = -1, this.batchDirty = -1, this.tint = 16777215, this.blendMode = y.NORMAL
+ }
+ e && (Graphics.__proto__ = e);
+ var t = {
+ blendMode: {
+ configurable: !0
+ },
+ tint: {
+ configurable: !0
+ },
+ fill: {
+ configurable: !0
+ },
+ line: {
+ configurable: !0
+ }
+ };
+ return ((Graphics.prototype = Object.create(e && e.prototype)).constructor = Graphics).prototype.clone = function() {
+ return this.finishPoly(), new Graphics(this.geometry)
+ }, t.blendMode.set = function(t) {
+ this.state.blendMode = t
+ }, t.blendMode.get = function() {
+ return this.state.blendMode
+ }, t.tint.get = function() {
+ return this._tint
+ }, t.tint.set = function(t) {
+ this._tint = t
+ }, t.fill.get = function() {
+ return this._fillStyle
+ }, t.line.get = function() {
+ return this._lineStyle
+ }, Graphics.prototype.lineStyle = function(t, e, r, n, i) {
+ return void 0 === t && (t = 0), void 0 === e && (e = 0), void 0 === r && (r = 1), void 0 === n && (n = .5), void 0 === i && (i = !1), this.lineTextureStyle(t, Ht.WHITE, e, r, null, n, i), this
+ }, Graphics.prototype.lineTextureStyle = function(t, e, r, n, i, o, a) {
+ void 0 === t && (t = 0), void 0 === e && (e = Ht.WHITE), void 0 === r && (r = 16777215), void 0 === n && (n = 1), void 0 === i && (i = null), void 0 === o && (o = .5), void 0 === a && (a = !1), this.currentPath && this.startPoly();
+ var s = 0 < t && 0 < n;
+ return s ? (i && (i = i.clone()).invert(), Object.assign(this._lineStyle, {
+ color: r,
+ width: t,
+ alpha: n,
+ matrix: i,
+ texture: e,
+ alignment: o,
+ native: a,
+ visible: s
+ })) : this._lineStyle.reset(), this
+ }, Graphics.prototype.startPoly = function() {
+ if (this.currentPath) {
+ var t = this.currentPath.points,
+ e = this.currentPath.points.length;
+ 2 < e && (this.drawShape(this.currentPath), this.currentPath = new ct, this.currentPath.closeStroke = !1, this.currentPath.points.push(t[e - 2], t[e - 1]))
+ } else this.currentPath = new ct, this.currentPath.closeStroke = !1
+ }, Graphics.prototype.finishPoly = function() {
+ this.currentPath && (2 < this.currentPath.points.length ? (this.drawShape(this.currentPath), this.currentPath = null) : this.currentPath.points.length = 0)
+ }, Graphics.prototype.moveTo = function(t, e) {
+ return this.startPoly(), this.currentPath.points[0] = t, this.currentPath.points[1] = e, this
+ }, Graphics.prototype.lineTo = function(t, e) {
+ this.currentPath || this.moveTo(0, 0);
+ var r = this.currentPath.points,
+ n = r[r.length - 2],
+ i = r[r.length - 1];
+ return n === t && i === e || r.push(t, e), this
+ }, Graphics.prototype._initCurve = function(t, e) {
+ void 0 === t && (t = 0), void 0 === e && (e = 0), this.currentPath ? 0 === this.currentPath.points.length && (this.currentPath.points = [t, e]) : this.moveTo(t, e)
+ }, Graphics.prototype.quadraticCurveTo = function(t, e, r, n) {
+ this._initCurve();
+ var i = this.currentPath.points;
+ return 0 === i.length && this.moveTo(0, 0), kr.curveTo(t, e, r, n, i), this
+ }, Graphics.prototype.bezierCurveTo = function(t, e, r, n, i, o) {
+ return this._initCurve(), Fr.curveTo(t, e, r, n, i, o, this.currentPath.points), this
+ }, Graphics.prototype.arcTo = function(t, e, r, n, i) {
+ this._initCurve(t, e);
+ var o = this.currentPath.points,
+ a = Lr.curveTo(t, e, r, n, i, o);
+ if (a) {
+ var s = a.cx,
+ u = a.cy,
+ h = a.radius,
+ c = a.startAngle,
+ l = a.endAngle,
+ f = a.anticlockwise;
+ this.arc(s, u, h, c, l, f)
+ }
+ return this
+ }, Graphics.prototype.arc = function(t, e, r, n, i, o) {
+ if (void 0 === o && (o = !1), n === i) return this;
+ if (!o && i <= n ? i += X : o && n <= i && (n += X), 0 === i - n) return this;
+ var a = t + Math.cos(n) * r,
+ s = e + Math.sin(n) * r,
+ u = this.currentPath ? this.currentPath.points : null;
+ if (u) {
+ var h = Math.abs(u[u.length - 2] - a),
+ c = Math.abs(u[u.length - 1] - s);
+ h < .001 && c < .001 || u.push(a, s)
+ } else this.moveTo(a, s), u = this.currentPath.points;
+ return Lr.arc(a, s, t, e, r, n, i, o, u), this
+ }, Graphics.prototype.beginFill = function(t, e) {
+ return void 0 === t && (t = 0), void 0 === e && (e = 1), this.beginTextureFill(Ht.WHITE, t, e)
+ }, Graphics.prototype.beginTextureFill = function(t, e, r, n) {
+ void 0 === t && (t = Ht.WHITE), void 0 === e && (e = 16777215), void 0 === r && (r = 1), void 0 === n && (n = null), this.currentPath && this.startPoly();
+ var i = 0 < r;
+ return i ? (n && (n = n.clone()).invert(), Object.assign(this._fillStyle, {
+ color: e,
+ alpha: r,
+ texture: t,
+ matrix: n,
+ visible: i
+ })) : this._fillStyle.reset(), this
+ }, Graphics.prototype.endFill = function() {
+ return this.finishPoly(), this._fillStyle.reset(), this
+ }, Graphics.prototype.drawRect = function(t, e, r, n) {
+ return this.drawShape(new ot(t, e, r, n))
+ }, Graphics.prototype.drawRoundedRect = function(t, e, r, n, i) {
+ return this.drawShape(new lt(t, e, r, n, i))
+ }, Graphics.prototype.drawCircle = function(t, e, r) {
+ return this.drawShape(new ut(t, e, r))
+ }, Graphics.prototype.drawEllipse = function(t, e, r, n) {
+ return this.drawShape(new ht(t, e, r, n))
+ }, Graphics.prototype.drawPolygon = function(t) {
+ var e = arguments,
+ r = t,
+ n = !0;
+ if (r.points && (n = r.closeStroke, r = r.points), !Array.isArray(r)) {
+ r = new Array(arguments.length);
+ for (var i = 0; i < r.length; ++i) r[i] = e[i]
+ }
+ var o = new ct(r);
+ return o.closeStroke = n, this.drawShape(o), this
+ }, Graphics.prototype.drawShape = function(t) {
+ return this._holeMode ? this.geometry.drawHole(t, this._matrix) : this.geometry.drawShape(t, this._fillStyle.clone(), this._lineStyle.clone(), this._matrix), this
+ }, Graphics.prototype.drawStar = function(t, e, r, n, i, o) {
+ return void 0 === o && (o = 0), this.drawPolygon(new Nr(t, e, r, n, i, o))
+ }, Graphics.prototype.clear = function() {
+ return this.geometry.clear(), this._matrix = null, this._holeMode = !1, this.currentPath = null, this._spriteRect = null, this
+ }, Graphics.prototype.isFastRect = function() {
+ return !1
+ }, Graphics.prototype._render = function(t) {
+ this.finishPoly();
+ var e = this.geometry;
+ if (e.updateBatches(), e.batchable) {
+ if (this.batchDirty !== e.batchDirty) {
+ this.batches = [], this.batchTint = -1, this._transformID = -1, this.batchDirty = e.batchDirty, this.vertexData = new Float32Array(e.points);
+ for (var r = this.blendMode, n = 0; n < e.batches.length; n++) {
+ var i = e.batches[n],
+ o = i.style.color,
+ a = new Float32Array(this.vertexData.buffer, 4 * i.attribStart * 2, 2 * i.attribSize),
+ s = new Float32Array(e.uvsFloat32.buffer, 4 * i.attribStart * 2, 2 * i.attribSize),
+ u = {
+ vertexData: a,
+ blendMode: r,
+ indices: new Uint16Array(e.indicesUint16.buffer, 2 * i.start, i.size),
+ uvs: s,
+ _batchRGB: hex2rgb(o),
+ _tintRGB: o,
+ _texture: i.style.texture,
+ alpha: i.style.alpha,
+ worldAlpha: 1
+ };
+ this.batches[n] = u
+ }
+ }
+ if (t.batch.setObjectRenderer(t.plugins.batch), this.batches.length) {
+ this.calculateVertices(), this.calculateTints();
+ for (var h = 0; h < this.batches.length; h++) {
+ var c = this.batches[h];
+ c.worldAlpha = this.worldAlpha * c.alpha, t.plugins.batch.render(c)
+ }
+ }
+ } else {
+ if (t.batch.flush(), !this.shader) {
+ if (!Ur) {
+ for (var l = new Int32Array(16), f = 0; f < 16; f++) l[f] = f;
+ var d = {
+ tint: new Float32Array([1, 1, 1, 1]),
+ translationMatrix: new Y,
+ default: oe.from({
+ uSamplers: l
+ }, !0)
+ },
+ p = t.plugins.batch.shader.program;
+ Ur = new Ie(p, d)
+ }
+ this.shader = Ur
+ }
+ var m = this.shader.uniforms;
+ m.translationMatrix = this.transform.worldTransform;
+ var v = this.tint,
+ g = this.worldAlpha;
+ m.tint[0] = (v >> 16 & 255) / 255 * g, m.tint[1] = (v >> 8 & 255) / 255 * g, m.tint[2] = (255 & v) / 255 * g, m.tint[3] = g, t.shader.bind(this.shader), t.geometry.bind(e, this.shader), t.state.setState(this.state);
+ for (var y = 0; y < e.drawCalls.length; y++) {
+ for (var _ = e.drawCalls[y], b = _.textureCount, x = 0; x < b; x++) t.texture.bind(_.textures[x], x);
+ t.geometry.draw(_.type, _.size, _.start)
+ }
+ }
+ }, Graphics.prototype._calculateBounds = function() {
+ this.finishPoly();
+ var t = this.geometry.bounds;
+ this._bounds.addFrame(this.transform, t.minX, t.minY, t.maxX, t.maxY)
+ }, Graphics.prototype.containsPoint = function(t) {
+ return this.worldTransform.applyInverse(t, Graphics._TEMP_POINT), this.geometry.containsPoint(Graphics._TEMP_POINT)
+ }, Graphics.prototype.calculateTints = function() {
+ if (this.batchTint !== this.tint) {
+ this.batchTint = this.tint;
+ for (var t = hex2rgb(this.tint, Br), e = 0; e < this.batches.length; e++) {
+ var r = this.batches[e],
+ n = r._batchRGB,
+ i = (t[0] * n[0] * 255 << 16) + (t[1] * n[1] * 255 << 8) + (0 | t[2] * n[2] * 255);
+ r._tintRGB = (i >> 16) + (65280 & i) + ((255 & i) << 16)
+ }
+ }
+ }, Graphics.prototype.calculateVertices = function() {
+ if (this._transformID !== this.transform._worldID) {
+ this._transformID = this.transform._worldID;
+ for (var t = this.transform.worldTransform, e = t.a, r = t.b, n = t.c, i = t.d, o = t.tx, a = t.ty, s = this.geometry.points, u = this.vertexData, h = 0, c = 0; c < s.length; c += 2) {
+ var l = s[c],
+ f = s[c + 1];
+ u[h++] = e * l + n * f + o, u[h++] = i * f + r * l + a
+ }
+ }
+ }, Graphics.prototype.closePath = function() {
+ var t = this.currentPath;
+ return t && (t.closeStroke = !0), this
+ }, Graphics.prototype.setMatrix = function(t) {
+ return this._matrix = t, this
+ }, Graphics.prototype.beginHole = function() {
+ return this.finishPoly(), this._holeMode = !0, this
+ }, Graphics.prototype.endHole = function() {
+ return this.finishPoly(), this._holeMode = !1, this
+ }, Graphics.prototype.destroy = function(t) {
+ e.prototype.destroy.call(this, t), this.geometry.refCount--, 0 === this.geometry.refCount && this.geometry.dispose(), this._matrix = null, this.currentPath = null, this._lineStyle.destroy(), this._lineStyle = null, this._fillStyle.destroy(), this._fillStyle = null, this.geometry = null, this.shader = null, this.vertexData = null, this.batches.length = 0, this.batches = null, e.prototype.destroy.call(this, t)
+ }, Object.defineProperties(Graphics.prototype, t), Graphics
+ }(pt);
+ Gr._TEMP_POINT = new q;
+ var jr = new q,
+ zr = new Uint16Array([0, 1, 2, 0, 2, 3]),
+ Xr = function(r) {
+ function Sprite(t) {
+ r.call(this), this._anchor = new j(this._onAnchorUpdate, this, t ? t.defaultAnchor.x : 0, t ? t.defaultAnchor.y : 0), this._texture = null, this._width = 0, this._height = 0, this._tint = null, this._tintRGB = null, this.tint = 16777215, this.blendMode = y.NORMAL, this.shader = null, this.cachedTint = 16777215, this.uvs = null, this.texture = t || Ht.EMPTY, this.vertexData = new Float32Array(8), this.vertexTrimmedData = null, this._transformID = -1, this._textureID = -1, this._transformTrimmedID = -1, this._textureTrimmedID = -1, this.indices = zr, this.size = 4, this.start = 0, this.pluginName = "batch", this.isSprite = !0, this._roundPixels = M.ROUND_PIXELS
+ }
+ r && (Sprite.__proto__ = r);
+ var t = {
+ roundPixels: {
+ configurable: !0
+ },
+ width: {
+ configurable: !0
+ },
+ height: {
+ configurable: !0
+ },
+ anchor: {
+ configurable: !0
+ },
+ tint: {
+ configurable: !0
+ },
+ texture: {
+ configurable: !0
+ }
+ };
+ return ((Sprite.prototype = Object.create(r && r.prototype)).constructor = Sprite).prototype._onTextureUpdate = function() {
+ this._textureID = -1, this._textureTrimmedID = -1, this.cachedTint = 16777215, this.uvs = this._texture._uvs.uvsFloat32, this._width && (this.scale.x = sign(this.scale.x) * this._width / this._texture.orig.width), this._height && (this.scale.y = sign(this.scale.y) * this._height / this._texture.orig.height)
+ }, Sprite.prototype._onAnchorUpdate = function() {
+ this._transformID = -1, this._transformTrimmedID = -1
+ }, Sprite.prototype.calculateVertices = function() {
+ var t = this._texture;
+ if (this._transformID !== this.transform._worldID || this._textureID !== t._updateID) {
+ this._transformID = this.transform._worldID, this._textureID = t._updateID;
+ var e = this.transform.worldTransform,
+ r = e.a,
+ n = e.b,
+ i = e.c,
+ o = e.d,
+ a = e.tx,
+ s = e.ty,
+ u = this.vertexData,
+ h = t.trim,
+ c = t.orig,
+ l = this._anchor,
+ f = 0,
+ d = 0,
+ p = 0,
+ m = 0;
+ if (p = h ? (f = (d = h.x - l._x * c.width) + h.width, (m = h.y - l._y * c.height) + h.height) : (f = (d = -l._x * c.width) + c.width, (m = -l._y * c.height) + c.height), u[0] = r * d + i * m + a, u[1] = o * m + n * d + s, u[2] = r * f + i * m + a, u[3] = o * m + n * f + s, u[4] = r * f + i * p + a, u[5] = o * p + n * f + s, u[6] = r * d + i * p + a, u[7] = o * p + n * d + s, this._roundPixels)
+ for (var v = 0; v < 8; v++) u[v] = Math.round(u[v])
+ }
+ }, Sprite.prototype.calculateTrimmedVertices = function() {
+ if (this.vertexTrimmedData) {
+ if (this._transformTrimmedID === this.transform._worldID && this._textureTrimmedID === this._texture._updateID) return
+ } else this.vertexTrimmedData = new Float32Array(8);
+ this._transformTrimmedID = this.transform._worldID, this._textureTrimmedID = this._texture._updateID;
+ var t = this._texture,
+ e = this.vertexTrimmedData,
+ r = t.orig,
+ n = this._anchor,
+ i = this.transform.worldTransform,
+ o = i.a,
+ a = i.b,
+ s = i.c,
+ u = i.d,
+ h = i.tx,
+ c = i.ty,
+ l = -n._x * r.width,
+ f = l + r.width,
+ d = -n._y * r.height,
+ p = d + r.height;
+ e[0] = o * l + s * d + h, e[1] = u * d + a * l + c, e[2] = o * f + s * d + h, e[3] = u * d + a * f + c, e[4] = o * f + s * p + h, e[5] = u * p + a * f + c, e[6] = o * l + s * p + h, e[7] = u * p + a * l + c
+ }, Sprite.prototype._render = function(t) {
+ this.calculateVertices(), t.batch.setObjectRenderer(t.plugins[this.pluginName]), t.plugins[this.pluginName].render(this)
+ }, Sprite.prototype._calculateBounds = function() {
+ var t = this._texture.trim,
+ e = this._texture.orig;
+ !t || t.width === e.width && t.height === e.height ? (this.calculateVertices(), this._bounds.addQuad(this.vertexData)) : (this.calculateTrimmedVertices(), this._bounds.addQuad(this.vertexTrimmedData))
+ }, Sprite.prototype.getLocalBounds = function(t) {
+ return 0 === this.children.length ? (this._bounds.minX = this._texture.orig.width * -this._anchor._x, this._bounds.minY = this._texture.orig.height * -this._anchor._y, this._bounds.maxX = this._texture.orig.width * (1 - this._anchor._x), this._bounds.maxY = this._texture.orig.height * (1 - this._anchor._y), t || (this._localBoundsRect || (this._localBoundsRect = new ot), t = this._localBoundsRect), this._bounds.getRectangle(t)) : r.prototype.getLocalBounds.call(this, t)
+ }, Sprite.prototype.containsPoint = function(t) {
+ this.worldTransform.applyInverse(t, jr);
+ var e = this._texture.orig.width,
+ r = this._texture.orig.height,
+ n = -e * this.anchor.x,
+ i = 0;
+ return jr.x >= n && jr.x < n + e && (i = -r * this.anchor.y, jr.y >= i && jr.y < i + r)
+ }, Sprite.prototype.destroy = function(t) {
+ if (r.prototype.destroy.call(this, t), this._texture.off("update", this._onTextureUpdate, this), this._anchor = null, "boolean" == typeof t ? t : t && t.texture) {
+ var e = "boolean" == typeof t ? t : t && t.baseTexture;
+ this._texture.destroy(!!e)
+ }
+ this._texture = null, this.shader = null
+ }, Sprite.from = function(t, e) {
+ return new Sprite(t instanceof Ht ? t : new Ht.from(t, e))
+ }, t.roundPixels.set = function(t) {
+ this._roundPixels !== t && (this._transformID = -1), this._roundPixels = t
+ }, t.roundPixels.get = function() {
+ return this._roundPixels
+ }, t.width.get = function() {
+ return Math.abs(this.scale.x) * this._texture.orig.width
+ }, t.width.set = function(t) {
+ var e = sign(this.scale.x) || 1;
+ this.scale.x = e * t / this._texture.orig.width, this._width = t
+ }, t.height.get = function() {
+ return Math.abs(this.scale.y) * this._texture.orig.height
+ }, t.height.set = function(t) {
+ var e = sign(this.scale.y) || 1;
+ this.scale.y = e * t / this._texture.orig.height, this._height = t
+ }, t.anchor.get = function() {
+ return this._anchor
+ }, t.anchor.set = function(t) {
+ this._anchor.copyFrom(t)
+ }, t.tint.get = function() {
+ return this._tint
+ }, t.tint.set = function(t) {
+ this._tint = t, this._tintRGB = (t >> 16) + (65280 & t) + ((255 & t) << 16)
+ }, t.texture.get = function() {
+ return this._texture
+ }, t.texture.set = function(t) {
+ this._texture !== t && (this._texture = t || Ht.EMPTY, this.cachedTint = 16777215, this._textureID = -1, this._textureTrimmedID = -1, t && (t.baseTexture.valid ? this._onTextureUpdate() : t.once("update", this._onTextureUpdate, this)))
+ }, Object.defineProperties(Sprite.prototype, t), Sprite
+ }(pt),
+ Vr = {
+ LINEAR_VERTICAL: 0,
+ LINEAR_HORIZONTAL: 1
+ },
+ qr = {
+ align: "left",
+ breakWords: !1,
+ dropShadow: !1,
+ dropShadowAlpha: 1,
+ dropShadowAngle: Math.PI / 6,
+ dropShadowBlur: 0,
+ dropShadowColor: "black",
+ dropShadowDistance: 5,
+ fill: "black",
+ fillGradientType: Vr.LINEAR_VERTICAL,
+ fillGradientStops: [],
+ fontFamily: "Arial",
+ fontSize: 26,
+ fontStyle: "normal",
+ fontVariant: "normal",
+ fontWeight: "normal",
+ letterSpacing: 0,
+ lineHeight: 0,
+ lineJoin: "miter",
+ miterLimit: 10,
+ padding: 0,
+ stroke: "black",
+ strokeThickness: 0,
+ textBaseline: "alphabetic",
+ trim: !1,
+ whiteSpace: "pre",
+ wordWrap: !1,
+ wordWrapWidth: 100,
+ leading: 0
+ },
+ Hr = function(t) {
+ this.styleID = 0, this.reset(), deepCopyProperties(this, t, t)
+ },
+ Wr = {
+ align: {
+ configurable: !0
+ },
+ breakWords: {
+ configurable: !0
+ },
+ dropShadow: {
+ configurable: !0
+ },
+ dropShadowAlpha: {
+ configurable: !0
+ },
+ dropShadowAngle: {
+ configurable: !0
+ },
+ dropShadowBlur: {
+ configurable: !0
+ },
+ dropShadowColor: {
+ configurable: !0
+ },
+ dropShadowDistance: {
+ configurable: !0
+ },
+ fill: {
+ configurable: !0
+ },
+ fillGradientType: {
+ configurable: !0
+ },
+ fillGradientStops: {
+ configurable: !0
+ },
+ fontFamily: {
+ configurable: !0
+ },
+ fontSize: {
+ configurable: !0
+ },
+ fontStyle: {
+ configurable: !0
+ },
+ fontVariant: {
+ configurable: !0
+ },
+ fontWeight: {
+ configurable: !0
+ },
+ letterSpacing: {
+ configurable: !0
+ },
+ lineHeight: {
+ configurable: !0
+ },
+ leading: {
+ configurable: !0
+ },
+ lineJoin: {
+ configurable: !0
+ },
+ miterLimit: {
+ configurable: !0
+ },
+ padding: {
+ configurable: !0
+ },
+ stroke: {
+ configurable: !0
+ },
+ strokeThickness: {
+ configurable: !0
+ },
+ textBaseline: {
+ configurable: !0
+ },
+ trim: {
+ configurable: !0
+ },
+ whiteSpace: {
+ configurable: !0
+ },
+ wordWrap: {
+ configurable: !0
+ },
+ wordWrapWidth: {
+ configurable: !0
+ }
+ };
+
+ function getSingleColor(t) {
+ return "number" == typeof t ? hex2string(t) : ("string" == typeof t && 0 === t.indexOf("0x") && (t = t.replace("0x", "#")), t)
+ }
+
+ function getColor(t) {
+ if (Array.isArray(t)) {
+ for (var e = 0; e < t.length; ++e) t[e] = getSingleColor(t[e]);
+ return t
+ }
+ return getSingleColor(t)
+ }
+
+ function deepCopyProperties(t, e, r) {
+ for (var n in r) Array.isArray(e[n]) ? t[n] = e[n].slice() : t[n] = e[n]
+ }
+ Hr.prototype.clone = function() {
+ var t = {};
+ return deepCopyProperties(t, this, qr), new Hr(t)
+ }, Hr.prototype.reset = function() {
+ deepCopyProperties(this, qr, qr)
+ }, Wr.align.get = function() {
+ return this._align
+ }, Wr.align.set = function(t) {
+ this._align !== t && (this._align = t, this.styleID++)
+ }, Wr.breakWords.get = function() {
+ return this._breakWords
+ }, Wr.breakWords.set = function(t) {
+ this._breakWords !== t && (this._breakWords = t, this.styleID++)
+ }, Wr.dropShadow.get = function() {
+ return this._dropShadow
+ }, Wr.dropShadow.set = function(t) {
+ this._dropShadow !== t && (this._dropShadow = t, this.styleID++)
+ }, Wr.dropShadowAlpha.get = function() {
+ return this._dropShadowAlpha
+ }, Wr.dropShadowAlpha.set = function(t) {
+ this._dropShadowAlpha !== t && (this._dropShadowAlpha = t, this.styleID++)
+ }, Wr.dropShadowAngle.get = function() {
+ return this._dropShadowAngle
+ }, Wr.dropShadowAngle.set = function(t) {
+ this._dropShadowAngle !== t && (this._dropShadowAngle = t, this.styleID++)
+ }, Wr.dropShadowBlur.get = function() {
+ return this._dropShadowBlur
+ }, Wr.dropShadowBlur.set = function(t) {
+ this._dropShadowBlur !== t && (this._dropShadowBlur = t, this.styleID++)
+ }, Wr.dropShadowColor.get = function() {
+ return this._dropShadowColor
+ }, Wr.dropShadowColor.set = function(t) {
+ var e = getColor(t);
+ this._dropShadowColor !== e && (this._dropShadowColor = e, this.styleID++)
+ }, Wr.dropShadowDistance.get = function() {
+ return this._dropShadowDistance
+ }, Wr.dropShadowDistance.set = function(t) {
+ this._dropShadowDistance !== t && (this._dropShadowDistance = t, this.styleID++)
+ }, Wr.fill.get = function() {
+ return this._fill
+ }, Wr.fill.set = function(t) {
+ var e = getColor(t);
+ this._fill !== e && (this._fill = e, this.styleID++)
+ }, Wr.fillGradientType.get = function() {
+ return this._fillGradientType
+ }, Wr.fillGradientType.set = function(t) {
+ this._fillGradientType !== t && (this._fillGradientType = t, this.styleID++)
+ }, Wr.fillGradientStops.get = function() {
+ return this._fillGradientStops
+ }, Wr.fillGradientStops.set = function(t) {
+ (function(t, e) {
+ if (!Array.isArray(t) || !Array.isArray(e)) return !1;
+ if (t.length !== e.length) return !1;
+ for (var r = 0; r < t.length; ++r)
+ if (t[r] !== e[r]) return !1;
+ return !0
+ })(this._fillGradientStops, t) || (this._fillGradientStops = t, this.styleID++)
+ }, Wr.fontFamily.get = function() {
+ return this._fontFamily
+ }, Wr.fontFamily.set = function(t) {
+ this.fontFamily !== t && (this._fontFamily = t, this.styleID++)
+ }, Wr.fontSize.get = function() {
+ return this._fontSize
+ }, Wr.fontSize.set = function(t) {
+ this._fontSize !== t && (this._fontSize = t, this.styleID++)
+ }, Wr.fontStyle.get = function() {
+ return this._fontStyle
+ }, Wr.fontStyle.set = function(t) {
+ this._fontStyle !== t && (this._fontStyle = t, this.styleID++)
+ }, Wr.fontVariant.get = function() {
+ return this._fontVariant
+ }, Wr.fontVariant.set = function(t) {
+ this._fontVariant !== t && (this._fontVariant = t, this.styleID++)
+ }, Wr.fontWeight.get = function() {
+ return this._fontWeight
+ }, Wr.fontWeight.set = function(t) {
+ this._fontWeight !== t && (this._fontWeight = t, this.styleID++)
+ }, Wr.letterSpacing.get = function() {
+ return this._letterSpacing
+ }, Wr.letterSpacing.set = function(t) {
+ this._letterSpacing !== t && (this._letterSpacing = t, this.styleID++)
+ }, Wr.lineHeight.get = function() {
+ return this._lineHeight
+ }, Wr.lineHeight.set = function(t) {
+ this._lineHeight !== t && (this._lineHeight = t, this.styleID++)
+ }, Wr.leading.get = function() {
+ return this._leading
+ }, Wr.leading.set = function(t) {
+ this._leading !== t && (this._leading = t, this.styleID++)
+ }, Wr.lineJoin.get = function() {
+ return this._lineJoin
+ }, Wr.lineJoin.set = function(t) {
+ this._lineJoin !== t && (this._lineJoin = t, this.styleID++)
+ }, Wr.miterLimit.get = function() {
+ return this._miterLimit
+ }, Wr.miterLimit.set = function(t) {
+ this._miterLimit !== t && (this._miterLimit = t, this.styleID++)
+ }, Wr.padding.get = function() {
+ return this._padding
+ }, Wr.padding.set = function(t) {
+ this._padding !== t && (this._padding = t, this.styleID++)
+ }, Wr.stroke.get = function() {
+ return this._stroke
+ }, Wr.stroke.set = function(t) {
+ var e = getColor(t);
+ this._stroke !== e && (this._stroke = e, this.styleID++)
+ }, Wr.strokeThickness.get = function() {
+ return this._strokeThickness
+ }, Wr.strokeThickness.set = function(t) {
+ this._strokeThickness !== t && (this._strokeThickness = t, this.styleID++)
+ }, Wr.textBaseline.get = function() {
+ return this._textBaseline
+ }, Wr.textBaseline.set = function(t) {
+ this._textBaseline !== t && (this._textBaseline = t, this.styleID++)
+ }, Wr.trim.get = function() {
+ return this._trim
+ }, Wr.trim.set = function(t) {
+ this._trim !== t && (this._trim = t, this.styleID++)
+ }, Wr.whiteSpace.get = function() {
+ return this._whiteSpace
+ }, Wr.whiteSpace.set = function(t) {
+ this._whiteSpace !== t && (this._whiteSpace = t, this.styleID++)
+ }, Wr.wordWrap.get = function() {
+ return this._wordWrap
+ }, Wr.wordWrap.set = function(t) {
+ this._wordWrap !== t && (this._wordWrap = t, this.styleID++)
+ }, Wr.wordWrapWidth.get = function() {
+ return this._wordWrapWidth
+ }, Wr.wordWrapWidth.set = function(t) {
+ this._wordWrapWidth !== t && (this._wordWrapWidth = t, this.styleID++)
+ }, Hr.prototype.toFontString = function() {
+ var t = "number" == typeof this.fontSize ? this.fontSize + "px" : this.fontSize,
+ e = this.fontFamily;
+ Array.isArray(this.fontFamily) || (e = this.fontFamily.split(","));
+ for (var r = e.length - 1; 0 <= r; r--) {
+ var n = e[r].trim();
+ /([\"\'])[^\'\"]+\1/.test(n) || (n = '"' + n + '"'), e[r] = n
+ }
+ return this.fontStyle + " " + this.fontVariant + " " + this.fontWeight + " " + t + " " + e.join(",")
+ }, Object.defineProperties(Hr.prototype, Wr);
+ var Yr = function(t, e, r, n, i, o, a, s, u) {
+ this.text = t, this.style = e, this.width = r, this.height = n, this.lines = i, this.lineWidths = o, this.lineHeight = a, this.maxLineWidth = s, this.fontProperties = u
+ };
+ Yr.measureText = function(t, e, r, n) {
+ void 0 === n && (n = Yr._canvas), r = null == r ? e.wordWrap : r;
+ var i = e.toFontString(),
+ o = Yr.measureFont(i);
+ 0 === o.fontSize && (o.fontSize = e.fontSize, o.ascent = e.fontSize);
+ var a = n.getContext("2d");
+ a.font = i;
+ for (var s = (r ? Yr.wordWrap(t, e, n) : t).split(/(?:\r\n|\r|\n)/), u = new Array(s.length), h = 0, c = 0; c < s.length; c++) {
+ var l = a.measureText(s[c]).width + (s[c].length - 1) * e.letterSpacing;
+ u[c] = l, h = Math.max(h, l)
+ }
+ var f = h + e.strokeThickness;
+ e.dropShadow && (f += e.dropShadowDistance);
+ var d = e.lineHeight || o.fontSize + e.strokeThickness,
+ p = Math.max(d, o.fontSize + e.strokeThickness) + (s.length - 1) * (d + e.leading);
+ return e.dropShadow && (p += e.dropShadowDistance), new Yr(t, e, f, p, s, u, d + e.leading, h, o)
+ }, Yr.wordWrap = function(t, e, r) {
+ void 0 === r && (r = Yr._canvas);
+ for (var n = r.getContext("2d"), i = 0, o = "", a = "", s = {}, u = e.letterSpacing, h = e.whiteSpace, c = Yr.collapseSpaces(h), l = Yr.collapseNewlines(h), f = !c, d = e.wordWrapWidth + u, p = Yr.tokenize(t), m = 0; m < p.length; m++) {
+ var v = p[m];
+ if (Yr.isNewline(v)) {
+ if (!l) {
+ a += Yr.addLine(o), f = !c, o = "", i = 0;
+ continue
+ }
+ v = " "
+ }
+ if (c) {
+ var g = Yr.isBreakingSpace(v),
+ y = Yr.isBreakingSpace(o[o.length - 1]);
+ if (g && y) continue
+ }
+ var _ = Yr.getFromCache(v, u, s, n);
+ if (d < _)
+ if ("" !== o && (a += Yr.addLine(o), o = "", i = 0), Yr.canBreakWords(v, e.breakWords))
+ for (var b = v.split(""), x = 0; x < b.length; x++) {
+ for (var w = b[x], T = 1; b[x + T];) {
+ var S = b[x + T],
+ M = w[w.length - 1];
+ if (Yr.canBreakChars(M, S, v, x, e.breakWords)) break;
+ w += S, T++
+ }
+ x += w.length - 1;
+ var E = Yr.getFromCache(w, u, s, n);
+ d < E + i && (a += Yr.addLine(o), f = !1, o = "", i = 0), o += w, i += E
+ } else {
+ 0 < o.length && (a += Yr.addLine(o), o = "", i = 0);
+ var A = m === p.length - 1;
+ a += Yr.addLine(v, !A), f = !1, o = "", i = 0
+ } else d < _ + i && (f = !1, a += Yr.addLine(o), o = "", i = 0), (0 < o.length || !Yr.isBreakingSpace(v) || f) && (o += v, i += _)
+ }
+ return a += Yr.addLine(o, !1)
+ }, Yr.addLine = function(t, e) {
+ return void 0 === e && (e = !0), t = Yr.trimRight(t), t = e ? t + "\n" : t
+ }, Yr.getFromCache = function(t, e, r, n) {
+ var i = r[t];
+ if (void 0 === i) {
+ var o = t.length * e;
+ i = n.measureText(t).width + o, r[t] = i
+ }
+ return i
+ }, Yr.collapseSpaces = function(t) {
+ return "normal" === t || "pre-line" === t
+ }, Yr.collapseNewlines = function(t) {
+ return "normal" === t
+ }, Yr.trimRight = function(t) {
+ if ("string" != typeof t) return "";
+ for (var e = t.length - 1; 0 <= e; e--) {
+ var r = t[e];
+ if (!Yr.isBreakingSpace(r)) break;
+ t = t.slice(0, -1)
+ }
+ return t
+ }, Yr.isNewline = function(t) {
+ return "string" == typeof t && 0 <= Yr._newlines.indexOf(t.charCodeAt(0))
+ }, Yr.isBreakingSpace = function(t) {
+ return "string" == typeof t && 0 <= Yr._breakingSpaces.indexOf(t.charCodeAt(0))
+ }, Yr.tokenize = function(t) {
+ var e = [],
+ r = "";
+ if ("string" != typeof t) return e;
+ for (var n = 0; n < t.length; n++) {
+ var i = t[n];
+ Yr.isBreakingSpace(i) || Yr.isNewline(i) ? ("" !== r && (e.push(r), r = ""), e.push(i)) : r += i
+ }
+ return "" !== r && e.push(r), e
+ }, Yr.canBreakWords = function(t, e) {
+ return e
+ }, Yr.canBreakChars = function(t, e, r, n, i) {
+ return !0
+ }, Yr.measureFont = function(t) {
+ if (Yr._fonts[t]) return Yr._fonts[t];
+ var e = {},
+ r = Yr._canvas,
+ n = Yr._context;
+ n.font = t;
+ var i = Yr.METRICS_STRING + Yr.BASELINE_SYMBOL,
+ o = Math.ceil(n.measureText(i).width),
+ a = Math.ceil(n.measureText(Yr.BASELINE_SYMBOL).width),
+ s = 2 * a;
+ a = a * Yr.BASELINE_MULTIPLIER | 0, r.width = o, r.height = s, n.fillStyle = "#f00", n.fillRect(0, 0, o, s), n.font = t, n.textBaseline = "alphabetic", n.fillStyle = "#000", n.fillText(i, 0, a);
+ var u = n.getImageData(0, 0, o, s).data,
+ h = u.length,
+ c = 4 * o,
+ l = 0,
+ f = 0,
+ d = !1;
+ for (l = 0; l < a; ++l) {
+ for (var p = 0; p < c; p += 4)
+ if (255 !== u[f + p]) {
+ d = !0;
+ break
+ }
+ if (d) break;
+ f += c
+ }
+ for (e.ascent = a - l, f = h - c, d = !1, l = s; a < l; --l) {
+ for (var m = 0; m < c; m += 4)
+ if (255 !== u[f + m]) {
+ d = !0;
+ break
+ }
+ if (d) break;
+ f -= c
+ }
+ return e.descent = l - a, e.fontSize = e.ascent + e.descent, Yr._fonts[t] = e
+ }, Yr.clearMetrics = function(t) {
+ void 0 === t && (t = ""), t ? delete Yr._fonts[t] : Yr._fonts = {}
+ };
+ var Kr = document.createElement("canvas");
+ Kr.width = Kr.height = 10, Yr._canvas = Kr, Yr._context = Kr.getContext("2d"), Yr._fonts = {}, Yr.METRICS_STRING = "|Éq", Yr.BASELINE_SYMBOL = "M", Yr.BASELINE_MULTIPLIER = 1.4, Yr._newlines = [10, 13];
+ var Zr = {
+ texture: !0,
+ children: !(Yr._breakingSpaces = [9, 32, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8200, 8201, 8202, 8287, 12288]),
+ baseTexture: !0
+ },
+ Qr = function(i) {
+ function Text(t, e, r) {
+ (r = r || document.createElement("canvas")).width = 3, r.height = 3;
+ var n = Ht.from(r);
+ n.orig = new ot, n.trim = new ot, i.call(this, n), this.canvas = r, this.context = this.canvas.getContext("2d"), this._resolution = M.RESOLUTION, this._autoResolution = !0, this._text = null, this._style = null, this._styleListener = null, this._font = "", this.text = t, this.style = e, this.localStyleID = -1
+ }
+ i && (Text.__proto__ = i);
+ var t = {
+ width: {
+ configurable: !0
+ },
+ height: {
+ configurable: !0
+ },
+ style: {
+ configurable: !0
+ },
+ text: {
+ configurable: !0
+ },
+ resolution: {
+ configurable: !0
+ }
+ };
+ return ((Text.prototype = Object.create(i && i.prototype)).constructor = Text).prototype.updateText = function(t) {
+ var e = this._style;
+ if (this.localStyleID !== e.styleID && (this.dirty = !0, this.localStyleID = e.styleID), this.dirty || !t) {
+ this._font = this._style.toFontString();
+ var r, n, i = this.context,
+ o = Yr.measureText(this._text || " ", this._style, this._style.wordWrap, this.canvas),
+ a = o.width,
+ s = o.height,
+ u = o.lines,
+ h = o.lineHeight,
+ c = o.lineWidths,
+ l = o.maxLineWidth,
+ f = o.fontProperties;
+ if (this.canvas.width = Math.ceil((Math.max(1, a) + 2 * e.padding) * this._resolution), this.canvas.height = Math.ceil((Math.max(1, s) + 2 * e.padding) * this._resolution), i.scale(this._resolution, this._resolution), i.clearRect(0, 0, this.canvas.width, this.canvas.height), i.font = this._font, i.strokeStyle = e.stroke, i.lineWidth = e.strokeThickness, i.textBaseline = e.textBaseline, i.lineJoin = e.lineJoin, i.miterLimit = e.miterLimit, e.dropShadow) {
+ var d = e.dropShadowColor,
+ p = hex2rgb("number" == typeof d ? d : string2hex(d));
+ i.shadowColor = "rgba(" + 255 * p[0] + "," + 255 * p[1] + "," + 255 * p[2] + "," + e.dropShadowAlpha + ")", i.shadowBlur = e.dropShadowBlur, i.shadowOffsetX = Math.cos(e.dropShadowAngle) * e.dropShadowDistance, i.shadowOffsetY = Math.sin(e.dropShadowAngle) * e.dropShadowDistance
+ } else i.shadowColor = 0, i.shadowBlur = 0, i.shadowOffsetX = 0, i.shadowOffsetY = 0;
+ i.fillStyle = this._generateFillStyle(e, u);
+ for (var m = 0; m < u.length; m++) r = e.strokeThickness / 2, n = e.strokeThickness / 2 + m * h + f.ascent, "right" === e.align ? r += l - c[m] : "center" === e.align && (r += (l - c[m]) / 2), e.stroke && e.strokeThickness && this.drawLetterSpacing(u[m], r + e.padding, n + e.padding, !0), e.fill && this.drawLetterSpacing(u[m], r + e.padding, n + e.padding);
+ this.updateTexture()
+ }
+ }, Text.prototype.drawLetterSpacing = function(t, e, r, n) {
+ void 0 === n && (n = !1);
+ var i = this._style.letterSpacing;
+ if (0 !== i)
+ for (var o = String.prototype.split.call(t, ""), a = e, s = 0, u = ""; s < t.length;) u = o[s++], n ? this.context.strokeText(u, a, r) : this.context.fillText(u, a, r), a += this.context.measureText(u).width + i;
+ else n ? this.context.strokeText(t, e, r) : this.context.fillText(t, e, r)
+ }, Text.prototype.updateTexture = function() {
+ var t = this.canvas;
+ if (this._style.trim) {
+ var e = trimCanvas(t);
+ e.data && (t.width = e.width, t.height = e.height, this.context.putImageData(e.data, 0, 0))
+ }
+ var r = this._texture,
+ n = this._style,
+ i = n.trim ? 0 : n.padding,
+ o = r.baseTexture;
+ r.trim.width = r._frame.width = t.width / this._resolution, r.trim.height = r._frame.height = t.height / this._resolution, r.trim.x = -i, r.trim.y = -i, r.orig.width = r._frame.width - 2 * i, r.orig.height = r._frame.height - 2 * i, this._onTextureUpdate(), o.setRealSize(t.width, t.height, this._resolution), this.dirty = !1
+ }, Text.prototype.render = function(t) {
+ this._autoResolution && this._resolution !== t.resolution && (this._resolution = t.resolution, this.dirty = !0), this.updateText(!0), i.prototype.render.call(this, t)
+ }, Text.prototype._renderCanvas = function(t) {
+ this._autoResolution && this._resolution !== t.resolution && (this._resolution = t.resolution, this.dirty = !0), this.updateText(!0), i.prototype._renderCanvas.call(this, t)
+ }, Text.prototype.getLocalBounds = function(t) {
+ return this.updateText(!0), i.prototype.getLocalBounds.call(this, t)
+ }, Text.prototype._calculateBounds = function() {
+ this.updateText(!0), this.calculateVertices(), this._bounds.addQuad(this.vertexData)
+ }, Text.prototype._onStyleChange = function() {
+ this.dirty = !0
+ }, Text.prototype._generateFillStyle = function(t, e) {
+ if (!Array.isArray(t.fill)) return t.fill;
+ var r, n, i, o, a = this.canvas.width / this._resolution,
+ s = this.canvas.height / this._resolution,
+ u = t.fill.slice(),
+ h = t.fillGradientStops.slice();
+ if (!h.length)
+ for (var c = u.length + 1, l = 1; l < c; ++l) h.push(l / c);
+ if (u.unshift(t.fill[0]), h.unshift(0), u.push(t.fill[t.fill.length - 1]), h.push(1), t.fillGradientType === Vr.LINEAR_VERTICAL) {
+ r = this.context.createLinearGradient(a / 2, 0, a / 2, s), n = (u.length + 1) * e.length;
+ for (var f = i = 0; f < e.length; f++) {
+ i += 1;
+ for (var d = 0; d < u.length; d++) o = "number" == typeof h[d] ? h[d] / e.length + f / e.length : i / n, r.addColorStop(o, u[d]), i++
+ }
+ } else {
+ r = this.context.createLinearGradient(0, s / 2, a, s / 2), n = u.length + 1, i = 1;
+ for (var p = 0; p < u.length; p++) o = "number" == typeof h[p] ? h[p] : i / n, r.addColorStop(o, u[p]), i++
+ }
+ return r
+ }, Text.prototype.destroy = function(t) {
+ "boolean" == typeof t && (t = {
+ children: t
+ }), t = Object.assign({}, Zr, t), i.prototype.destroy.call(this, t), this.context = null, this.canvas = null, this._style = null
+ }, t.width.get = function() {
+ return this.updateText(!0), Math.abs(this.scale.x) * this._texture.orig.width
+ }, t.width.set = function(t) {
+ this.updateText(!0);
+ var e = sign(this.scale.x) || 1;
+ this.scale.x = e * t / this._texture.orig.width, this._width = t
+ }, t.height.get = function() {
+ return this.updateText(!0), Math.abs(this.scale.y) * this._texture.orig.height
+ }, t.height.set = function(t) {
+ this.updateText(!0);
+ var e = sign(this.scale.y) || 1;
+ this.scale.y = e * t / this._texture.orig.height, this._height = t
+ }, t.style.get = function() {
+ return this._style
+ }, t.style.set = function(t) {
+ t = t || {}, this._style = t instanceof Hr ? t : new Hr(t), this.localStyleID = -1, this.dirty = !0
+ }, t.text.get = function() {
+ return this._text
+ }, t.text.set = function(t) {
+ t = String(null == t ? "" : t), this._text !== t && (this._text = t, this.dirty = !0)
+ }, t.resolution.get = function() {
+ return this._resolution
+ }, t.resolution.set = function(t) {
+ this._autoResolution = !1, this._resolution !== t && (this._resolution = t, this.dirty = !0)
+ }, Object.defineProperties(Text.prototype, t), Text
+ }(Xr);
+ M.UPLOADS_PER_FRAME = 4;
+ var Jr = function(t) {
+ this.maxItemsPerFrame = t, this.itemsLeft = 0
+ };
+ Jr.prototype.beginFrame = function() {
+ this.itemsLeft = this.maxItemsPerFrame
+ }, Jr.prototype.allowedToUpload = function() {
+ return 0 < this.itemsLeft--
+ };
+ var $r = function(t) {
+ var e = this;
+ this.limiter = new Jr(M.UPLOADS_PER_FRAME), this.renderer = t, this.uploadHookHelper = null, this.queue = [], this.addHooks = [], this.uploadHooks = [], this.completes = [], this.ticking = !1, this.delayedTick = function() {
+ e.queue && e.prepareItems()
+ }, this.registerFindHook(findText), this.registerFindHook(findTextStyle), this.registerFindHook(findMultipleBaseTextures), this.registerFindHook(findBaseTexture), this.registerFindHook(findTexture), this.registerUploadHook(drawText), this.registerUploadHook(calculateTextStyle)
+ };
+
+ function findMultipleBaseTextures(t, e) {
+ var r = !1;
+ if (t && t._textures && t._textures.length)
+ for (var n = 0; n < t._textures.length; n++)
+ if (t._textures[n] instanceof Ht) {
+ var i = t._textures[n].baseTexture; - 1 === e.indexOf(i) && (e.push(i), r = !0)
+ }
+ return r
+ }
+
+ function findBaseTexture(t, e) {
+ return t instanceof Rt && (-1 === e.indexOf(t) && e.push(t), !0)
+ }
+
+ function findTexture(t, e) {
+ if (t._texture && t._texture instanceof Ht) {
+ var r = t._texture.baseTexture;
+ return -1 === e.indexOf(r) && e.push(r), !0
+ }
+ return !1
+ }
+
+ function drawText(t, e) {
+ return e instanceof Qr && (e.updateText(!0), !0)
+ }
+
+ function calculateTextStyle(t, e) {
+ if (e instanceof Hr) {
+ var r = e.toFontString();
+ return Yr.measureFont(r), !0
+ }
+ return !1
+ }
+
+ function findText(t, e) {
+ if (t instanceof Qr) {
+ -1 === e.indexOf(t.style) && e.push(t.style), -1 === e.indexOf(t) && e.push(t);
+ var r = t._texture.baseTexture;
+ return -1 === e.indexOf(r) && e.push(r), !0
+ }
+ return !1
+ }
+
+ function findTextStyle(t, e) {
+ return t instanceof Hr && (-1 === e.indexOf(t) && e.push(t), !0)
+ }
+ $r.prototype.upload = function(t, e) {
+ "function" == typeof t && (e = t, t = null), t && this.add(t), this.queue.length ? (e && this.completes.push(e), this.ticking || (this.ticking = !0, xt.system.addOnce(this.tick, this, _t.UTILITY))) : e && e()
+ }, $r.prototype.tick = function() {
+ setTimeout(this.delayedTick, 0)
+ }, $r.prototype.prepareItems = function() {
+ for (this.limiter.beginFrame(); this.queue.length && this.limiter.allowedToUpload();) {
+ var t = this.queue[0],
+ e = !1;
+ if (t && !t._destroyed)
+ for (var r = 0, n = this.uploadHooks.length; r < n; r++)
+ if (this.uploadHooks[r](this.uploadHookHelper, t)) {
+ this.queue.shift(), e = !0;
+ break
+ }
+ e || this.queue.shift()
+ }
+ if (this.queue.length) xt.system.addOnce(this.tick, this, _t.UTILITY);
+ else {
+ this.ticking = !1;
+ for (var i = this.completes.slice(0), o = this.completes.length = 0, a = i.length; o < a; o++) i[o]()
+ }
+ }, $r.prototype.registerFindHook = function(t) {
+ return t && this.addHooks.push(t), this
+ }, $r.prototype.registerUploadHook = function(t) {
+ return t && this.uploadHooks.push(t), this
+ }, $r.prototype.add = function(t) {
+ for (var e = 0, r = this.addHooks.length; e < r && !this.addHooks[e](t, this.queue); e++);
+ if (t instanceof pt)
+ for (var n = t.children.length - 1; 0 <= n; n--) this.add(t.children[n]);
+ return this
+ }, $r.prototype.destroy = function() {
+ this.ticking && xt.system.remove(this.tick, this), this.ticking = !1, this.addHooks = null, this.uploadHooks = null, this.renderer = null, this.completes = null, this.queue = null, this.limiter = null, this.uploadHookHelper = null
+ };
+ var tn = function(e) {
+ function Prepare(t) {
+ e.call(this, t), this.uploadHookHelper = this.renderer, this.registerFindHook(findGraphics), this.registerUploadHook(uploadBaseTextures), this.registerUploadHook(uploadGraphics)
+ }
+ return e && (Prepare.__proto__ = e), (Prepare.prototype = Object.create(e && e.prototype)).constructor = Prepare
+ }($r);
+
+ function uploadBaseTextures(t, e) {
+ return e instanceof Rt && (e._glTextures[t.CONTEXT_UID] || t.textureManager.updateTexture(e), !0)
+ }
+
+ function uploadGraphics(t, e) {
+ return e instanceof Gr && ((e.dirty || e.clearDirty || !e._webGL[t.plugins.graphics.CONTEXT_UID]) && t.plugins.graphics.updateGraphics(e), !0)
+ }
+
+ function findGraphics(t, e) {
+ return t instanceof Gr && (e.push(t), !0)
+ }
+ var en = function(t) {
+ this.maxMilliseconds = t, this.frameStart = 0
+ };
+ en.prototype.beginFrame = function() {
+ this.frameStart = Date.now()
+ }, en.prototype.allowedToUpload = function() {
+ return Date.now() - this.frameStart < this.maxMilliseconds
+ };
+ var rn = function Application(e) {
+ var r = this;
+ e = Object.assign({
+ forceCanvas: !1
+ }, e), this.renderer = autoDetectRenderer(e), this.stage = new pt, Application._plugins.forEach(function(t) {
+ t.init.call(r, e)
+ })
+ },
+ nn = {
+ view: {
+ configurable: !0
+ },
+ screen: {
+ configurable: !0
+ }
+ };
+ rn.registerPlugin = function(t) {
+ rn._plugins.push(t)
+ }, rn.prototype.render = function() {
+ this.renderer.render(this.stage)
+ }, nn.view.get = function() {
+ return this.renderer.view
+ }, nn.screen.get = function() {
+ return this.renderer.screen
+ }, rn.prototype.destroy = function(t) {
+ var e = this,
+ r = rn._plugins.slice(0);
+ r.reverse(), r.forEach(function(t) {
+ t.destroy.call(e)
+ }), this.stage.destroy(), this.stage = null, this.renderer.destroy(t), this.renderer = null, this._options = null
+ }, Object.defineProperties(rn.prototype, nn), rn._plugins = [];
+ var on = function() {};
+ on.init = function(t) {
+ var e = this;
+ Object.defineProperty(this, "resizeTo", {
+ set: function(t) {
+ window.removeEventListener("resize", this.resize), (this._resizeTo = t) && (window.addEventListener("resize", this.resize), this.resize())
+ },
+ get: function() {
+ return this._resizeTo
+ }
+ }), this.resize = function() {
+ e._resizeTo && (e._resizeTo === window ? e.renderer.resize(window.innerWidth, window.innerHeight) : e.renderer.resize(e._resizeTo.clientWidth, e._resizeTo.clientHeight))
+ }, this._resizeTo = null, this.resizeTo = t.resizeTo || null
+ }, on.destroy = function() {
+ this.resizeTo = null, this.resize = null
+ }, rn.registerPlugin(on);
+ var an = r(66),
+ sn = r.n(an);
+
+ function unwrapExports(t) {
+ return t && t.__esModule && Object.prototype.hasOwnProperty.call(t, "default") ? t.default : t
+ }
+
+ function createCommonjsModule(t, e) {
+ return t(e = {
+ exports: {}
+ }, e.exports), e.exports
+ }
+ var un = function(t, e) {
+ e = e || {};
+ for (var n = {
+ key: ["source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor"],
+ q: {
+ name: "queryKey",
+ parser: /(?:^|&)([^&=]*)=?([^&]*)/g
+ },
+ parser: {
+ strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
+ loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
+ }
+ }, r = n.parser[e.strictMode ? "strict" : "loose"].exec(t), i = {}, o = 14; o--;) i[n.key[o]] = r[o] || "";
+ return i[n.q.name] = {}, i[n.key[12]].replace(n.q.parser, function(t, e, r) {
+ e && (i[n.q.name][e] = r)
+ }), i
+ },
+ hn = createCommonjsModule(function(t, e) {
+ Object.defineProperty(e, "__esModule", {
+ value: !0
+ });
+ var r = function() {
+ function defineProperties(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n)
+ }
+ }
+ return function(t, e, r) {
+ return e && defineProperties(t.prototype, e), r && defineProperties(t, r), t
+ }
+ }();
+
+ function _classCallCheck(t, e) {
+ if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
+ }
+ var n = function() {
+ function MiniSignalBinding(t, e, r) {
+ void 0 === e && (e = !1), _classCallCheck(this, MiniSignalBinding), this._fn = t, this._once = e, this._thisArg = r, this._next = this._prev = this._owner = null
+ }
+ return r(MiniSignalBinding, [{
+ key: "detach",
+ value: function() {
+ return null !== this._owner && (this._owner.detach(this), !0)
+ }
+ }]), MiniSignalBinding
+ }();
+
+ function _addMiniSignalBinding(t, e) {
+ return t._head ? (t._tail._next = e)._prev = t._tail : t._head = e, (t._tail = e)._owner = t, e
+ }
+ var i = function() {
+ function MiniSignal() {
+ _classCallCheck(this, MiniSignal), this._head = this._tail = void 0
+ }
+ return r(MiniSignal, [{
+ key: "handlers",
+ value: function() {
+ var t = !(arguments.length <= 0 || void 0 === arguments[0]) && arguments[0],
+ e = this._head;
+ if (t) return !!e;
+ for (var r = []; e;) r.push(e), e = e._next;
+ return r
+ }
+ }, {
+ key: "has",
+ value: function(t) {
+ if (!(t instanceof n)) throw new Error("MiniSignal#has(): First arg must be a MiniSignalBinding object.");
+ return t._owner === this
+ }
+ }, {
+ key: "dispatch",
+ value: function() {
+ var t = arguments,
+ e = this._head;
+ if (!e) return !1;
+ for (; e;) e._once && this.detach(e), e._fn.apply(e._thisArg, t), e = e._next;
+ return !0
+ }
+ }, {
+ key: "add",
+ value: function(t) {
+ var e = arguments.length <= 1 || void 0 === arguments[1] ? null : arguments[1];
+ if ("function" != typeof t) throw new Error("MiniSignal#add(): First arg must be a Function.");
+ return _addMiniSignalBinding(this, new n(t, !1, e))
+ }
+ }, {
+ key: "once",
+ value: function(t) {
+ var e = arguments.length <= 1 || void 0 === arguments[1] ? null : arguments[1];
+ if ("function" != typeof t) throw new Error("MiniSignal#once(): First arg must be a Function.");
+ return _addMiniSignalBinding(this, new n(t, !0, e))
+ }
+ }, {
+ key: "detach",
+ value: function(t) {
+ if (!(t instanceof n)) throw new Error("MiniSignal#detach(): First arg must be a MiniSignalBinding object.");
+ return t._owner !== this || (t._prev && (t._prev._next = t._next), t._next && (t._next._prev = t._prev), t === this._head ? (this._head = t._next, null === t._next && (this._tail = null)) : t === this._tail && (this._tail = t._prev, this._tail._next = null), t._owner = null), this
+ }
+ }, {
+ key: "detachAll",
+ value: function() {
+ var t = this._head;
+ if (!t) return this;
+ for (this._head = this._tail = null; t;) t._owner = null, t = t._next;
+ return this
+ }
+ }]), MiniSignal
+ }();
+ i.MiniSignalBinding = n, e.default = i, t.exports = e.default
+ });
+ unwrapExports(hn);
+ var cn = createCommonjsModule(function(t, e) {
+ e.__esModule = !0, e.Resource = void 0;
+ var r = function() {
+ function defineProperties(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n)
+ }
+ }
+ return function(t, e, r) {
+ return e && defineProperties(t.prototype, e), r && defineProperties(t, r), t
+ }
+ }(),
+ i = _interopRequireDefault(un),
+ n = _interopRequireDefault(hn);
+
+ function _interopRequireDefault(t) {
+ return t && t.__esModule ? t : {
+ default: t
+ }
+ }
+ var o = !(!window.XDomainRequest || "withCredentials" in new XMLHttpRequest),
+ a = null;
+
+ function _noop() {}
+ var s = e.Resource = function() {
+ function Resource(t, e, r) {
+ if (function(t, e) {
+ if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
+ }(this, Resource), "string" != typeof t || "string" != typeof e) throw new Error("Both name and url are required for constructing a resource.");
+ r = r || {}, this._flags = 0, this._setFlag(Resource.STATUS_FLAGS.DATA_URL, 0 === e.indexOf("data:")), this.name = t, this.url = e, this.extension = this._getExtension(), this.data = null, this.crossOrigin = !0 === r.crossOrigin ? "anonymous" : r.crossOrigin, this.timeout = r.timeout || 0, this.loadType = r.loadType || this._determineLoadType(), this.xhrType = r.xhrType, this.metadata = r.metadata || {}, this.error = null, this.xhr = null, this.children = [], this.type = Resource.TYPE.UNKNOWN, this.progressChunk = 0, this._dequeue = _noop, this._onLoadBinding = null, this._elementTimer = 0, this._boundComplete = this.complete.bind(this), this._boundOnError = this._onError.bind(this), this._boundOnProgress = this._onProgress.bind(this), this._boundOnTimeout = this._onTimeout.bind(this), this._boundXhrOnError = this._xhrOnError.bind(this), this._boundXhrOnTimeout = this._xhrOnTimeout.bind(this), this._boundXhrOnAbort = this._xhrOnAbort.bind(this), this._boundXhrOnLoad = this._xhrOnLoad.bind(this), this.onStart = new n.default, this.onProgress = new n.default, this.onComplete = new n.default, this.onAfterMiddleware = new n.default
+ }
+ return Resource.setExtensionLoadType = function(t, e) {
+ setExtMap(Resource._loadTypeMap, t, e)
+ }, Resource.setExtensionXhrType = function(t, e) {
+ setExtMap(Resource._xhrTypeMap, t, e)
+ }, Resource.prototype.complete = function() {
+ this._clearEvents(), this._finish()
+ }, Resource.prototype.abort = function(t) {
+ if (!this.error) {
+ if (this.error = new Error(t), this._clearEvents(), this.xhr) this.xhr.abort();
+ else if (this.xdr) this.xdr.abort();
+ else if (this.data)
+ if (this.data.src) this.data.src = Resource.EMPTY_GIF;
+ else
+ for (; this.data.firstChild;) this.data.removeChild(this.data.firstChild);
+ this._finish()
+ }
+ }, Resource.prototype.load = function(t) {
+ var e = this;
+ if (!this.isLoading)
+ if (this.isComplete) t && setTimeout(function() {
+ return t(e)
+ }, 1);
+ else switch (t && this.onComplete.once(t), this._setFlag(Resource.STATUS_FLAGS.LOADING, !0), this.onStart.dispatch(this), !1 !== this.crossOrigin && "string" == typeof this.crossOrigin || (this.crossOrigin = this._determineCrossOrigin(this.url)), this.loadType) {
+ case Resource.LOAD_TYPE.IMAGE:
+ this.type = Resource.TYPE.IMAGE, this._loadElement("image");
+ break;
+ case Resource.LOAD_TYPE.AUDIO:
+ this.type = Resource.TYPE.AUDIO, this._loadSourceElement("audio");
+ break;
+ case Resource.LOAD_TYPE.VIDEO:
+ this.type = Resource.TYPE.VIDEO, this._loadSourceElement("video");
+ break;
+ case Resource.LOAD_TYPE.XHR:
+ default:
+ o && this.crossOrigin ? this._loadXdr() : this._loadXhr()
+ }
+ }, Resource.prototype._hasFlag = function(t) {
+ return 0 != (this._flags & t)
+ }, Resource.prototype._setFlag = function(t, e) {
+ this._flags = e ? this._flags | t : this._flags & ~t
+ }, Resource.prototype._clearEvents = function() {
+ clearTimeout(this._elementTimer), this.data && this.data.removeEventListener && (this.data.removeEventListener("error", this._boundOnError, !1), this.data.removeEventListener("load", this._boundComplete, !1), this.data.removeEventListener("progress", this._boundOnProgress, !1), this.data.removeEventListener("canplaythrough", this._boundComplete, !1)), this.xhr && (this.xhr.removeEventListener ? (this.xhr.removeEventListener("error", this._boundXhrOnError, !1), this.xhr.removeEventListener("timeout", this._boundXhrOnTimeout, !1), this.xhr.removeEventListener("abort", this._boundXhrOnAbort, !1), this.xhr.removeEventListener("progress", this._boundOnProgress, !1), this.xhr.removeEventListener("load", this._boundXhrOnLoad, !1)) : (this.xhr.onerror = null, this.xhr.ontimeout = null, this.xhr.onprogress = null, this.xhr.onload = null))
+ }, Resource.prototype._finish = function() {
+ if (this.isComplete) throw new Error("Complete called again for an already completed resource.");
+ this._setFlag(Resource.STATUS_FLAGS.COMPLETE, !0), this._setFlag(Resource.STATUS_FLAGS.LOADING, !1), this.onComplete.dispatch(this)
+ }, Resource.prototype._loadElement = function(t) {
+ this.metadata.loadElement ? this.data = this.metadata.loadElement : "image" === t && void 0 !== window.Image ? this.data = new Image : this.data = document.createElement(t), this.crossOrigin && (this.data.crossOrigin = this.crossOrigin), this.metadata.skipSource || (this.data.src = this.url), this.data.addEventListener("error", this._boundOnError, !1), this.data.addEventListener("load", this._boundComplete, !1), this.data.addEventListener("progress", this._boundOnProgress, !1), this.timeout && (this._elementTimer = setTimeout(this._boundOnTimeout, this.timeout))
+ }, Resource.prototype._loadSourceElement = function(t) {
+ if (this.metadata.loadElement ? this.data = this.metadata.loadElement : "audio" === t && void 0 !== window.Audio ? this.data = new Audio : this.data = document.createElement(t), null !== this.data) {
+ if (this.crossOrigin && (this.data.crossOrigin = this.crossOrigin), !this.metadata.skipSource)
+ if (navigator.isCocoonJS) this.data.src = Array.isArray(this.url) ? this.url[0] : this.url;
+ else if (Array.isArray(this.url))
+ for (var e = this.metadata.mimeType, r = 0; r < this.url.length; ++r) this.data.appendChild(this._createSource(t, this.url[r], Array.isArray(e) ? e[r] : e));
+ else {
+ var n = this.metadata.mimeType;
+ this.data.appendChild(this._createSource(t, this.url, Array.isArray(n) ? n[0] : n))
+ }
+ this.data.addEventListener("error", this._boundOnError, !1), this.data.addEventListener("load", this._boundComplete, !1), this.data.addEventListener("progress", this._boundOnProgress, !1), this.data.addEventListener("canplaythrough", this._boundComplete, !1), this.data.load(), this.timeout && (this._elementTimer = setTimeout(this._boundOnTimeout, this.timeout))
+ } else this.abort("Unsupported element: " + t)
+ }, Resource.prototype._loadXhr = function() {
+ "string" != typeof this.xhrType && (this.xhrType = this._determineXhrType());
+ var t = this.xhr = new XMLHttpRequest;
+ t.open("GET", this.url, !0), t.timeout = this.timeout, this.xhrType === Resource.XHR_RESPONSE_TYPE.JSON || this.xhrType === Resource.XHR_RESPONSE_TYPE.DOCUMENT ? t.responseType = Resource.XHR_RESPONSE_TYPE.TEXT : t.responseType = this.xhrType, t.addEventListener("error", this._boundXhrOnError, !1), t.addEventListener("timeout", this._boundXhrOnTimeout, !1), t.addEventListener("abort", this._boundXhrOnAbort, !1), t.addEventListener("progress", this._boundOnProgress, !1), t.addEventListener("load", this._boundXhrOnLoad, !1), t.send()
+ }, Resource.prototype._loadXdr = function() {
+ "string" != typeof this.xhrType && (this.xhrType = this._determineXhrType());
+ var t = this.xhr = new XDomainRequest;
+ t.timeout = this.timeout || 5e3, t.onerror = this._boundXhrOnError, t.ontimeout = this._boundXhrOnTimeout, t.onprogress = this._boundOnProgress, t.onload = this._boundXhrOnLoad, t.open("GET", this.url, !0), setTimeout(function() {
+ return t.send()
+ }, 1)
+ }, Resource.prototype._createSource = function(t, e, r) {
+ r || (r = t + "/" + this._getExtension(e));
+ var n = document.createElement("source");
+ return n.src = e, n.type = r, n
+ }, Resource.prototype._onError = function(t) {
+ this.abort("Failed to load element using: " + t.target.nodeName)
+ }, Resource.prototype._onProgress = function(t) {
+ t && t.lengthComputable && this.onProgress.dispatch(this, t.loaded / t.total)
+ }, Resource.prototype._onTimeout = function() {
+ this.abort("Load timed out.")
+ }, Resource.prototype._xhrOnError = function() {
+ var t = this.xhr;
+ this.abort(reqType(t) + " Request failed. Status: " + t.status + ', text: "' + t.statusText + '"')
+ }, Resource.prototype._xhrOnTimeout = function() {
+ var t = this.xhr;
+ this.abort(reqType(t) + " Request timed out.")
+ }, Resource.prototype._xhrOnAbort = function() {
+ var t = this.xhr;
+ this.abort(reqType(t) + " Request was aborted by the user.")
+ }, Resource.prototype._xhrOnLoad = function() {
+ var t = this.xhr,
+ e = "",
+ r = void 0 === t.status ? 200 : t.status;
+ if ("" !== t.responseType && "text" !== t.responseType && void 0 !== t.responseType || (e = t.responseText), 0 === r && (0 < e.length || t.responseType === Resource.XHR_RESPONSE_TYPE.BUFFER) ? r = 200 : 1223 === r && (r = 204), 2 === (r / 100 | 0)) {
+ if (this.xhrType === Resource.XHR_RESPONSE_TYPE.TEXT) this.data = e, this.type = Resource.TYPE.TEXT;
+ else if (this.xhrType === Resource.XHR_RESPONSE_TYPE.JSON) try {
+ this.data = JSON.parse(e), this.type = Resource.TYPE.JSON
+ } catch (t) {
+ return void this.abort("Error trying to parse loaded json: " + t)
+ } else if (this.xhrType === Resource.XHR_RESPONSE_TYPE.DOCUMENT) try {
+ if (window.DOMParser) {
+ var n = new DOMParser;
+ this.data = n.parseFromString(e, "text/xml")
+ } else {
+ var i = document.createElement("div");
+ i.innerHTML = e, this.data = i
+ }
+ this.type = Resource.TYPE.XML
+ } catch (t) {
+ return void this.abort("Error trying to parse loaded xml: " + t)
+ } else this.data = t.response || e;
+ this.complete()
+ } else this.abort("[" + t.status + "] " + t.statusText + ": " + t.responseURL)
+ }, Resource.prototype._determineCrossOrigin = function(t, e) {
+ if (0 === t.indexOf("data:")) return "";
+ if (window.origin !== window.location.origin) return "anonymous";
+ e = e || window.location, a || (a = document.createElement("a")), a.href = t;
+ var r = !(t = (0, i.default)(a.href, {
+ strictMode: !0
+ })).port && "" === e.port || t.port === e.port,
+ n = t.protocol ? t.protocol + ":" : "";
+ return t.host === e.hostname && r && n === e.protocol ? "" : "anonymous"
+ }, Resource.prototype._determineXhrType = function() {
+ return Resource._xhrTypeMap[this.extension] || Resource.XHR_RESPONSE_TYPE.TEXT
+ }, Resource.prototype._determineLoadType = function() {
+ return Resource._loadTypeMap[this.extension] || Resource.LOAD_TYPE.XHR
+ }, Resource.prototype._getExtension = function() {
+ var t = this.url,
+ e = "";
+ if (this.isDataUrl) {
+ var r = t.indexOf("/");
+ e = t.substring(r + 1, t.indexOf(";", r))
+ } else {
+ var n = t.indexOf("?"),
+ i = t.indexOf("#"),
+ o = Math.min(-1 < n ? n : t.length, -1 < i ? i : t.length);
+ e = (t = t.substring(0, o)).substring(t.lastIndexOf(".") + 1)
+ }
+ return e.toLowerCase()
+ }, Resource.prototype._getMimeFromXhrType = function(t) {
+ switch (t) {
+ case Resource.XHR_RESPONSE_TYPE.BUFFER:
+ return "application/octet-binary";
+ case Resource.XHR_RESPONSE_TYPE.BLOB:
+ return "application/blob";
+ case Resource.XHR_RESPONSE_TYPE.DOCUMENT:
+ return "application/xml";
+ case Resource.XHR_RESPONSE_TYPE.JSON:
+ return "application/json";
+ case Resource.XHR_RESPONSE_TYPE.DEFAULT:
+ case Resource.XHR_RESPONSE_TYPE.TEXT:
+ default:
+ return "text/plain"
+ }
+ }, r(Resource, [{
+ key: "isDataUrl",
+ get: function() {
+ return this._hasFlag(Resource.STATUS_FLAGS.DATA_URL)
+ }
+ }, {
+ key: "isComplete",
+ get: function() {
+ return this._hasFlag(Resource.STATUS_FLAGS.COMPLETE)
+ }
+ }, {
+ key: "isLoading",
+ get: function() {
+ return this._hasFlag(Resource.STATUS_FLAGS.LOADING)
+ }
+ }]), Resource
+ }();
+
+ function setExtMap(t, e, r) {
+ e && 0 === e.indexOf(".") && (e = e.substring(1)), e && (t[e] = r)
+ }
+
+ function reqType(t) {
+ return t.toString().replace("object ", "")
+ }
+ s.STATUS_FLAGS = {
+ NONE: 0,
+ DATA_URL: 1,
+ COMPLETE: 2,
+ LOADING: 4
+ }, s.TYPE = {
+ UNKNOWN: 0,
+ JSON: 1,
+ XML: 2,
+ IMAGE: 3,
+ AUDIO: 4,
+ VIDEO: 5,
+ TEXT: 6
+ }, s.LOAD_TYPE = {
+ XHR: 1,
+ IMAGE: 2,
+ AUDIO: 3,
+ VIDEO: 4
+ }, s.XHR_RESPONSE_TYPE = {
+ DEFAULT: "text",
+ BUFFER: "arraybuffer",
+ BLOB: "blob",
+ DOCUMENT: "document",
+ JSON: "json",
+ TEXT: "text"
+ }, s._loadTypeMap = {
+ gif: s.LOAD_TYPE.IMAGE,
+ png: s.LOAD_TYPE.IMAGE,
+ bmp: s.LOAD_TYPE.IMAGE,
+ jpg: s.LOAD_TYPE.IMAGE,
+ jpeg: s.LOAD_TYPE.IMAGE,
+ tif: s.LOAD_TYPE.IMAGE,
+ tiff: s.LOAD_TYPE.IMAGE,
+ webp: s.LOAD_TYPE.IMAGE,
+ tga: s.LOAD_TYPE.IMAGE,
+ svg: s.LOAD_TYPE.IMAGE,
+ "svg+xml": s.LOAD_TYPE.IMAGE,
+ mp3: s.LOAD_TYPE.AUDIO,
+ ogg: s.LOAD_TYPE.AUDIO,
+ wav: s.LOAD_TYPE.AUDIO,
+ mp4: s.LOAD_TYPE.VIDEO,
+ webm: s.LOAD_TYPE.VIDEO
+ }, s._xhrTypeMap = {
+ xhtml: s.XHR_RESPONSE_TYPE.DOCUMENT,
+ html: s.XHR_RESPONSE_TYPE.DOCUMENT,
+ htm: s.XHR_RESPONSE_TYPE.DOCUMENT,
+ xml: s.XHR_RESPONSE_TYPE.DOCUMENT,
+ tmx: s.XHR_RESPONSE_TYPE.DOCUMENT,
+ svg: s.XHR_RESPONSE_TYPE.DOCUMENT,
+ tsx: s.XHR_RESPONSE_TYPE.DOCUMENT,
+ gif: s.XHR_RESPONSE_TYPE.BLOB,
+ png: s.XHR_RESPONSE_TYPE.BLOB,
+ bmp: s.XHR_RESPONSE_TYPE.BLOB,
+ jpg: s.XHR_RESPONSE_TYPE.BLOB,
+ jpeg: s.XHR_RESPONSE_TYPE.BLOB,
+ tif: s.XHR_RESPONSE_TYPE.BLOB,
+ tiff: s.XHR_RESPONSE_TYPE.BLOB,
+ webp: s.XHR_RESPONSE_TYPE.BLOB,
+ tga: s.XHR_RESPONSE_TYPE.BLOB,
+ json: s.XHR_RESPONSE_TYPE.JSON,
+ text: s.XHR_RESPONSE_TYPE.TEXT,
+ txt: s.XHR_RESPONSE_TYPE.TEXT,
+ ttf: s.XHR_RESPONSE_TYPE.BUFFER,
+ otf: s.XHR_RESPONSE_TYPE.BUFFER
+ }, s.EMPTY_GIF = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==", t.exports.default = s
+ });
+ unwrapExports(cn);
+ cn.Resource;
+ var ln = createCommonjsModule(function(t, e) {
+ e.__esModule = !0, e.encodeBinary = encodeBinary;
+ var s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+ function encodeBinary(t) {
+ for (var e = "", r = 0; r < t.length;) {
+ for (var n = [0, 0, 0], i = [0, 0, 0, 0], o = 0; o < n.length; ++o) r < t.length ? n[o] = 255 & t.charCodeAt(r++) : n[o] = 0;
+ switch (i[0] = n[0] >> 2, i[1] = (3 & n[0]) << 4 | n[1] >> 4, i[2] = (15 & n[1]) << 2 | n[2] >> 6, i[3] = 63 & n[2], r - (t.length - 1)) {
+ case 2:
+ i[3] = 64, i[2] = 64;
+ break;
+ case 1:
+ i[3] = 64
+ }
+ for (var a = 0; a < i.length; ++a) e += s.charAt(i[a])
+ }
+ return e
+ }
+ t.exports.default = encodeBinary
+ });
+ unwrapExports(ln);
+ ln.encodeBinary;
+ var fn = createCommonjsModule(function(t, e) {
+ e.__esModule = !0, e.blobMiddlewareFactory = function() {
+ return function(t, e) {
+ if (t.data) {
+ if (t.xhr && t.xhrType === cn.Resource.XHR_RESPONSE_TYPE.BLOB)
+ if (window.Blob && "string" != typeof t.data) {
+ if (0 === t.data.type.indexOf("image")) {
+ var r = i.createObjectURL(t.data);
+ return t.blob = t.data, t.data = new Image, t.data.src = r, t.type = cn.Resource.TYPE.IMAGE, void(t.data.onload = function() {
+ i.revokeObjectURL(r), t.data.onload = null, e()
+ })
+ }
+ } else {
+ var n = t.xhr.getResponseHeader("content-type");
+ if (n && 0 === n.indexOf("image")) return t.data = new Image, t.data.src = "data:" + n + ";base64," + (0, ln.encodeBinary)(t.xhr.responseText), t.type = cn.Resource.TYPE.IMAGE, void(t.data.onload = function() {
+ t.data.onload = null, e()
+ })
+ }
+ e()
+ } else e()
+ }
+ };
+ var i = window.URL || window.webkitURL
+ });
+ unwrapExports(fn);
+ var dn = fn.blobMiddlewareFactory,
+ pn = function() {};
+ pn.use = function(t, e) {
+ t.data && t.type === an.Resource.TYPE.IMAGE && (t.texture = Ht.fromLoader(t.data, t.url, t.name)), e()
+ };
+ var mn = function(s) {
+ function Loader(t, e) {
+ var n = this;
+ s.call(this, t, e), l.a.call(this);
+ for (var r = 0; r < Loader._plugins.length; ++r) {
+ var i = Loader._plugins[r],
+ o = i.pre,
+ a = i.use;
+ o && this.pre(o), a && this.use(a)
+ }
+ this.onStart.add(function(t) {
+ return n.emit("start", t)
+ }), this.onProgress.add(function(t, e) {
+ return n.emit("progress", t, e)
+ }), this.onError.add(function(t, e, r) {
+ return n.emit("error", t, e, r)
+ }), this.onLoad.add(function(t, e) {
+ return n.emit("load", t, e)
+ }), this.onComplete.add(function(t, e) {
+ return n.emit("complete", t, e)
+ }), this._protected = !1
+ }
+ s && (Loader.__proto__ = s);
+ var t = {
+ shared: {
+ configurable: !0
+ }
+ };
+ return ((Loader.prototype = Object.create(s && s.prototype)).constructor = Loader).prototype.destroy = function() {
+ this._protected || (this.removeAllListeners(), this.reset())
+ }, t.shared.get = function() {
+ var t = Loader._shared;
+ return t || ((t = new Loader)._protected = !0, Loader._shared = t), t
+ }, Object.defineProperties(Loader, t), Loader
+ }(sn.a);
+ Object.assign(mn.prototype, l.a.prototype), mn._plugins = [], mn.registerPlugin = function(t) {
+ return mn._plugins.push(t), t.add && t.add(), mn
+ }, mn.registerPlugin({
+ use: dn()
+ }), mn.registerPlugin(pn);
+ var vn = function() {};
+ vn.init = function(t) {
+ t = Object.assign({
+ sharedLoader: !1
+ }, t), this.loader = t.sharedLoader ? mn.shared : new mn
+ }, vn.destroy = function() {
+ this.loader && (this.loader.destroy(), this.loader = null)
+ };
+ var gn = an.Resource,
+ yn = function(i) {
+ function ParticleContainer(t, e, r, n) {
+ void 0 === t && (t = 1500), void 0 === r && (r = 16384), void 0 === n && (n = !1), i.call(this);
+ 16384 < r && (r = 16384), t < r && (r = t), this._properties = [!1, !0, !1, !1, !1], this._maxSize = t, this._batchSize = r, this._buffers = null, this._bufferUpdateIDs = [], this._updateID = 0, this.interactiveChildren = !1, this.blendMode = y.NORMAL, this.autoResize = n, this.roundPixels = !0, this.baseTexture = null, this.setProperties(e), this._tint = 0, this.tintRgb = new Float32Array(4), this.tint = 16777215
+ }
+ i && (ParticleContainer.__proto__ = i);
+ var t = {
+ tint: {
+ configurable: !0
+ }
+ };
+ return ((ParticleContainer.prototype = Object.create(i && i.prototype)).constructor = ParticleContainer).prototype.setProperties = function(t) {
+ t && (this._properties[0] = "vertices" in t || "scale" in t ? !!t.vertices || !!t.scale : this._properties[0], this._properties[1] = "position" in t ? !!t.position : this._properties[1], this._properties[2] = "rotation" in t ? !!t.rotation : this._properties[2], this._properties[3] = "uvs" in t ? !!t.uvs : this._properties[3], this._properties[4] = "tint" in t || "alpha" in t ? !!t.tint || !!t.alpha : this._properties[4])
+ }, ParticleContainer.prototype.updateTransform = function() {
+ this.displayObjectUpdateTransform()
+ }, t.tint.get = function() {
+ return this._tint
+ }, t.tint.set = function(t) {
+ hex2rgb(this._tint = t, this.tintRgb)
+ }, ParticleContainer.prototype.render = function(t) {
+ var e = this;
+ this.visible && !(this.worldAlpha <= 0) && this.children.length && this.renderable && (this.baseTexture || (this.baseTexture = this.children[0]._texture.baseTexture, this.baseTexture.valid || this.baseTexture.once("update", function() {
+ return e.onChildrenChange(0)
+ })), t.batch.setObjectRenderer(t.plugins.particle), t.plugins.particle.render(this))
+ }, ParticleContainer.prototype.onChildrenChange = function(t) {
+ for (var e = Math.floor(t / this._batchSize); this._bufferUpdateIDs.length < e;) this._bufferUpdateIDs.push(0);
+ this._bufferUpdateIDs[e] = ++this._updateID
+ }, ParticleContainer.prototype.dispose = function() {
+ if (this._buffers) {
+ for (var t = 0; t < this._buffers.length; ++t) this._buffers[t].destroy();
+ this._buffers = null
+ }
+ }, ParticleContainer.prototype.destroy = function(t) {
+ i.prototype.destroy.call(this, t), this.dispose(), this._properties = null, this._buffers = null, this._bufferUpdateIDs = null
+ }, Object.defineProperties(ParticleContainer.prototype, t), ParticleContainer
+ }(pt),
+ _n = function(t, e, r) {
+ this.geometry = new ee, this.indexBuffer = null, this.size = r, this.dynamicProperties = [], this.staticProperties = [];
+ for (var n = 0; n < t.length; ++n) {
+ var i = t[n];
+ i = {
+ attributeName: i.attributeName,
+ size: i.size,
+ uploadFunction: i.uploadFunction,
+ type: i.type || w.FLOAT,
+ offset: i.offset
+ }, e[n] ? this.dynamicProperties.push(i) : this.staticProperties.push(i)
+ }
+ this.staticStride = 0, this.staticBuffer = null, this.staticData = null, this.staticDataUint32 = null, this.dynamicStride = 0, this.dynamicBuffer = null, this.dynamicData = null, this.dynamicDataUint32 = null, this._updateID = 0, this.initBuffers()
+ };
+ _n.prototype.initBuffers = function() {
+ var t = this.geometry,
+ e = 0;
+ this.indexBuffer = new Zt(createIndicesForQuads(this.size), !0, !0), t.addIndex(this.indexBuffer);
+ for (var r = this.dynamicStride = 0; r < this.dynamicProperties.length; ++r) {
+ var n = this.dynamicProperties[r];
+ n.offset = e, e += n.size, this.dynamicStride += n.size
+ }
+ var i = new ArrayBuffer(this.size * this.dynamicStride * 4 * 4);
+ this.dynamicData = new Float32Array(i), this.dynamicDataUint32 = new Uint32Array(i), this.dynamicBuffer = new Zt(this.dynamicData, !1, !1);
+ for (var o = 0, a = this.staticStride = 0; a < this.staticProperties.length; ++a) {
+ var s = this.staticProperties[a];
+ s.offset = o, o += s.size, this.staticStride += s.size
+ }
+ var u = new ArrayBuffer(this.size * this.staticStride * 4 * 4);
+ this.staticData = new Float32Array(u), this.staticDataUint32 = new Uint32Array(u), this.staticBuffer = new Zt(this.staticData, !0, !1);
+ for (var h = 0; h < this.dynamicProperties.length; ++h) {
+ var c = this.dynamicProperties[h];
+ t.addAttribute(c.attributeName, this.dynamicBuffer, 0, c.type === w.UNSIGNED_BYTE, c.type, 4 * this.dynamicStride, 4 * c.offset)
+ }
+ for (var l = 0; l < this.staticProperties.length; ++l) {
+ var f = this.staticProperties[l];
+ t.addAttribute(f.attributeName, this.staticBuffer, 0, f.type === w.UNSIGNED_BYTE, f.type, 4 * this.staticStride, 4 * f.offset)
+ }
+ }, _n.prototype.uploadDynamic = function(t, e, r) {
+ for (var n = 0; n < this.dynamicProperties.length; n++) {
+ var i = this.dynamicProperties[n];
+ i.uploadFunction(t, e, r, i.type === w.UNSIGNED_BYTE ? this.dynamicDataUint32 : this.dynamicData, this.dynamicStride, i.offset)
+ }
+ this.dynamicBuffer._updateID++
+ }, _n.prototype.uploadStatic = function(t, e, r) {
+ for (var n = 0; n < this.staticProperties.length; n++) {
+ var i = this.staticProperties[n];
+ i.uploadFunction(t, e, r, i.type === w.UNSIGNED_BYTE ? this.staticDataUint32 : this.staticData, this.staticStride, i.offset)
+ }
+ this.staticBuffer._updateID++
+ }, _n.prototype.destroy = function() {
+ this.indexBuffer = null, this.dynamicProperties = null, this.dynamicBuffer = null, this.dynamicData = null, this.dynamicDataUint32 = null, this.staticProperties = null, this.staticBuffer = null, this.staticData = null, this.staticDataUint32 = null, this.geometry.destroy()
+ };
+ var bn = function(e) {
+ function ParticleRenderer(t) {
+ e.call(this, t), this.shader = null, this.properties = null, this.tempMatrix = new Y, this.properties = [{
+ attributeName: "aVertexPosition",
+ size: 2,
+ uploadFunction: this.uploadVertices,
+ offset: 0
+ }, {
+ attributeName: "aPositionCoord",
+ size: 2,
+ uploadFunction: this.uploadPosition,
+ offset: 0
+ }, {
+ attributeName: "aRotation",
+ size: 1,
+ uploadFunction: this.uploadRotation,
+ offset: 0
+ }, {
+ attributeName: "aTextureCoord",
+ size: 2,
+ uploadFunction: this.uploadUvs,
+ offset: 0
+ }, {
+ attributeName: "aColor",
+ size: 1,
+ type: w.UNSIGNED_BYTE,
+ uploadFunction: this.uploadTint,
+ offset: 0
+ }], this.shader = Ie.from("attribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec4 aColor;\n\nattribute vec2 aPositionCoord;\nattribute float aRotation;\n\nuniform mat3 translationMatrix;\nuniform vec4 uColor;\n\nvarying vec2 vTextureCoord;\nvarying vec4 vColor;\n\nvoid main(void){\n float x = (aVertexPosition.x) * cos(aRotation) - (aVertexPosition.y) * sin(aRotation);\n float y = (aVertexPosition.x) * sin(aRotation) + (aVertexPosition.y) * cos(aRotation);\n\n vec2 v = vec2(x, y);\n v = v + aPositionCoord;\n\n gl_Position = vec4((translationMatrix * vec3(v, 1.0)).xy, 0.0, 1.0);\n\n vTextureCoord = aTextureCoord;\n vColor = aColor * uColor;\n}\n", "varying vec2 vTextureCoord;\nvarying vec4 vColor;\n\nuniform sampler2D uSampler;\n\nvoid main(void){\n vec4 color = texture2D(uSampler, vTextureCoord) * vColor;\n gl_FragColor = color;\n}", {})
+ }
+ return e && (ParticleRenderer.__proto__ = e), ((ParticleRenderer.prototype = Object.create(e && e.prototype)).constructor = ParticleRenderer).prototype.render = function(t) {
+ var e = t.children,
+ r = t._maxSize,
+ n = t._batchSize,
+ i = this.renderer,
+ o = e.length;
+ if (0 !== o) {
+ r < o && (o = r);
+ var a = t._buffers;
+ a || (a = t._buffers = this.generateBuffers(t));
+ var s = e[0]._texture.baseTexture;
+ this.renderer.state.setBlendMode(correctBlendMode(t.blendMode, s.premultiplyAlpha));
+ var u = i.gl,
+ h = t.worldTransform.copyTo(this.tempMatrix);
+ h.prepend(i.globalUniforms.uniforms.projectionMatrix), this.shader.uniforms.translationMatrix = h.toArray(!0), this.shader.uniforms.uColor = premultiplyRgba(t.tintRgb, t.worldAlpha, this.shader.uniforms.uColor, s.premultiplyAlpha), this.shader.uniforms.uSampler = s, this.renderer.shader.bind(this.shader);
+ for (var c = !1, l = 0, f = 0; l < o; l += n, f += 1) {
+ var d = o - l;
+ if (n < d && (d = n), f >= a.length) {
+ if (!t.autoResize) break;
+ a.push(this._generateOneMoreBuffer(t))
+ }
+ var p = a[f];
+ p.uploadDynamic(e, l, d);
+ var m = t._bufferUpdateIDs[f] || 0;
+ (c = c || p._updateID < m) && (p._updateID = t._updateID, p.uploadStatic(e, l, d)), i.geometry.bind(p.geometry), u.drawElements(u.TRIANGLES, 6 * d, u.UNSIGNED_SHORT, 0)
+ }
+ }
+ }, ParticleRenderer.prototype.generateBuffers = function(t) {
+ for (var e = [], r = t._maxSize, n = t._batchSize, i = t._properties, o = 0; o < r; o += n) e.push(new _n(this.properties, i, n));
+ return e
+ }, ParticleRenderer.prototype._generateOneMoreBuffer = function(t) {
+ var e = t._batchSize,
+ r = t._properties;
+ return new _n(this.properties, r, e)
+ }, ParticleRenderer.prototype.uploadVertices = function(t, e, r, n, i, o) {
+ for (var a = 0, s = 0, u = 0, h = 0, c = 0; c < r; ++c) {
+ var l = t[e + c],
+ f = l._texture,
+ d = l.scale.x,
+ p = l.scale.y,
+ m = f.trim,
+ v = f.orig;
+ m ? (a = (s = m.x - l.anchor.x * v.width) + m.width, u = (h = m.y - l.anchor.y * v.height) + m.height) : (a = v.width * (1 - l.anchor.x), s = v.width * -l.anchor.x, u = v.height * (1 - l.anchor.y), h = v.height * -l.anchor.y), n[o] = s * d, n[o + 1] = h * p, n[o + i] = a * d, n[o + i + 1] = h * p, n[o + 2 * i] = a * d, n[o + 2 * i + 1] = u * p, n[o + 3 * i] = s * d, n[o + 3 * i + 1] = u * p, o += 4 * i
+ }
+ }, ParticleRenderer.prototype.uploadPosition = function(t, e, r, n, i, o) {
+ for (var a = 0; a < r; a++) {
+ var s = t[e + a].position;
+ n[o] = s.x, n[o + 1] = s.y, n[o + i] = s.x, n[o + i + 1] = s.y, n[o + 2 * i] = s.x, n[o + 2 * i + 1] = s.y, n[o + 3 * i] = s.x, n[o + 3 * i + 1] = s.y, o += 4 * i
+ }
+ }, ParticleRenderer.prototype.uploadRotation = function(t, e, r, n, i, o) {
+ for (var a = 0; a < r; a++) {
+ var s = t[e + a].rotation;
+ n[o] = s, n[o + i] = s, n[o + 2 * i] = s, n[o + 3 * i] = s, o += 4 * i
+ }
+ }, ParticleRenderer.prototype.uploadUvs = function(t, e, r, n, i, o) {
+ for (var a = 0; a < r; ++a) {
+ var s = t[e + a]._texture._uvs;
+ n[o + 3 * i + 1] = s ? (n[o] = s.x0, n[o + 1] = s.y0, n[o + i] = s.x1, n[o + i + 1] = s.y1, n[o + 2 * i] = s.x2, n[o + 2 * i + 1] = s.y2, n[o + 3 * i] = s.x3, s.y3) : (n[o] = 0, n[o + 1] = 0, n[o + i] = 0, n[o + i + 1] = 0, n[o + 2 * i] = 0, n[o + 2 * i + 1] = 0, n[o + 3 * i] = 0), o += 4 * i
+ }
+ }, ParticleRenderer.prototype.uploadTint = function(t, e, r, n, i, o) {
+ for (var a = 0; a < r; ++a) {
+ var s = t[e + a],
+ u = s._texture.baseTexture.premultiplyAlpha,
+ h = s.alpha,
+ c = h < 1 && u ? premultiplyTint(s._tintRGB, h) : s._tintRGB + (255 * h << 24);
+ n[o] = c, n[o + i] = c, n[o + 2 * i] = c, n[o + 3 * i] = c, o += 4 * i
+ }
+ }, ParticleRenderer.prototype.destroy = function() {
+ e.prototype.destroy.call(this), this.shader && (this.shader.destroy(), this.shader = null), this.tempMatrix = null
+ }, ParticleRenderer
+ }(he),
+ xn = function(t, e, r) {
+ void 0 === r && (r = null), this.baseTexture = t, this.textures = {}, this.animations = {}, this.data = e, this.resolution = this._updateResolution(r || (this.baseTexture.resource ? this.baseTexture.resource.url : null)), this._frames = this.data.frames, this._frameKeys = Object.keys(this._frames), this._batchIndex = 0, this._callback = null
+ },
+ wn = {
+ BATCH_SIZE: {
+ configurable: !0
+ }
+ };
+ wn.BATCH_SIZE.get = function() {
+ return 1e3
+ }, xn.prototype._updateResolution = function(t) {
+ var e = this.data.meta.scale,
+ r = getResolutionOfUrl(t, null);
+ return null === r && (r = void 0 !== e ? parseFloat(e) : 1), 1 !== r && this.baseTexture.setResolution(r), r
+ }, xn.prototype.parse = function(t) {
+ this._batchIndex = 0, this._callback = t, this._frameKeys.length <= xn.BATCH_SIZE ? (this._processFrames(0), this._processAnimations(), this._parseComplete()) : this._nextBatch()
+ }, xn.prototype._processFrames = function(t) {
+ for (var e = t, r = xn.BATCH_SIZE; e - t < r && e < this._frameKeys.length;) {
+ var n = this._frameKeys[e],
+ i = this._frames[n],
+ o = i.frame;
+ if (o) {
+ var a = null,
+ s = null,
+ u = !1 !== i.trimmed && i.sourceSize ? i.sourceSize : i.frame,
+ h = new ot(0, 0, Math.floor(u.w) / this.resolution, Math.floor(u.h) / this.resolution);
+ a = i.rotated ? new ot(Math.floor(o.x) / this.resolution, Math.floor(o.y) / this.resolution, Math.floor(o.h) / this.resolution, Math.floor(o.w) / this.resolution) : new ot(Math.floor(o.x) / this.resolution, Math.floor(o.y) / this.resolution, Math.floor(o.w) / this.resolution, Math.floor(o.h) / this.resolution), !1 !== i.trimmed && i.spriteSourceSize && (s = new ot(Math.floor(i.spriteSourceSize.x) / this.resolution, Math.floor(i.spriteSourceSize.y) / this.resolution, Math.floor(o.w) / this.resolution, Math.floor(o.h) / this.resolution)), this.textures[n] = new Ht(this.baseTexture, a, h, s, i.rotated ? 2 : 0, i.anchor), Ht.addToCache(this.textures[n], n)
+ }
+ e++
+ }
+ }, xn.prototype._processAnimations = function() {
+ var t = this.data.animations || {};
+ for (var e in t) {
+ this.animations[e] = [];
+ for (var r = 0; r < t[e].length; r++) {
+ var n = t[e][r];
+ this.animations[e].push(this.textures[n])
+ }
+ }
+ }, xn.prototype._parseComplete = function() {
+ var t = this._callback;
+ this._callback = null, this._batchIndex = 0, t.call(this, this.textures)
+ }, xn.prototype._nextBatch = function() {
+ var t = this;
+ this._processFrames(this._batchIndex * xn.BATCH_SIZE), this._batchIndex++, setTimeout(function() {
+ t._batchIndex * xn.BATCH_SIZE < t._frameKeys.length ? t._nextBatch() : (t._processAnimations(), t._parseComplete())
+ }, 0)
+ }, xn.prototype.destroy = function(t) {
+ for (var e in void 0 === t && (t = !1), this.textures) this.textures[e].destroy();
+ this._frames = null, this._frameKeys = null, this.data = null, this.textures = null, t && this.baseTexture.destroy(), this.baseTexture = null
+ }, Object.defineProperties(xn, wn);
+ var Tn = function() {};
+ Tn.use = function(r, n) {
+ var t = r.name + "_image";
+ if (r.data && r.type === gn.TYPE.JSON && r.data.frames && !this.resources[t]) {
+ var e = {
+ crossOrigin: r.crossOrigin,
+ metadata: r.metadata.imageMetadata,
+ parentResource: r
+ },
+ i = Tn.getResourcePath(r, this.baseUrl);
+ this.add(t, i, e, function(t) {
+ if (t.error) n(t.error);
+ else {
+ var e = new xn(t.texture.baseTexture, r.data, r.url);
+ e.parse(function() {
+ r.spritesheet = e, r.textures = e.textures, n()
+ })
+ }
+ })
+ } else n()
+ }, Tn.getResourcePath = function(t, e) {
+ return t.isDataUrl ? t.data.meta.image : m.a.resolve(t.url.replace(e, ""), t.data.meta.image)
+ };
+ var Sn = new q,
+ Mn = function(n) {
+ function TilingSprite(t, e, r) {
+ void 0 === e && (e = 100), void 0 === r && (r = 100), n.call(this, t), this.tileTransform = new nt, this._width = e, this._height = r, this._canvasPattern = null, this.uvMatrix = t.uvMatrix || new ke(t), this.pluginName = "tilingSprite", this.uvRespectAnchor = !1
+ }
+ n && (TilingSprite.__proto__ = n), (TilingSprite.prototype = Object.create(n && n.prototype)).constructor = TilingSprite;
+ var t = {
+ clampMargin: {
+ configurable: !0
+ },
+ tileScale: {
+ configurable: !0
+ },
+ tilePosition: {
+ configurable: !0
+ },
+ width: {
+ configurable: !0
+ },
+ height: {
+ configurable: !0
+ }
+ };
+ return t.clampMargin.get = function() {
+ return this.uvMatrix.clampMargin
+ }, t.clampMargin.set = function(t) {
+ this.uvMatrix.clampMargin = t, this.uvMatrix.update(!0)
+ }, t.tileScale.get = function() {
+ return this.tileTransform.scale
+ }, t.tileScale.set = function(t) {
+ this.tileTransform.scale.copyFrom(t)
+ }, t.tilePosition.get = function() {
+ return this.tileTransform.position
+ }, t.tilePosition.set = function(t) {
+ this.tileTransform.position.copyFrom(t)
+ }, TilingSprite.prototype._onTextureUpdate = function() {
+ this.uvMatrix && (this.uvMatrix.texture = this._texture), this.cachedTint = 16777215
+ }, TilingSprite.prototype._render = function(t) {
+ var e = this._texture;
+ e && e.valid && (this.tileTransform.updateLocalTransform(), this.uvMatrix.update(), t.batch.setObjectRenderer(t.plugins[this.pluginName]), t.plugins[this.pluginName].render(this))
+ }, TilingSprite.prototype._calculateBounds = function() {
+ var t = this._width * -this._anchor._x,
+ e = this._height * -this._anchor._y,
+ r = this._width * (1 - this._anchor._x),
+ n = this._height * (1 - this._anchor._y);
+ this._bounds.addFrame(this.transform, t, e, r, n)
+ }, TilingSprite.prototype.getLocalBounds = function(t) {
+ return 0 === this.children.length ? (this._bounds.minX = this._width * -this._anchor._x, this._bounds.minY = this._height * -this._anchor._y, this._bounds.maxX = this._width * (1 - this._anchor._x), this._bounds.maxY = this._height * (1 - this._anchor._y), t || (this._localBoundsRect || (this._localBoundsRect = new ot), t = this._localBoundsRect), this._bounds.getRectangle(t)) : n.prototype.getLocalBounds.call(this, t)
+ }, TilingSprite.prototype.containsPoint = function(t) {
+ this.worldTransform.applyInverse(t, Sn);
+ var e = this._width,
+ r = this._height,
+ n = -e * this.anchor._x;
+ if (Sn.x >= n && Sn.x < n + e) {
+ var i = -r * this.anchor._y;
+ if (Sn.y >= i && Sn.y < i + r) return !0
+ }
+ return !1
+ }, TilingSprite.prototype.destroy = function(t) {
+ n.prototype.destroy.call(this, t), this.tileTransform = null, this.uvMatrix = null
+ }, TilingSprite.from = function(t, e, r) {
+ return new TilingSprite(Ht.from(t), e, r)
+ }, TilingSprite.fromFrame = function(t, e, r) {
+ var n = F[t];
+ if (!n) throw new Error('The frameId "' + t + '" does not exist in the texture cache ' + this);
+ return new TilingSprite(n, e, r)
+ }, TilingSprite.fromImage = function(t, e, r, n) {
+ return n && "object" != typeof n && (n = {
+ scaleMode: arguments[4],
+ resourceOptions: {
+ crossorigin: arguments[3]
+ }
+ }), new TilingSprite(Ht.from(t, n), e, r)
+ }, t.width.get = function() {
+ return this._width
+ }, t.width.set = function(t) {
+ this._width = t
+ }, t.height.get = function() {
+ return this._height
+ }, t.height.set = function(t) {
+ this._height = t
+ }, Object.defineProperties(TilingSprite.prototype, t), TilingSprite
+ }(Xr),
+ En = "attribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\nuniform mat3 translationMatrix;\nuniform mat3 uTransform;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n\n vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;\n}\n",
+ An = new Y,
+ Pn = function(r) {
+ function TilingSpriteRenderer(t) {
+ r.call(this, t);
+ var e = {
+ globals: this.renderer.globalUniforms
+ };
+ this.shader = Ie.from(En, "varying vec2 vTextureCoord;\n\nuniform sampler2D uSampler;\nuniform vec4 uColor;\nuniform mat3 uMapCoord;\nuniform vec4 uClampFrame;\nuniform vec2 uClampOffset;\n\nvoid main(void)\n{\n vec2 coord = mod(vTextureCoord - uClampOffset, vec2(1.0, 1.0)) + uClampOffset;\n coord = (uMapCoord * vec3(coord, 1.0)).xy;\n coord = clamp(coord, uClampFrame.xy, uClampFrame.zw);\n\n vec4 sample = texture2D(uSampler, coord);\n gl_FragColor = sample * uColor;\n}\n", e), this.simpleShader = Ie.from(En, "varying vec2 vTextureCoord;\n\nuniform sampler2D uSampler;\nuniform vec4 uColor;\n\nvoid main(void)\n{\n vec4 sample = texture2D(uSampler, vTextureCoord);\n gl_FragColor = sample * uColor;\n}\n", e), this.quad = new ne
+ }
+ return r && (TilingSpriteRenderer.__proto__ = r), ((TilingSpriteRenderer.prototype = Object.create(r && r.prototype)).constructor = TilingSpriteRenderer).prototype.render = function(t) {
+ var e = this.renderer,
+ r = this.quad,
+ n = r.vertices;
+ n[0] = n[6] = t._width * -t.anchor.x, n[1] = n[3] = t._height * -t.anchor.y, n[2] = n[4] = t._width * (1 - t.anchor.x), n[5] = n[7] = t._height * (1 - t.anchor.y), t.uvRespectAnchor && ((n = r.uvs)[0] = n[6] = -t.anchor.x, n[1] = n[3] = -t.anchor.y, n[2] = n[4] = 1 - t.anchor.x, n[5] = n[7] = 1 - t.anchor.y), r.invalidate();
+ var i = t._texture,
+ o = i.baseTexture,
+ a = t.tileTransform.localTransform,
+ s = t.uvMatrix,
+ u = o.isPowerOfTwo && i.frame.width === o.width && i.frame.height === o.height;
+ u && (o._glTextures[e.CONTEXT_UID] ? u = o.wrapMode !== S.CLAMP : o.wrapMode === S.CLAMP && (o.wrapMode = S.REPEAT));
+ var h = u ? this.simpleShader : this.shader,
+ c = i.width,
+ l = i.height,
+ f = t._width,
+ d = t._height;
+ An.set(a.a * c / f, a.b * c / d, a.c * l / f, a.d * l / d, a.tx / f, a.ty / d), An.invert(), u ? An.prepend(s.mapCoord) : (h.uniforms.uMapCoord = s.mapCoord.toArray(!0), h.uniforms.uClampFrame = s.uClampFrame, h.uniforms.uClampOffset = s.uClampOffset), h.uniforms.uTransform = An.toArray(!0), h.uniforms.uColor = premultiplyTintToRgba(t.tint, t.worldAlpha, h.uniforms.uColor, o.premultiplyAlpha), h.uniforms.translationMatrix = t.transform.worldTransform.toArray(!0), h.uniforms.uSampler = i, e.shader.bind(h), e.geometry.bind(r), e.state.setBlendMode(correctBlendMode(t.blendMode, o.premultiplyAlpha)), e.geometry.draw(this.renderer.gl.TRIANGLES, 6, 0)
+ }, TilingSpriteRenderer
+ }(he),
+ In = function(n) {
+ function BitmapText(t, e) {
+ var r = this;
+ void 0 === e && (e = {}), n.call(this), this._textWidth = 0, this._textHeight = 0, this._glyphs = [], this._font = {
+ tint: void 0 !== e.tint ? e.tint : 16777215,
+ align: e.align || "left",
+ name: null,
+ size: 0
+ }, this.font = e.font, this._text = t, this._maxWidth = 0, this._maxLineHeight = 0, this._letterSpacing = 0, this._anchor = new j(function() {
+ r.dirty = !0
+ }, this, 0, 0), this.dirty = !1, this.roundPixels = M.ROUND_PIXELS, this.updateText()
+ }
+ n && (BitmapText.__proto__ = n);
+ var t = {
+ tint: {
+ configurable: !0
+ },
+ align: {
+ configurable: !0
+ },
+ anchor: {
+ configurable: !0
+ },
+ font: {
+ configurable: !0
+ },
+ text: {
+ configurable: !0
+ },
+ maxWidth: {
+ configurable: !0
+ },
+ maxLineHeight: {
+ configurable: !0
+ },
+ textWidth: {
+ configurable: !0
+ },
+ letterSpacing: {
+ configurable: !0
+ },
+ textHeight: {
+ configurable: !0
+ }
+ };
+ return ((BitmapText.prototype = Object.create(n && n.prototype)).constructor = BitmapText).prototype.updateText = function() {
+ for (var t = BitmapText.fonts[this._font.name], e = this._font.size / t.size, r = new q, n = [], i = [], o = this._text.replace(/(?:\r\n|\r)/g, "\n") || " ", a = o.length, s = this._maxWidth * t.size / this._font.size, u = null, h = 0, c = 0, l = 0, f = -1, d = 0, p = 0, m = 0, v = 0; v < a; v++) {
+ var g = o.charCodeAt(v),
+ y = o.charAt(v);
+ if (/(?:\s)/.test(y) && (f = v, d = h), "\r" !== y && "\n" !== y) {
+ var _ = t.chars[g];
+ _ && (u && _.kerning[u] && (r.x += _.kerning[u]), n.push({
+ texture: _.texture,
+ line: l,
+ charCode: g,
+ position: new q(r.x + _.xOffset + this._letterSpacing / 2, r.y + _.yOffset)
+ }), r.x += _.xAdvance + this._letterSpacing, h = r.x, m = Math.max(m, _.yOffset + _.texture.height), u = g, -1 !== f && 0 < s && r.x > s && (removeItems(n, 1 + f - ++p, 1 + v - f), v = f, f = -1, i.push(d), c = Math.max(c, d), l++, r.x = 0, r.y += t.lineHeight, u = null))
+ } else i.push(h), c = Math.max(c, h), ++l, ++p, r.x = 0, r.y += t.lineHeight, u = null
+ }
+ var b = o.charAt(o.length - 1);
+ "\r" !== b && "\n" !== b && (/(?:\s)/.test(b) && (h = d), i.push(h), c = Math.max(c, h));
+ for (var x = [], w = 0; w <= l; w++) {
+ var T = 0;
+ "right" === this._font.align ? T = c - i[w] : "center" === this._font.align && (T = (c - i[w]) / 2), x.push(T)
+ }
+ for (var S = n.length, M = this.tint, E = 0; E < S; E++) {
+ var A = this._glyphs[E];
+ A ? A.texture = n[E].texture : ((A = new Xr(n[E].texture)).roundPixels = this.roundPixels, this._glyphs.push(A)), A.position.x = (n[E].position.x + x[n[E].line]) * e, A.position.y = n[E].position.y * e, A.scale.x = A.scale.y = e, A.tint = M, A.parent || this.addChild(A)
+ }
+ for (var P = S; P < this._glyphs.length; ++P) this.removeChild(this._glyphs[P]);
+ if (this._textWidth = c * e, this._textHeight = (r.y + t.lineHeight) * e, 0 !== this.anchor.x || 0 !== this.anchor.y)
+ for (var I = 0; I < S; I++) this._glyphs[I].x -= this._textWidth * this.anchor.x, this._glyphs[I].y -= this._textHeight * this.anchor.y;
+ this._maxLineHeight = m * e
+ }, BitmapText.prototype.updateTransform = function() {
+ this.validate(), this.containerUpdateTransform()
+ }, BitmapText.prototype.getLocalBounds = function() {
+ return this.validate(), n.prototype.getLocalBounds.call(this)
+ }, BitmapText.prototype.validate = function() {
+ this.dirty && (this.updateText(), this.dirty = !1)
+ }, t.tint.get = function() {
+ return this._font.tint
+ }, t.tint.set = function(t) {
+ this._font.tint = "number" == typeof t && 0 <= t ? t : 16777215, this.dirty = !0
+ }, t.align.get = function() {
+ return this._font.align
+ }, t.align.set = function(t) {
+ this._font.align = t || "left", this.dirty = !0
+ }, t.anchor.get = function() {
+ return this._anchor
+ }, t.anchor.set = function(t) {
+ "number" == typeof t ? this._anchor.set(t) : this._anchor.copyFrom(t)
+ }, t.font.get = function() {
+ return this._font
+ }, t.font.set = function(t) {
+ t && (this._font.size = "string" == typeof t ? (t = t.split(" "), this._font.name = 1 === t.length ? t[0] : t.slice(1).join(" "), 2 <= t.length ? parseInt(t[0], 10) : BitmapText.fonts[this._font.name].size) : (this._font.name = t.name, "number" == typeof t.size ? t.size : parseInt(t.size, 10)), this.dirty = !0)
+ }, t.text.get = function() {
+ return this._text
+ }, t.text.set = function(t) {
+ t = String(null == t ? "" : t), this._text !== t && (this._text = t, this.dirty = !0)
+ }, t.maxWidth.get = function() {
+ return this._maxWidth
+ }, t.maxWidth.set = function(t) {
+ this._maxWidth !== t && (this._maxWidth = t, this.dirty = !0)
+ }, t.maxLineHeight.get = function() {
+ return this.validate(), this._maxLineHeight
+ }, t.textWidth.get = function() {
+ return this.validate(), this._textWidth
+ }, t.letterSpacing.get = function() {
+ return this._letterSpacing
+ }, t.letterSpacing.set = function(t) {
+ this._letterSpacing !== t && (this._letterSpacing = t, this.dirty = !0)
+ }, t.textHeight.get = function() {
+ return this.validate(), this._textHeight
+ }, BitmapText.registerFont = function(t, e) {
+ var r = {},
+ n = t.getElementsByTagName("info")[0],
+ i = t.getElementsByTagName("common")[0],
+ o = t.getElementsByTagName("page"),
+ a = getResolutionOfUrl(o[0].getAttribute("file"), M.RESOLUTION),
+ s = {};
+ r.font = n.getAttribute("face"), r.size = parseInt(n.getAttribute("size"), 10), r.lineHeight = parseInt(i.getAttribute("lineHeight"), 10) / a, r.chars = {}, e instanceof Ht && (e = [e]);
+ for (var u = 0; u < o.length; u++) {
+ var h = o[u].getAttribute("id"),
+ c = o[u].getAttribute("file");
+ s[h] = e instanceof Array ? e[u] : e[c]
+ }
+ for (var l = t.getElementsByTagName("char"), f = 0; f < l.length; f++) {
+ var d = l[f],
+ p = parseInt(d.getAttribute("id"), 10),
+ m = d.getAttribute("page") || 0,
+ v = new ot(parseInt(d.getAttribute("x"), 10) / a + s[m].frame.x / a, parseInt(d.getAttribute("y"), 10) / a + s[m].frame.y / a, parseInt(d.getAttribute("width"), 10) / a, parseInt(d.getAttribute("height"), 10) / a);
+ r.chars[p] = {
+ xOffset: parseInt(d.getAttribute("xoffset"), 10) / a,
+ yOffset: parseInt(d.getAttribute("yoffset"), 10) / a,
+ xAdvance: parseInt(d.getAttribute("xadvance"), 10) / a,
+ kerning: {},
+ texture: new Ht(s[m].baseTexture, v),
+ page: m
+ }
+ }
+ for (var g = t.getElementsByTagName("kerning"), y = 0; y < g.length; y++) {
+ var _ = g[y],
+ b = parseInt(_.getAttribute("first"), 10) / a,
+ x = parseInt(_.getAttribute("second"), 10) / a,
+ w = parseInt(_.getAttribute("amount"), 10) / a;
+ r.chars[x] && (r.chars[x].kerning[b] = w)
+ }
+ return BitmapText.fonts[r.font] = r
+ }, Object.defineProperties(BitmapText.prototype, t), BitmapText
+ }(pt);
+ In.fonts = {};
+ var On = function() {};
+ On.parse = function(t, e) {
+ t.bitmapFont = In.registerFont(t.data, e)
+ }, On.add = function() {
+ gn.setExtensionXhrType("fnt", gn.XHR_RESPONSE_TYPE.DOCUMENT)
+ }, On.dirname = function(t) {
+ var e = t.replace(/\/$/, "").replace(/\/[^\/]*$/, "");
+ return e === t ? "." : "" === e ? "/" : e
+ }, On.use = function(e, r) {
+ if (e.data && e.type === gn.TYPE.XML)
+ if (0 !== e.data.getElementsByTagName("page").length && 0 !== e.data.getElementsByTagName("info").length && null !== e.data.getElementsByTagName("info")[0].getAttribute("face")) {
+ var t = e.isDataUrl ? "" : On.dirname(e.url);
+ e.isDataUrl && ("." === t && (t = ""), this.baseUrl && t && "/" === this.baseUrl.charAt(this.baseUrl.length - 1) && (t += "/")), (t = t.replace(this.baseUrl, "")) && "/" !== t.charAt(t.length - 1) && (t += "/");
+ for (var n = e.data.getElementsByTagName("page"), i = {}, o = function(t) {
+ i[t.metadata.pageFile] = t.texture, Object.keys(i).length === n.length && (On.parse(e, i), r())
+ }, a = 0; a < n.length; ++a) {
+ var s = n[a].getAttribute("file"),
+ u = t + s,
+ h = !1;
+ for (var c in this.resources) {
+ var l = this.resources[c];
+ if (l.url === u) {
+ l.metadata.pageFile = s, l.texture ? o(l) : l.onAfterMiddleware.add(o), h = !0;
+ break
+ }
+ }
+ if (!h) {
+ var f = {
+ crossOrigin: e.crossOrigin,
+ loadType: gn.LOAD_TYPE.IMAGE,
+ metadata: Object.assign({
+ pageFile: s
+ }, e.metadata.imageMetadata),
+ parentResource: e
+ };
+ this.add(u, f, o)
+ }
+ }
+ } else r();
+ else r()
+ };
+ var Cn = function(e) {
+ function AlphaFilter(t) {
+ void 0 === t && (t = 1), e.call(this, tr, "varying vec2 vTextureCoord;\n\nuniform sampler2D uSampler;\nuniform float uAlpha;\n\nvoid main(void)\n{\n gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;\n}\n", {
+ uAlpha: 1
+ }), this.alpha = t
+ }
+ e && (AlphaFilter.__proto__ = e), (AlphaFilter.prototype = Object.create(e && e.prototype)).constructor = AlphaFilter;
+ var t = {
+ alpha: {
+ configurable: !0
+ }
+ };
+ return t.alpha.get = function() {
+ return this.uniforms.uAlpha
+ }, t.alpha.set = function(t) {
+ this.uniforms.uAlpha = t
+ }, Object.defineProperties(AlphaFilter.prototype, t), AlphaFilter
+ }(De),
+ Rn = "\n attribute vec2 aVertexPosition;\n\n uniform mat3 projectionMatrix;\n\n uniform float strength;\n\n varying vec2 vBlurTexCoords[%size%];\n\n uniform vec4 inputSize;\n uniform vec4 outputFrame;\n \n vec4 filterVertexPosition( void )\n {\n vec2 position = aVertexPosition * max(outputFrame.zw, vec2(0.)) + outputFrame.xy;\n \n return vec4((projectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0);\n }\n \n vec2 filterTextureCoord( void )\n {\n return aVertexPosition * (outputFrame.zw * inputSize.zw);\n }\n\n void main(void)\n {\n gl_Position = filterVertexPosition();\n\n vec2 textureCoord = filterTextureCoord();\n %blur%\n }";
+ var Dn = {
+ 5: [.153388, .221461, .250301],
+ 7: [.071303, .131514, .189879, .214607],
+ 9: [.028532, .067234, .124009, .179044, .20236],
+ 11: [.0093, .028002, .065984, .121703, .175713, .198596],
+ 13: [.002406, .009255, .027867, .065666, .121117, .174868, .197641],
+ 15: [489e-6, .002403, .009246, .02784, .065602, .120999, .174697, .197448]
+ },
+ Fn = ["varying vec2 vBlurTexCoords[%size%];", "uniform sampler2D uSampler;", "void main(void)", "{", " gl_FragColor = vec4(0.0);", " %blur%", "}"].join("\n");
+ var kn = function(s) {
+ function BlurFilterPass(t, e, r, n, i) {
+ var o = function(t, e) {
+ var r, n = Math.ceil(t / 2),
+ i = Rn,
+ o = "";
+ r = e ? "vBlurTexCoords[%index%] = textureCoord + vec2(%sampleIndex% * strength, 0.0);" : "vBlurTexCoords[%index%] = textureCoord + vec2(0.0, %sampleIndex% * strength);";
+ for (var a = 0; a < t; a++) {
+ var s = r.replace("%index%", a);
+ o += s = s.replace("%sampleIndex%", a - (n - 1) + ".0"), o += "\n"
+ }
+ return i = (i = i.replace("%blur%", o)).replace("%size%", t)
+ }(i = i || 5, t),
+ a = function(t) {
+ for (var e, r = Dn[t], n = r.length, i = Fn, o = "", a = 0; a < t; a++) {
+ var s = "gl_FragColor += texture2D(uSampler, vBlurTexCoords[%index%]) * %value%;".replace("%index%", a);
+ n <= (e = a) && (e = t - a - 1), o += s = s.replace("%value%", r[e]), o += "\n"
+ }
+ return i = (i = i.replace("%blur%", o)).replace("%size%", t)
+ }(i);
+ s.call(this, o, a), this.horizontal = t, this.resolution = n || M.RESOLUTION, this._quality = 0, this.quality = r || 4, this.blur = e || 8
+ }
+ s && (BlurFilterPass.__proto__ = s);
+ var t = {
+ blur: {
+ configurable: !0
+ },
+ quality: {
+ configurable: !0
+ }
+ };
+ return ((BlurFilterPass.prototype = Object.create(s && s.prototype)).constructor = BlurFilterPass).prototype.apply = function(t, e, r, n) {
+ if (r ? this.horizontal ? this.uniforms.strength = 1 / r.width * (r.width / e.width) : this.uniforms.strength = 1 / r.height * (r.height / e.height) : this.horizontal ? this.uniforms.strength = 1 / t.renderer.width * (t.renderer.width / e.width) : this.uniforms.strength = 1 / t.renderer.height * (t.renderer.height / e.height), this.uniforms.strength *= this.strength, this.uniforms.strength /= this.passes, 1 === this.passes) t.applyFilter(this, e, r, n);
+ else {
+ var i = t.getFilterTexture(),
+ o = t.renderer,
+ a = e,
+ s = i;
+ this.state.blend = !1, t.applyFilter(this, a, s, !1);
+ for (var u = 1; u < this.passes - 1; u++) {
+ o.renderTexture.bind(a, a.filterFrame);
+ var h = this.uniforms.uSampler = s;
+ s = a, a = h, o.shader.bind(this), o.geometry.draw(5)
+ }
+ this.state.blend = !0, t.applyFilter(this, s, r, n), t.returnFilterTexture(i)
+ }
+ }, t.blur.get = function() {
+ return this.strength
+ }, t.blur.set = function(t) {
+ this.padding = 1 + 2 * Math.abs(t), this.strength = t
+ }, t.quality.get = function() {
+ return this._quality
+ }, t.quality.set = function(t) {
+ this._quality = t, this.passes = t
+ }, Object.defineProperties(BlurFilterPass.prototype, t), BlurFilterPass
+ }(De),
+ Ln = function(i) {
+ function BlurFilter(t, e, r, n) {
+ i.call(this), this.blurXFilter = new kn(!0, t, e, r, n), this.blurYFilter = new kn(!1, t, e, r, n), this.resolution = r || M.RESOLUTION, this.quality = e || 4, this.blur = t || 8, this.repeatEdgePixels = !1
+ }
+ i && (BlurFilter.__proto__ = i);
+ var t = {
+ blur: {
+ configurable: !0
+ },
+ quality: {
+ configurable: !0
+ },
+ blurX: {
+ configurable: !0
+ },
+ blurY: {
+ configurable: !0
+ },
+ blendMode: {
+ configurable: !0
+ },
+ repeatEdgePixels: {
+ configurable: !0
+ }
+ };
+ return ((BlurFilter.prototype = Object.create(i && i.prototype)).constructor = BlurFilter).prototype.apply = function(t, e, r, n) {
+ var i = Math.abs(this.blurXFilter.strength),
+ o = Math.abs(this.blurYFilter.strength);
+ if (i && o) {
+ var a = t.getFilterTexture();
+ this.blurXFilter.apply(t, e, a, !0), this.blurYFilter.apply(t, a, r, n), t.returnFilterTexture(a)
+ } else o ? this.blurYFilter.apply(t, e, r, n) : this.blurXFilter.apply(t, e, r, n)
+ }, BlurFilter.prototype.updatePadding = function() {
+ this._repeatEdgePixels ? this.padding = 0 : this.padding = 2 * Math.max(Math.abs(this.blurXFilter.strength), Math.abs(this.blurYFilter.strength))
+ }, t.blur.get = function() {
+ return this.blurXFilter.blur
+ }, t.blur.set = function(t) {
+ this.blurXFilter.blur = this.blurYFilter.blur = t, this.updatePadding()
+ }, t.quality.get = function() {
+ return this.blurXFilter.quality
+ }, t.quality.set = function(t) {
+ this.blurXFilter.quality = this.blurYFilter.quality = t
+ }, t.blurX.get = function() {
+ return this.blurXFilter.blur
+ }, t.blurX.set = function(t) {
+ this.blurXFilter.blur = t, this.updatePadding()
+ }, t.blurY.get = function() {
+ return this.blurYFilter.blur
+ }, t.blurY.set = function(t) {
+ this.blurYFilter.blur = t, this.updatePadding()
+ }, t.blendMode.get = function() {
+ return this.blurYFilter.blendMode
+ }, t.blendMode.set = function(t) {
+ this.blurYFilter.blendMode = t
+ }, t.repeatEdgePixels.get = function() {
+ return this._repeatEdgePixels
+ }, t.repeatEdgePixels.set = function(t) {
+ this._repeatEdgePixels = t, this.updatePadding()
+ }, Object.defineProperties(BlurFilter.prototype, t), BlurFilter
+ }(De),
+ Nn = function(e) {
+ function ColorMatrixFilter() {
+ var t = {
+ m: new Float32Array([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0]),
+ uAlpha: 1
+ };
+ e.call(this, er, "varying vec2 vTextureCoord;\nuniform sampler2D uSampler;\nuniform float m[20];\nuniform float uAlpha;\n\nvoid main(void)\n{\n vec4 c = texture2D(uSampler, vTextureCoord);\n\n if (uAlpha == 0.0) {\n gl_FragColor = c;\n return;\n }\n\n // Un-premultiply alpha before applying the color matrix. See issue #3539.\n if (c.a > 0.0) {\n c.rgb /= c.a;\n }\n\n vec4 result;\n\n result.r = (m[0] * c.r);\n result.r += (m[1] * c.g);\n result.r += (m[2] * c.b);\n result.r += (m[3] * c.a);\n result.r += m[4];\n\n result.g = (m[5] * c.r);\n result.g += (m[6] * c.g);\n result.g += (m[7] * c.b);\n result.g += (m[8] * c.a);\n result.g += m[9];\n\n result.b = (m[10] * c.r);\n result.b += (m[11] * c.g);\n result.b += (m[12] * c.b);\n result.b += (m[13] * c.a);\n result.b += m[14];\n\n result.a = (m[15] * c.r);\n result.a += (m[16] * c.g);\n result.a += (m[17] * c.b);\n result.a += (m[18] * c.a);\n result.a += m[19];\n\n vec3 rgb = mix(c.rgb, result.rgb, uAlpha);\n\n // Premultiply alpha again.\n rgb *= result.a;\n\n gl_FragColor = vec4(rgb, result.a);\n}\n", t), this.alpha = 1
+ }
+ e && (ColorMatrixFilter.__proto__ = e);
+ var t = {
+ matrix: {
+ configurable: !0
+ },
+ alpha: {
+ configurable: !0
+ }
+ };
+ return ((ColorMatrixFilter.prototype = Object.create(e && e.prototype)).constructor = ColorMatrixFilter).prototype._loadMatrix = function(t, e) {
+ void 0 === e && (e = !1);
+ var r = t;
+ e && (this._multiply(r, this.uniforms.m, t), r = this._colorMatrix(r)), this.uniforms.m = r
+ }, ColorMatrixFilter.prototype._multiply = function(t, e, r) {
+ return t[0] = e[0] * r[0] + e[1] * r[5] + e[2] * r[10] + e[3] * r[15], t[1] = e[0] * r[1] + e[1] * r[6] + e[2] * r[11] + e[3] * r[16], t[2] = e[0] * r[2] + e[1] * r[7] + e[2] * r[12] + e[3] * r[17], t[3] = e[0] * r[3] + e[1] * r[8] + e[2] * r[13] + e[3] * r[18], t[4] = e[0] * r[4] + e[1] * r[9] + e[2] * r[14] + e[3] * r[19] + e[4], t[5] = e[5] * r[0] + e[6] * r[5] + e[7] * r[10] + e[8] * r[15], t[6] = e[5] * r[1] + e[6] * r[6] + e[7] * r[11] + e[8] * r[16], t[7] = e[5] * r[2] + e[6] * r[7] + e[7] * r[12] + e[8] * r[17], t[8] = e[5] * r[3] + e[6] * r[8] + e[7] * r[13] + e[8] * r[18], t[9] = e[5] * r[4] + e[6] * r[9] + e[7] * r[14] + e[8] * r[19] + e[9], t[10] = e[10] * r[0] + e[11] * r[5] + e[12] * r[10] + e[13] * r[15], t[11] = e[10] * r[1] + e[11] * r[6] + e[12] * r[11] + e[13] * r[16], t[12] = e[10] * r[2] + e[11] * r[7] + e[12] * r[12] + e[13] * r[17], t[13] = e[10] * r[3] + e[11] * r[8] + e[12] * r[13] + e[13] * r[18], t[14] = e[10] * r[4] + e[11] * r[9] + e[12] * r[14] + e[13] * r[19] + e[14], t[15] = e[15] * r[0] + e[16] * r[5] + e[17] * r[10] + e[18] * r[15], t[16] = e[15] * r[1] + e[16] * r[6] + e[17] * r[11] + e[18] * r[16], t[17] = e[15] * r[2] + e[16] * r[7] + e[17] * r[12] + e[18] * r[17], t[18] = e[15] * r[3] + e[16] * r[8] + e[17] * r[13] + e[18] * r[18], t[19] = e[15] * r[4] + e[16] * r[9] + e[17] * r[14] + e[18] * r[19] + e[19], t
+ }, ColorMatrixFilter.prototype._colorMatrix = function(t) {
+ var e = new Float32Array(t);
+ return e[4] /= 255, e[9] /= 255, e[14] /= 255, e[19] /= 255, e
+ }, ColorMatrixFilter.prototype.brightness = function(t, e) {
+ var r = [t, 0, 0, 0, 0, 0, t, 0, 0, 0, 0, 0, t, 0, 0, 0, 0, 0, 1, 0];
+ this._loadMatrix(r, e)
+ }, ColorMatrixFilter.prototype.greyscale = function(t, e) {
+ var r = [t, t, t, 0, 0, t, t, t, 0, 0, t, t, t, 0, 0, 0, 0, 0, 1, 0];
+ this._loadMatrix(r, e)
+ }, ColorMatrixFilter.prototype.blackAndWhite = function(t) {
+ this._loadMatrix([.3, .6, .1, 0, 0, .3, .6, .1, 0, 0, .3, .6, .1, 0, 0, 0, 0, 0, 1, 0], t)
+ }, ColorMatrixFilter.prototype.hue = function(t, e) {
+ t = (t || 0) / 180 * Math.PI;
+ var r = Math.cos(t),
+ n = Math.sin(t),
+ i = (0, Math.sqrt)(1 / 3),
+ o = [r + 1 / 3 * (1 - r), 1 / 3 * (1 - r) - i * n, 1 / 3 * (1 - r) + i * n, 0, 0, 1 / 3 * (1 - r) + i * n, r + 1 / 3 * (1 - r), 1 / 3 * (1 - r) - i * n, 0, 0, 1 / 3 * (1 - r) - i * n, 1 / 3 * (1 - r) + i * n, r + 1 / 3 * (1 - r), 0, 0, 0, 0, 0, 1, 0];
+ this._loadMatrix(o, e)
+ }, ColorMatrixFilter.prototype.contrast = function(t, e) {
+ var r = (t || 0) + 1,
+ n = -.5 * (r - 1),
+ i = [r, 0, 0, 0, n, 0, r, 0, 0, n, 0, 0, r, 0, n, 0, 0, 0, 1, 0];
+ this._loadMatrix(i, e)
+ }, ColorMatrixFilter.prototype.saturate = function(t, e) {
+ void 0 === t && (t = 0);
+ var r = 2 * t / 3 + 1,
+ n = -.5 * (r - 1),
+ i = [r, n, n, 0, 0, n, r, n, 0, 0, n, n, r, 0, 0, 0, 0, 0, 1, 0];
+ this._loadMatrix(i, e)
+ }, ColorMatrixFilter.prototype.desaturate = function() {
+ this.saturate(-1)
+ }, ColorMatrixFilter.prototype.negative = function(t) {
+ this._loadMatrix([-1, 0, 0, 1, 0, 0, -1, 0, 1, 0, 0, 0, -1, 1, 0, 0, 0, 0, 1, 0], t)
+ }, ColorMatrixFilter.prototype.sepia = function(t) {
+ this._loadMatrix([.393, .7689999, .18899999, 0, 0, .349, .6859999, .16799999, 0, 0, .272, .5339999, .13099999, 0, 0, 0, 0, 0, 1, 0], t)
+ }, ColorMatrixFilter.prototype.technicolor = function(t) {
+ this._loadMatrix([1.9125277891456083, -.8545344976951645, -.09155508482755585, 0, 11.793603434377337, -.3087833385928097, 1.7658908555458428, -.10601743074722245, 0, -70.35205161461398, -.231103377548616, -.7501899197440212, 1.847597816108189, 0, 30.950940869491138, 0, 0, 0, 1, 0], t)
+ }, ColorMatrixFilter.prototype.polaroid = function(t) {
+ this._loadMatrix([1.438, -.062, -.062, 0, 0, -.122, 1.378, -.122, 0, 0, -.016, -.016, 1.483, 0, 0, 0, 0, 0, 1, 0], t)
+ }, ColorMatrixFilter.prototype.toBGR = function(t) {
+ this._loadMatrix([0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], t)
+ }, ColorMatrixFilter.prototype.kodachrome = function(t) {
+ this._loadMatrix([1.1285582396593525, -.3967382283601348, -.03992559172921793, 0, 63.72958762196502, -.16404339962244616, 1.0835251566291304, -.05498805115633132, 0, 24.732407896706203, -.16786010706155763, -.5603416277695248, 1.6014850761964943, 0, 35.62982807460946, 0, 0, 0, 1, 0], t)
+ }, ColorMatrixFilter.prototype.browni = function(t) {
+ this._loadMatrix([.5997023498159715, .34553243048391263, -.2708298674538042, 0, 47.43192855600873, -.037703249837783157, .8609577587992641, .15059552388459913, 0, -36.96841498319127, .24113635128153335, -.07441037908422492, .44972182064877153, 0, -7.562075277591283, 0, 0, 0, 1, 0], t)
+ }, ColorMatrixFilter.prototype.vintage = function(t) {
+ this._loadMatrix([.6279345635605994, .3202183420819367, -.03965408211312453, 0, 9.651285835294123, .02578397704808868, .6441188644374771, .03259127616149294, 0, 7.462829176470591, .0466055556782719, -.0851232987247891, .5241648018700465, 0, 5.159190588235296, 0, 0, 0, 1, 0], t)
+ }, ColorMatrixFilter.prototype.colorTone = function(t, e, r, n, i) {
+ var o = ((r = r || 16770432) >> 16 & 255) / 255,
+ a = (r >> 8 & 255) / 255,
+ s = (255 & r) / 255,
+ u = ((n = n || 3375104) >> 16 & 255) / 255,
+ h = (n >> 8 & 255) / 255,
+ c = (255 & n) / 255,
+ l = [.3, .59, .11, 0, 0, o, a, s, t = t || .2, 0, u, h, c, e = e || .15, 0, o - u, a - h, s - c, 0, 0];
+ this._loadMatrix(l, i)
+ }, ColorMatrixFilter.prototype.night = function(t, e) {
+ var r = [-2 * (t = t || .1), -t, 0, 0, 0, -t, 0, t, 0, 0, 0, t, 2 * t, 0, 0, 0, 0, 0, 1, 0];
+ this._loadMatrix(r, e)
+ }, ColorMatrixFilter.prototype.predator = function(t, e) {
+ var r = [11.224130630493164 * t, -4.794486999511719 * t, -2.8746118545532227 * t, 0 * t, .40342438220977783 * t, -3.6330697536468506 * t, 9.193157196044922 * t, -2.951810836791992 * t, 0 * t, -1.316135048866272 * t, -3.2184197902679443 * t, -4.2375030517578125 * t, 7.476448059082031 * t, 0 * t, .8044459223747253 * t, 0, 0, 0, 1, 0];
+ this._loadMatrix(r, e)
+ }, ColorMatrixFilter.prototype.lsd = function(t) {
+ this._loadMatrix([2, -.4, .5, 0, 0, -.5, 2, -.4, 0, 0, -.4, -.5, 3, 0, 0, 0, 0, 0, 1, 0], t)
+ }, ColorMatrixFilter.prototype.reset = function() {
+ this._loadMatrix([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0], !1)
+ }, t.matrix.get = function() {
+ return this.uniforms.m
+ }, t.matrix.set = function(t) {
+ this.uniforms.m = t
+ }, t.alpha.get = function() {
+ return this.uniforms.uAlpha
+ }, t.alpha.set = function(t) {
+ this.uniforms.uAlpha = t
+ }, Object.defineProperties(ColorMatrixFilter.prototype, t), ColorMatrixFilter
+ }(De);
+ Nn.prototype.grayscale = Nn.prototype.greyscale;
+ var Bn = function(n) {
+ function DisplacementFilter(t, e) {
+ var r = new Y;
+ t.renderable = !1, n.call(this, "attribute vec2 aVertexPosition;\n\nuniform mat3 projectionMatrix;\nuniform mat3 filterMatrix;\n\nvarying vec2 vTextureCoord;\nvarying vec2 vFilterCoord;\n\nuniform vec4 inputSize;\nuniform vec4 outputFrame;\n\nvec4 filterVertexPosition( void )\n{\n vec2 position = aVertexPosition * max(outputFrame.zw, vec2(0.)) + outputFrame.xy;\n\n return vec4((projectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0);\n}\n\nvec2 filterTextureCoord( void )\n{\n return aVertexPosition * (outputFrame.zw * inputSize.zw);\n}\n\nvoid main(void)\n{\n\tgl_Position = filterVertexPosition();\n\tvTextureCoord = filterTextureCoord();\n\tvFilterCoord = ( filterMatrix * vec3( vTextureCoord, 1.0) ).xy;\n}\n", "varying vec2 vFilterCoord;\nvarying vec2 vTextureCoord;\n\nuniform vec2 scale;\nuniform mat2 rotation;\nuniform sampler2D uSampler;\nuniform sampler2D mapSampler;\n\nuniform highp vec4 inputSize;\nuniform vec4 inputClamp;\n\nvoid main(void)\n{\n vec4 map = texture2D(mapSampler, vFilterCoord);\n\n map -= 0.5;\n map.xy = scale * inputSize.zw * (rotation * map.xy);\n\n gl_FragColor = texture2D(uSampler, clamp(vec2(vTextureCoord.x + map.x, vTextureCoord.y + map.y), inputClamp.xy, inputClamp.zw));\n}\n", {
+ mapSampler: t._texture,
+ filterMatrix: r,
+ scale: {
+ x: 1,
+ y: 1
+ },
+ rotation: new Float32Array([1, 0, 0, 1])
+ }), this.maskSprite = t, this.maskMatrix = r, null == e && (e = 20), this.scale = new q(e, e)
+ }
+ n && (DisplacementFilter.__proto__ = n);
+ var t = {
+ map: {
+ configurable: !0
+ }
+ };
+ return ((DisplacementFilter.prototype = Object.create(n && n.prototype)).constructor = DisplacementFilter).prototype.apply = function(t, e, r) {
+ this.uniforms.filterMatrix = t.calculateSpriteMatrix(this.maskMatrix, this.maskSprite), this.uniforms.scale.x = this.scale.x, this.uniforms.scale.y = this.scale.y;
+ var n = this.maskSprite.transform.worldTransform,
+ i = Math.sqrt(n.a * n.a + n.b * n.b),
+ o = Math.sqrt(n.c * n.c + n.d * n.d);
+ 0 !== i && 0 !== o && (this.uniforms.rotation[0] = n.a / i, this.uniforms.rotation[1] = n.b / i, this.uniforms.rotation[2] = n.c / o, this.uniforms.rotation[3] = n.d / o), t.applyFilter(this, e, r)
+ }, t.map.get = function() {
+ return this.uniforms.mapSampler
+ }, t.map.set = function(t) {
+ this.uniforms.mapSampler = t
+ }, Object.defineProperties(DisplacementFilter.prototype, t), DisplacementFilter
+ }(De),
+ Un = function(t) {
+ function FXAAFilter() {
+ t.call(this, "\nattribute vec2 aVertexPosition;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 v_rgbNW;\nvarying vec2 v_rgbNE;\nvarying vec2 v_rgbSW;\nvarying vec2 v_rgbSE;\nvarying vec2 v_rgbM;\n\nvarying vec2 vFragCoord;\n\nuniform vec4 inputPixel;\nuniform vec4 outputFrame;\n\nvec4 filterVertexPosition( void )\n{\n vec2 position = aVertexPosition * max(outputFrame.zw, vec2(0.)) + outputFrame.xy;\n\n return vec4((projectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0);\n}\n\nvoid texcoords(vec2 fragCoord, vec2 inverseVP,\n out vec2 v_rgbNW, out vec2 v_rgbNE,\n out vec2 v_rgbSW, out vec2 v_rgbSE,\n out vec2 v_rgbM) {\n v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP;\n v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP;\n v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP;\n v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP;\n v_rgbM = vec2(fragCoord * inverseVP);\n}\n\nvoid main(void) {\n\n gl_Position = filterVertexPosition();\n\n vFragCoord = aVertexPosition * outputFrame.zw;\n\n texcoords(vFragCoord, inputPixel.zw, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);\n}\n", 'varying vec2 v_rgbNW;\nvarying vec2 v_rgbNE;\nvarying vec2 v_rgbSW;\nvarying vec2 v_rgbSE;\nvarying vec2 v_rgbM;\n\nvarying vec2 vFragCoord;\nuniform sampler2D uSampler;\nuniform highp vec4 inputPixel;\n\n\n/**\n Basic FXAA implementation based on the code on geeks3d.com with the\n modification that the texture2DLod stuff was removed since it\'s\n unsupported by WebGL.\n\n --\n\n From:\n https://github.com/mitsuhiko/webgl-meincraft\n\n Copyright (c) 2011 by Armin Ronacher.\n\n Some rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n * Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n\n * Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the following\n disclaimer in the documentation and/or other materials provided\n with the distribution.\n\n * The names of the contributors may not be used to endorse or\n promote products derived from this software without specific\n prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef FXAA_REDUCE_MIN\n#define FXAA_REDUCE_MIN (1.0/ 128.0)\n#endif\n#ifndef FXAA_REDUCE_MUL\n#define FXAA_REDUCE_MUL (1.0 / 8.0)\n#endif\n#ifndef FXAA_SPAN_MAX\n#define FXAA_SPAN_MAX 8.0\n#endif\n\n//optimized version for mobile, where dependent\n//texture reads can be a bottleneck\nvec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 inverseVP,\n vec2 v_rgbNW, vec2 v_rgbNE,\n vec2 v_rgbSW, vec2 v_rgbSE,\n vec2 v_rgbM) {\n vec4 color;\n vec3 rgbNW = texture2D(tex, v_rgbNW).xyz;\n vec3 rgbNE = texture2D(tex, v_rgbNE).xyz;\n vec3 rgbSW = texture2D(tex, v_rgbSW).xyz;\n vec3 rgbSE = texture2D(tex, v_rgbSE).xyz;\n vec4 texColor = texture2D(tex, v_rgbM);\n vec3 rgbM = texColor.xyz;\n vec3 luma = vec3(0.299, 0.587, 0.114);\n float lumaNW = dot(rgbNW, luma);\n float lumaNE = dot(rgbNE, luma);\n float lumaSW = dot(rgbSW, luma);\n float lumaSE = dot(rgbSE, luma);\n float lumaM = dot(rgbM, luma);\n float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));\n float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));\n\n mediump vec2 dir;\n dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n\n float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *\n (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);\n\n float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);\n dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),\n max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),\n dir * rcpDirMin)) * inverseVP;\n\n vec3 rgbA = 0.5 * (\n texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz +\n texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);\n vec3 rgbB = rgbA * 0.5 + 0.25 * (\n texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz +\n texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);\n\n float lumaB = dot(rgbB, luma);\n if ((lumaB < lumaMin) || (lumaB > lumaMax))\n color = vec4(rgbA, texColor.a);\n else\n color = vec4(rgbB, texColor.a);\n return color;\n}\n\nvoid main() {\n\n vec4 color;\n\n color = fxaa(uSampler, vFragCoord, inputPixel.zw, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);\n\n gl_FragColor = color;\n}\n')
+ }
+ return t && (FXAAFilter.__proto__ = t), (FXAAFilter.prototype = Object.create(t && t.prototype)).constructor = FXAAFilter
+ }(De),
+ Gn = function(r) {
+ function NoiseFilter(t, e) {
+ void 0 === t && (t = .5), void 0 === e && (e = Math.random()), r.call(this, er, "precision highp float;\n\nvarying vec2 vTextureCoord;\nvarying vec4 vColor;\n\nuniform float uNoise;\nuniform float uSeed;\nuniform sampler2D uSampler;\n\nfloat rand(vec2 co)\n{\n return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nvoid main()\n{\n vec4 color = texture2D(uSampler, vTextureCoord);\n float randomValue = rand(gl_FragCoord.xy * uSeed);\n float diff = (randomValue - 0.5) * uNoise;\n\n // Un-premultiply alpha before applying the color matrix. See issue #3539.\n if (color.a > 0.0) {\n color.rgb /= color.a;\n }\n\n color.r += diff;\n color.g += diff;\n color.b += diff;\n\n // Premultiply alpha again.\n color.rgb *= color.a;\n\n gl_FragColor = color;\n}\n", {
+ uNoise: 0,
+ uSeed: 0
+ }), this.noise = t, this.seed = e
+ }
+ r && (NoiseFilter.__proto__ = r), (NoiseFilter.prototype = Object.create(r && r.prototype)).constructor = NoiseFilter;
+ var t = {
+ noise: {
+ configurable: !0
+ },
+ seed: {
+ configurable: !0
+ }
+ };
+ return t.noise.get = function() {
+ return this.uniforms.uNoise
+ }, t.noise.set = function(t) {
+ this.uniforms.uNoise = t
+ }, t.seed.get = function() {
+ return this.uniforms.uSeed
+ }, t.seed.set = function(t) {
+ this.uniforms.uSeed = t
+ }, Object.defineProperties(NoiseFilter.prototype, t), NoiseFilter
+ }(De),
+ jn = new Y;
+ dt.prototype._cacheAsBitmap = !1, dt.prototype._cacheData = !1;
+ var zn = function() {
+ this.textureCacheId = null, this.originalRender = null, this.originalRenderCanvas = null, this.originalCalculateBounds = null, this.originalGetLocalBounds = null, this.originalUpdateTransform = null, this.originalHitTest = null, this.originalDestroy = null, this.originalMask = null, this.originalFilterArea = null, this.sprite = null
+ };
+ Object.defineProperties(dt.prototype, {
+ cacheAsBitmap: {
+ get: function() {
+ return this._cacheAsBitmap
+ },
+ set: function(t) {
+ var e;
+ this._cacheAsBitmap !== t && ((this._cacheAsBitmap = t) ? (this._cacheData || (this._cacheData = new zn), (e = this._cacheData).originalRender = this.render, e.originalRenderCanvas = this.renderCanvas, e.originalUpdateTransform = this.updateTransform, e.originalCalculateBounds = this.calculateBounds, e.originalGetLocalBounds = this.getLocalBounds, e.originalDestroy = this.destroy, e.originalContainsPoint = this.containsPoint, e.originalMask = this._mask, e.originalFilterArea = this.filterArea, this.render = this._renderCached, this.renderCanvas = this._renderCachedCanvas, this.destroy = this._cacheAsBitmapDestroy) : ((e = this._cacheData).sprite && this._destroyCachedDisplayObject(), this.render = e.originalRender, this.renderCanvas = e.originalRenderCanvas, this.calculateBounds = e.originalCalculateBounds, this.getLocalBounds = e.originalGetLocalBounds, this.destroy = e.originalDestroy, this.updateTransform = e.originalUpdateTransform, this.containsPoint = e.originalContainsPoint, this._mask = e.originalMask, this.filterArea = e.originalFilterArea))
+ }
+ }
+ }), dt.prototype._renderCached = function(t) {
+ !this.visible || this.worldAlpha <= 0 || !this.renderable || (this._initCachedDisplayObject(t), this._cacheData.sprite.transform._worldID = this.transform._worldID, this._cacheData.sprite.worldAlpha = this.worldAlpha, this._cacheData.sprite._render(t))
+ }, dt.prototype._initCachedDisplayObject = function(t) {
+ if (!this._cacheData || !this._cacheData.sprite) {
+ var e = this.alpha;
+ this.alpha = 1, t.batch.flush();
+ var r = this.getLocalBounds().clone();
+ if (this.filters) {
+ var n = this.filters[0].padding;
+ r.pad(n)
+ }
+ r.ceil(M.RESOLUTION);
+ var i = t._activeRenderTarget,
+ o = Wt.create(r.width, r.height),
+ a = "cacheAsBitmap_" + uid();
+ this._cacheData.textureCacheId = a, Rt.addToCache(o.baseTexture, a), Ht.addToCache(o, a);
+ var s = jn;
+ s.tx = -r.x, s.ty = -r.y, this.transform.worldTransform.identity(), this.render = this._cacheData.originalRender, t.render(this, o, !0, s, !0), t.renderTexture.bind(i), this.render = this._renderCached, this.updateTransform = this.displayObjectUpdateTransform, this.calculateBounds = this._calculateCachedBounds, this.getLocalBounds = this._getCachedLocalBounds, this._mask = null, this.filterArea = null;
+ var u = new Xr(o);
+ u.transform.worldTransform = this.transform.worldTransform, u.anchor.x = -r.x / r.width, u.anchor.y = -r.y / r.height, u.alpha = e, u._bounds = this._bounds, this._cacheData.sprite = u, this.transform._parentID = -1, this.parent ? this.updateTransform() : (this.parent = t._tempDisplayObjectParent, this.updateTransform(), this.parent = null), this.containsPoint = u.containsPoint.bind(u)
+ }
+ }, dt.prototype._renderCachedCanvas = function(t) {
+ !this.visible || this.worldAlpha <= 0 || !this.renderable || (this._initCachedDisplayObjectCanvas(t), this._cacheData.sprite.worldAlpha = this.worldAlpha, this._cacheData.sprite._renderCanvas(t))
+ }, dt.prototype._initCachedDisplayObjectCanvas = function(t) {
+ if (!this._cacheData || !this._cacheData.sprite) {
+ var e = this.getLocalBounds(),
+ r = this.alpha;
+ this.alpha = 1;
+ var n = t.context;
+ e.ceil(M.RESOLUTION);
+ var i = Wt.create(e.width, e.height),
+ o = "cacheAsBitmap_" + uid();
+ this._cacheData.textureCacheId = o, Rt.addToCache(i.baseTexture, o), Ht.addToCache(i, o);
+ var a = jn;
+ this.transform.localTransform.copyTo(a), a.invert(), a.tx -= e.x, a.ty -= e.y, this.renderCanvas = this._cacheData.originalRenderCanvas, t.render(this, i, !0, a, !1), t.context = n, this.renderCanvas = this._renderCachedCanvas, this.updateTransform = this.displayObjectUpdateTransform, this.calculateBounds = this._calculateCachedBounds, this.getLocalBounds = this._getCachedLocalBounds, this._mask = null, this.filterArea = null;
+ var s = new Xr(i);
+ s.transform.worldTransform = this.transform.worldTransform, s.anchor.x = -e.x / e.width, s.anchor.y = -e.y / e.height, s.alpha = r, s._bounds = this._bounds, this._cacheData.sprite = s, this.transform._parentID = -1, this.parent ? this.updateTransform() : (this.parent = t._tempDisplayObjectParent, this.updateTransform(), this.parent = null), this.containsPoint = s.containsPoint.bind(s)
+ }
+ }, dt.prototype._calculateCachedBounds = function() {
+ this._bounds.clear(), this._cacheData.sprite.transform._worldID = this.transform._worldID, this._cacheData.sprite._calculateBounds(), this._lastBoundsID = this._boundsID
+ }, dt.prototype._getCachedLocalBounds = function() {
+ return this._cacheData.sprite.getLocalBounds()
+ }, dt.prototype._destroyCachedDisplayObject = function() {
+ this._cacheData.sprite._texture.destroy(!0), this._cacheData.sprite = null, Rt.removeFromCache(this._cacheData.textureCacheId), Ht.removeFromCache(this._cacheData.textureCacheId), this._cacheData.textureCacheId = null
+ }, dt.prototype._cacheAsBitmapDestroy = function(t) {
+ this.cacheAsBitmap = !1, this.destroy(t)
+ }, dt.prototype.name = null, pt.prototype.getChildByName = function(t) {
+ for (var e = 0; e < this.children.length; e++)
+ if (this.children[e].name === t) return this.children[e];
+ return null
+ }, dt.prototype.getGlobalPosition = function(t, e) {
+ return void 0 === t && (t = new q), void 0 === e && (e = !1), this.parent ? this.parent.toGlobal(this.position, t, e) : (t.x = this.position.x, t.y = this.position.y), t
+ };
+ var Xn = function(t, e) {
+ this.uvBuffer = t, this.uvMatrix = e, this.data = null, this._bufferUpdateId = -1, this._textureUpdateId = -1, this._updateID = 0
+ };
+ Xn.prototype.update = function(t) {
+ if (t || this._bufferUpdateId !== this.uvBuffer._updateID || this._textureUpdateId !== this.uvMatrix._updateID) {
+ this._bufferUpdateId = this.uvBuffer._updateID, this._textureUpdateId = this.uvMatrix._updateID;
+ var e = this.uvBuffer.data;
+ this.data && this.data.length === e.length || (this.data = new Float32Array(e.length)), this.uvMatrix.multiplyUvs(e, this.data), this._updateID++
+ }
+ };
+ var Vn = new q,
+ qn = new ct,
+ Hn = function(i) {
+ function Mesh(t, e, r, n) {
+ void 0 === n && (n = x.TRIANGLES), i.call(this), (this.geometry = t).refCount++, this.shader = e, this.state = r || Ce.for2d(), this.drawMode = n, this.start = 0, this.size = 0, this.uvs = null, this.indices = null, this.vertexData = new Float32Array(1), this.vertexDirty = 0, this._transformID = -1, this.tint = 16777215, this.blendMode = y.NORMAL, this._roundPixels = M.ROUND_PIXELS, this.batchUvs = null
+ }
+ i && (Mesh.__proto__ = i), (Mesh.prototype = Object.create(i && i.prototype)).constructor = Mesh;
+ var t = {
+ uvBuffer: {
+ configurable: !0
+ },
+ verticesBuffer: {
+ configurable: !0
+ },
+ material: {
+ configurable: !0
+ },
+ blendMode: {
+ configurable: !0
+ },
+ roundPixels: {
+ configurable: !0
+ },
+ tint: {
+ configurable: !0
+ },
+ texture: {
+ configurable: !0
+ }
+ };
+ return t.uvBuffer.get = function() {
+ return this.geometry.buffers[1].data
+ }, t.verticesBuffer.get = function() {
+ return this.geometry.buffers[0].data
+ }, t.material.set = function(t) {
+ this.shader = t
+ }, t.material.get = function() {
+ return this.shader
+ }, t.blendMode.set = function(t) {
+ this.state.blendMode = t
+ }, t.blendMode.get = function() {
+ return this.state.blendMode
+ }, t.roundPixels.set = function(t) {
+ this._roundPixels !== t && (this._transformID = -1), this._roundPixels = t
+ }, t.roundPixels.get = function() {
+ return this._roundPixels
+ }, t.tint.get = function() {
+ return this.shader.tint
+ }, t.tint.set = function(t) {
+ this.shader.tint = t
+ }, t.texture.get = function() {
+ return this.shader.texture
+ }, t.texture.set = function(t) {
+ this.shader.texture = t
+ }, Mesh.prototype._render = function(t) {
+ var e = this.geometry.buffers[0].data;
+ this.shader.batchable && this.drawMode === x.TRIANGLES && e.length < 2 * Mesh.BATCHABLE_SIZE ? this._renderToBatch(t) : this._renderDefault(t)
+ }, Mesh.prototype._renderDefault = function(t) {
+ var e = this.shader;
+ e.alpha = this.worldAlpha, e.update && e.update(), t.batch.flush(), e.program.uniformData.translationMatrix && (e.uniforms.translationMatrix = this.transform.worldTransform.toArray(!0)), t.shader.bind(e), t.state.setState(this.state), t.geometry.bind(this.geometry, e), t.geometry.draw(this.drawMode, this.size, this.start, this.geometry.instanceCount)
+ }, Mesh.prototype._renderToBatch = function(t) {
+ var e = this.geometry;
+ this.shader.uvMatrix && (this.shader.uvMatrix.update(), this.calculateUvs()), this.calculateVertices(), this.indices = e.indexBuffer.data, this._tintRGB = this.shader._tintRGB, this._texture = this.shader.texture;
+ var r = this.material.pluginName;
+ t.batch.setObjectRenderer(t.plugins[r]), t.plugins[r].render(this)
+ }, Mesh.prototype.calculateVertices = function() {
+ var t = this.geometry,
+ e = t.buffers[0].data;
+ if (t.vertexDirtyId !== this.vertexDirty || this._transformID !== this.transform._worldID) {
+ this._transformID = this.transform._worldID, this.vertexData.length !== e.length && (this.vertexData = new Float32Array(e.length));
+ for (var r = this.transform.worldTransform, n = r.a, i = r.b, o = r.c, a = r.d, s = r.tx, u = r.ty, h = this.vertexData, c = 0; c < h.length / 2; c++) {
+ var l = e[2 * c],
+ f = e[2 * c + 1];
+ h[2 * c] = n * l + o * f + s, h[2 * c + 1] = i * l + a * f + u
+ }
+ if (this._roundPixels)
+ for (var d = 0; d < h.length; d++) h[d] = Math.round(h[d]);
+ this.vertexDirty = t.vertexDirtyId
+ }
+ }, Mesh.prototype.calculateUvs = function() {
+ var t = this.geometry.buffers[1];
+ this.shader.uvMatrix.isSimple ? this.uvs = t.data : (this.batchUvs || (this.batchUvs = new Xn(t, this.shader.uvMatrix)), this.batchUvs.update(), this.uvs = this.batchUvs.data)
+ }, Mesh.prototype._calculateBounds = function() {
+ this.calculateVertices(), this._bounds.addVertexData(this.vertexData, 0, this.vertexData.length)
+ }, Mesh.prototype.containsPoint = function(t) {
+ if (!this.getBounds().contains(t.x, t.y)) return !1;
+ this.worldTransform.applyInverse(t, Vn);
+ for (var e = this.geometry.getAttribute("aVertexPosition").data, r = qn.points, n = this.geometry.getIndex().data, i = n.length, o = 4 === this.drawMode ? 3 : 1, a = 0; a + 2 < i; a += o) {
+ var s = 2 * n[a],
+ u = 2 * n[a + 1],
+ h = 2 * n[a + 2];
+ if (r[0] = e[s], r[1] = e[s + 1], r[2] = e[u], r[3] = e[u + 1], r[4] = e[h], r[5] = e[h + 1], qn.contains(Vn.x, Vn.y)) return !0
+ }
+ return !1
+ }, Mesh.prototype.destroy = function(t) {
+ i.prototype.destroy.call(this, t), this.geometry.refCount--, 0 === this.geometry.refCount && this.geometry.dispose(), this.geometry = null, this.shader = null, this.state = null, this.uvs = null, this.indices = null, this.vertexData = null
+ }, Object.defineProperties(Mesh.prototype, t), Mesh
+ }(pt);
+ Hn.BATCHABLE_SIZE = 100;
+ var Wn = function(n) {
+ function MeshMaterial(t, e) {
+ var r = {
+ uSampler: t,
+ alpha: 1,
+ uTextureMatrix: Y.IDENTITY,
+ uColor: new Float32Array([1, 1, 1, 1])
+ };
+ (e = Object.assign({
+ tint: 16777215,
+ alpha: 1,
+ pluginName: "batch"
+ }, e)).uniforms && Object.assign(r, e.uniforms), n.call(this, e.program || Ae.from("attribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\nuniform mat3 translationMatrix;\nuniform mat3 uTextureMatrix;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n\n vTextureCoord = (uTextureMatrix * vec3(aTextureCoord, 1.0)).xy;\n}\n", "varying vec2 vTextureCoord;\nuniform vec4 uColor;\n\nuniform sampler2D uSampler;\n\nvoid main(void)\n{\n gl_FragColor = texture2D(uSampler, vTextureCoord) * uColor;\n}\n"), r), this._colorDirty = !1, this.uvMatrix = new ke(t), this.batchable = void 0 === e.program, this.pluginName = e.pluginName, this.tint = e.tint, this.alpha = e.alpha
+ }
+ n && (MeshMaterial.__proto__ = n), (MeshMaterial.prototype = Object.create(n && n.prototype)).constructor = MeshMaterial;
+ var t = {
+ texture: {
+ configurable: !0
+ },
+ alpha: {
+ configurable: !0
+ },
+ tint: {
+ configurable: !0
+ }
+ };
+ return t.texture.get = function() {
+ return this.uniforms.uSampler
+ }, t.texture.set = function(t) {
+ this.uniforms.uSampler !== t && (this.uniforms.uSampler = t, this.uvMatrix.texture = t)
+ }, t.alpha.set = function(t) {
+ t !== this._alpha && (this._alpha = t, this._colorDirty = !0)
+ }, t.alpha.get = function() {
+ return this._alpha
+ }, t.tint.set = function(t) {
+ t !== this._tint && (this._tint = t, this._tintRGB = (t >> 16) + (65280 & t) + ((255 & t) << 16), this._colorDirty = !0)
+ }, t.tint.get = function() {
+ return this._tint
+ }, MeshMaterial.prototype.update = function() {
+ if (this._colorDirty) {
+ this._colorDirty = !1;
+ var t = this.texture.baseTexture;
+ premultiplyTintToRgba(this._tint, this._alpha, this.uniforms.uColor, t.premultiplyAlpha)
+ }
+ this.uvMatrix.update() && (this.uniforms.uTextureMatrix = this.uvMatrix.mapCoord)
+ }, Object.defineProperties(MeshMaterial.prototype, t), MeshMaterial
+ }(Ie),
+ Yn = function(a) {
+ function MeshGeometry(t, e, r) {
+ a.call(this);
+ var n = new Zt(t),
+ i = new Zt(e, !0),
+ o = new Zt(r, !0, !0);
+ this.addAttribute("aVertexPosition", n, 2, !1, w.FLOAT).addAttribute("aTextureCoord", i, 2, !1, w.FLOAT).addIndex(o), this._updateId = -1
+ }
+ a && (MeshGeometry.__proto__ = a), (MeshGeometry.prototype = Object.create(a && a.prototype)).constructor = MeshGeometry;
+ var t = {
+ vertexDirtyId: {
+ configurable: !0
+ }
+ };
+ return t.vertexDirtyId.get = function() {
+ return this.buffers[0]._updateID
+ }, Object.defineProperties(MeshGeometry.prototype, t), MeshGeometry
+ }(ee),
+ Kn = function(i) {
+ function PlaneGeometry(t, e, r, n) {
+ void 0 === t && (t = 100), void 0 === e && (e = 100), void 0 === r && (r = 10), void 0 === n && (n = 10), i.call(this), this.segWidth = r, this.segHeight = n, this.width = t, this.height = e, this.build()
+ }
+ return i && (PlaneGeometry.__proto__ = i), ((PlaneGeometry.prototype = Object.create(i && i.prototype)).constructor = PlaneGeometry).prototype.build = function() {
+ for (var t = this.segWidth * this.segHeight, e = [], r = [], n = [], i = this.segWidth - 1, o = this.segHeight - 1, a = this.width / i, s = this.height / o, u = 0; u < t; u++) {
+ var h = u % this.segWidth,
+ c = u / this.segWidth | 0;
+ e.push(h * a, c * s), r.push(h / i, c / o)
+ }
+ for (var l = i * o, f = 0; f < l; f++) {
+ var d = f % i,
+ p = f / i | 0,
+ m = p * this.segWidth + d,
+ v = p * this.segWidth + d + 1,
+ g = (p + 1) * this.segWidth + d,
+ y = (p + 1) * this.segWidth + d + 1;
+ n.push(m, v, g, v, y, g)
+ }
+ this.buffers[0].data = new Float32Array(e), this.buffers[1].data = new Float32Array(r), this.indexBuffer.data = new Uint16Array(n), this.buffers[0].update(), this.buffers[1].update(), this.indexBuffer.update()
+ }, PlaneGeometry
+ }(Yn),
+ Zn = function(r) {
+ function RopeGeometry(t, e) {
+ void 0 === t && (t = 200), r.call(this, new Float32Array(4 * e.length), new Float32Array(4 * e.length), new Uint16Array(6 * (e.length - 1))), this.points = e, this.width = t, this.build()
+ }
+ return r && (RopeGeometry.__proto__ = r), ((RopeGeometry.prototype = Object.create(r && r.prototype)).constructor = RopeGeometry).prototype.build = function() {
+ var t = this.points;
+ if (t) {
+ var e = this.getAttribute("aVertexPosition"),
+ r = this.getAttribute("aTextureCoord"),
+ n = this.getIndex();
+ if (!(t.length < 1)) {
+ e.data.length / 4 !== t.length && (e.data = new Float32Array(4 * t.length), r.data = new Float32Array(4 * t.length), n.data = new Uint16Array(6 * (t.length - 1)));
+ var i = r.data,
+ o = n.data;
+ i[0] = 0, i[1] = 0, i[2] = 0, i[3] = 1;
+ for (var a = t.length, s = 0; s < a; s++) {
+ var u = 4 * s,
+ h = s / (a - 1);
+ i[u] = h, i[u + 1] = 0, i[u + 2] = h, i[u + 3] = 1
+ }
+ for (var c = 0, l = 0; l < a - 1; l++) {
+ var f = 2 * l;
+ o[c++] = f, o[c++] = f + 1, o[c++] = f + 2, o[c++] = f + 2, o[c++] = f + 1, o[c++] = f + 3
+ }
+ r.update(), n.update(), this.updateVertices()
+ }
+ }
+ }, RopeGeometry.prototype.updateVertices = function() {
+ var t = this.points;
+ if (!(t.length < 1)) {
+ for (var e, r = t[0], n = 0, i = 0, o = this.buffers[0].data, a = t.length, s = 0; s < a; s++) {
+ var u = t[s],
+ h = 4 * s;
+ i = -((e = s < t.length - 1 ? t[s + 1] : u).x - r.x), n = e.y - r.y;
+ var c = Math.sqrt(n * n + i * i),
+ l = this.width / 2;
+ n /= c, i /= c, n *= l, i *= l, o[h] = u.x + n, o[h + 1] = u.y + i, o[h + 2] = u.x - n, o[h + 3] = u.y - i, r = u
+ }
+ this.buffers[0].update()
+ }
+ }, RopeGeometry.prototype.update = function() {
+ this.updateVertices()
+ }, RopeGeometry
+ }(Yn),
+ Qn = function(i) {
+ function SimpleRope(t, e) {
+ var r = new Zn(t.height, e),
+ n = new Wn(t);
+ i.call(this, r, n), this.autoUpdate = !0
+ }
+ return i && (SimpleRope.__proto__ = i), ((SimpleRope.prototype = Object.create(i && i.prototype)).constructor = SimpleRope).prototype._render = function(t) {
+ (this.autoUpdate || this.geometry.width !== this.shader.texture.height) && (this.geometry.width = this.shader.texture.height, this.geometry.update()), i.prototype._render.call(this, t)
+ }, SimpleRope
+ }(Hn),
+ Jn = function(o) {
+ function SimplePlane(t, e, r) {
+ var n = new Kn(t.width, t.height, e, r),
+ i = new Wn(Ht.WHITE);
+ o.call(this, n, i), this.texture = t
+ }
+ o && (SimplePlane.__proto__ = o);
+ var t = {
+ texture: {
+ configurable: !0
+ }
+ };
+ return ((SimplePlane.prototype = Object.create(o && o.prototype)).constructor = SimplePlane).prototype.textureUpdated = function() {
+ this._textureID = this.shader.texture._updateID, this.geometry.width = this.shader.texture.width, this.geometry.height = this.shader.texture.height, this.geometry.build()
+ }, t.texture.set = function(t) {
+ this.shader.texture !== t && (this.shader.texture = t, this._textureID = -1, t.baseTexture.valid ? this.textureUpdated() : t.once("update", this.textureUpdated, this))
+ }, t.texture.get = function() {
+ return this.shader.texture
+ }, SimplePlane.prototype._render = function(t) {
+ this._textureID !== this.shader.texture._updateID && this.textureUpdated(), o.prototype._render.call(this, t)
+ }, Object.defineProperties(SimplePlane.prototype, t), SimplePlane
+ }(Hn),
+ $n = function(s) {
+ function SimpleMesh(t, e, r, n, i) {
+ void 0 === t && (t = Ht.EMPTY);
+ var o = new Yn(e, r, n);
+ o.getAttribute("aVertexPosition").static = !1;
+ var a = new Wn(t);
+ s.call(this, o, a, null, i), this.autoUpdate = !0
+ }
+ s && (SimpleMesh.__proto__ = s), (SimpleMesh.prototype = Object.create(s && s.prototype)).constructor = SimpleMesh;
+ var t = {
+ vertices: {
+ configurable: !0
+ }
+ };
+ return t.vertices.get = function() {
+ return this.geometry.getAttribute("aVertexPosition").data
+ }, t.vertices.set = function(t) {
+ this.geometry.getAttribute("aVertexPosition").data = t
+ }, SimpleMesh.prototype._render = function(t) {
+ this.autoUpdate && this.geometry.getAttribute("aVertexPosition").update(), s.prototype._render.call(this, t)
+ }, Object.defineProperties(SimpleMesh.prototype, t), SimpleMesh
+ }(Hn),
+ ti = function(o) {
+ function NineSlicePlane(t, e, r, n, i) {
+ o.call(this, Ht.WHITE, 4, 4), this._origWidth = t.orig.width, this._origHeight = t.orig.height, this._width = this._origWidth, this._height = this._origHeight, this._leftWidth = void 0 !== e ? e : 10, this._rightWidth = void 0 !== n ? n : 10, this._topHeight = void 0 !== r ? r : 10, this._bottomHeight = void 0 !== i ? i : 10, this.texture = t
+ }
+ o && (NineSlicePlane.__proto__ = o);
+ var t = {
+ vertices: {
+ configurable: !0
+ },
+ width: {
+ configurable: !0
+ },
+ height: {
+ configurable: !0
+ },
+ leftWidth: {
+ configurable: !0
+ },
+ rightWidth: {
+ configurable: !0
+ },
+ topHeight: {
+ configurable: !0
+ },
+ bottomHeight: {
+ configurable: !0
+ }
+ };
+ return ((NineSlicePlane.prototype = Object.create(o && o.prototype)).constructor = NineSlicePlane).prototype.textureUpdated = function() {
+ this._textureID = this.shader.texture._updateID, this._refresh()
+ }, t.vertices.get = function() {
+ return this.geometry.getAttribute("aVertexPosition").data
+ }, t.vertices.set = function(t) {
+ this.geometry.getAttribute("aVertexPosition").data = t
+ }, NineSlicePlane.prototype.updateHorizontalVertices = function() {
+ var t = this.vertices,
+ e = this._topHeight + this._bottomHeight,
+ r = this._height > e ? 1 : this._height / e;
+ t[9] = t[11] = t[13] = t[15] = this._topHeight * r, t[17] = t[19] = t[21] = t[23] = this._height - this._bottomHeight * r, t[25] = t[27] = t[29] = t[31] = this._height
+ }, NineSlicePlane.prototype.updateVerticalVertices = function() {
+ var t = this.vertices,
+ e = this._leftWidth + this._rightWidth,
+ r = this._width > e ? 1 : this._width / e;
+ t[2] = t[10] = t[18] = t[26] = this._leftWidth * r, t[4] = t[12] = t[20] = t[28] = this._width - this._rightWidth * r, t[6] = t[14] = t[22] = t[30] = this._width
+ }, t.width.get = function() {
+ return this._width
+ }, t.width.set = function(t) {
+ this._width = t, this._refresh()
+ }, t.height.get = function() {
+ return this._height
+ }, t.height.set = function(t) {
+ this._height = t, this._refresh()
+ }, t.leftWidth.get = function() {
+ return this._leftWidth
+ }, t.leftWidth.set = function(t) {
+ this._leftWidth = t, this._refresh()
+ }, t.rightWidth.get = function() {
+ return this._rightWidth
+ }, t.rightWidth.set = function(t) {
+ this._rightWidth = t, this._refresh()
+ }, t.topHeight.get = function() {
+ return this._topHeight
+ }, t.topHeight.set = function(t) {
+ this._topHeight = t, this._refresh()
+ }, t.bottomHeight.get = function() {
+ return this._bottomHeight
+ }, t.bottomHeight.set = function(t) {
+ this._bottomHeight = t, this._refresh()
+ }, NineSlicePlane.prototype._refresh = function() {
+ var t = this.texture,
+ e = this.geometry.buffers[1].data;
+ this._origWidth = t.orig.width, this._origHeight = t.orig.height;
+ var r = 1 / this._origWidth,
+ n = 1 / this._origHeight;
+ e[0] = e[8] = e[16] = e[24] = 0, e[1] = e[3] = e[5] = e[7] = 0, e[6] = e[14] = e[22] = e[30] = 1, e[25] = e[27] = e[29] = e[31] = 1, e[2] = e[10] = e[18] = e[26] = r * this._leftWidth, e[4] = e[12] = e[20] = e[28] = 1 - r * this._rightWidth, e[9] = e[11] = e[13] = e[15] = n * this._topHeight, e[17] = e[19] = e[21] = e[23] = 1 - n * this._bottomHeight, this.updateHorizontalVertices(), this.updateVerticalVertices(), this.geometry.buffers[0].update(), this.geometry.buffers[1].update()
+ }, Object.defineProperties(NineSlicePlane.prototype, t), NineSlicePlane
+ }(Jn),
+ ei = function(r) {
+ function AnimatedSprite(t, e) {
+ r.call(this, t[0] instanceof Ht ? t[0] : t[0].texture), this._textures = null, this._durations = null, this.textures = t, this._autoUpdate = !1 !== e, this.animationSpeed = 1, this.loop = !0, this.updateAnchor = !1, this.onComplete = null, this.onFrameChange = null, this.onLoop = null, this._currentTime = 0, this.playing = !1
+ }
+ r && (AnimatedSprite.__proto__ = r);
+ var t = {
+ totalFrames: {
+ configurable: !0
+ },
+ textures: {
+ configurable: !0
+ },
+ currentFrame: {
+ configurable: !0
+ }
+ };
+ return ((AnimatedSprite.prototype = Object.create(r && r.prototype)).constructor = AnimatedSprite).prototype.stop = function() {
+ this.playing && (this.playing = !1, this._autoUpdate && xt.shared.remove(this.update, this))
+ }, AnimatedSprite.prototype.play = function() {
+ this.playing || (this.playing = !0, this._autoUpdate && xt.shared.add(this.update, this, _t.HIGH))
+ }, AnimatedSprite.prototype.gotoAndStop = function(t) {
+ this.stop();
+ var e = this.currentFrame;
+ this._currentTime = t, e !== this.currentFrame && this.updateTexture()
+ }, AnimatedSprite.prototype.gotoAndPlay = function(t) {
+ var e = this.currentFrame;
+ this._currentTime = t, e !== this.currentFrame && this.updateTexture(), this.play()
+ }, AnimatedSprite.prototype.update = function(t) {
+ var e = this.animationSpeed * t,
+ r = this.currentFrame;
+ if (null !== this._durations) {
+ var n = this._currentTime % 1 * this._durations[this.currentFrame];
+ for (n += e / 60 * 1e3; n < 0;) this._currentTime--, n += this._durations[this.currentFrame];
+ var i = Math.sign(this.animationSpeed * t);
+ for (this._currentTime = Math.floor(this._currentTime); n >= this._durations[this.currentFrame];) n -= this._durations[this.currentFrame] * i, this._currentTime += i;
+ this._currentTime += n / this._durations[this.currentFrame]
+ } else this._currentTime += e;
+ this._currentTime < 0 && !this.loop ? (this.gotoAndStop(0), this.onComplete && this.onComplete()) : this._currentTime >= this._textures.length && !this.loop ? (this.gotoAndStop(this._textures.length - 1), this.onComplete && this.onComplete()) : r !== this.currentFrame && (this.loop && this.onLoop && (0 < this.animationSpeed && this.currentFrame < r ? this.onLoop() : this.animationSpeed < 0 && this.currentFrame > r && this.onLoop()), this.updateTexture())
+ }, AnimatedSprite.prototype.updateTexture = function() {
+ this._texture = this._textures[this.currentFrame], this._textureID = -1, this._textureTrimmedID = -1, this.cachedTint = 16777215, this.uvs = this._texture._uvs.uvsFloat32, this.updateAnchor && this._anchor.copy(this._texture.defaultAnchor), this.onFrameChange && this.onFrameChange(this.currentFrame)
+ }, AnimatedSprite.prototype.destroy = function(t) {
+ this.stop(), r.prototype.destroy.call(this, t), this.onComplete = null, this.onFrameChange = null, this.onLoop = null
+ }, AnimatedSprite.fromFrames = function(t) {
+ for (var e = [], r = 0; r < t.length; ++r) e.push(Ht.from(t[r]));
+ return new AnimatedSprite(e)
+ }, AnimatedSprite.fromImages = function(t) {
+ for (var e = [], r = 0; r < t.length; ++r) e.push(Ht.from(t[r]));
+ return new AnimatedSprite(e)
+ }, t.totalFrames.get = function() {
+ return this._textures.length
+ }, t.textures.get = function() {
+ return this._textures
+ }, t.textures.set = function(t) {
+ if (t[0] instanceof Ht) this._textures = t, this._durations = null;
+ else {
+ this._textures = [], this._durations = [];
+ for (var e = 0; e < t.length; e++) this._textures.push(t[e].texture), this._durations.push(t[e].time)
+ }
+ this.gotoAndStop(0), this.updateTexture()
+ }, t.currentFrame.get = function() {
+ var t = Math.floor(this._currentTime) % this._textures.length;
+ return t < 0 && (t += this._textures.length), t
+ }, Object.defineProperties(AnimatedSprite.prototype, t), AnimatedSprite
+ }(Xr);
+ r.d(e, "VERSION", function() {
+ return ri
+ }), r.d(e, "filters", function() {
+ return ni
+ }), r.d(e, "useDeprecated", function() {
+ return useDeprecated
+ }), r.d(e, "accessibility", function() {
+ return i
+ }), r.d(e, "extract", function() {
+ return o
+ }), r.d(e, "interaction", function() {
+ return a
+ }), r.d(e, "prepare", function() {
+ return s
+ }), r.d(e, "utils", function() {
+ return n
+ }), r.d(e, "Application", function() {
+ return rn
+ }), r.d(e, "AbstractRenderer", function() {
+ return Je
+ }), r.d(e, "Attribute", function() {
+ return Yt
+ }), r.d(e, "BaseRenderTexture", function() {
+ return Xt
+ }), r.d(e, "BaseTexture", function() {
+ return Rt
+ }), r.d(e, "BatchDrawCall", function() {
+ return ir
+ }), r.d(e, "BatchGeometry", function() {
+ return nr
+ }), r.d(e, "BatchRenderer", function() {
+ return cr
+ }), r.d(e, "Buffer", function() {
+ return Zt
+ }), r.d(e, "CubeTexture", function() {
+ return rr
+ }), r.d(e, "Filter", function() {
+ return De
+ }), r.d(e, "Framebuffer", function() {
+ return jt
+ }), r.d(e, "GLProgram", function() {
+ return Xe
+ }), r.d(e, "GLTexture", function() {
+ return Rt
+ }), r.d(e, "Geometry", function() {
+ return ee
+ }), r.d(e, "ObjectRenderer", function() {
+ return he
+ }), r.d(e, "Program", function() {
+ return Ae
+ }), r.d(e, "Quad", function() {
+ return re
+ }), r.d(e, "QuadUv", function() {
+ return ne
+ }), r.d(e, "RenderTexture", function() {
+ return Wt
+ }), r.d(e, "Renderer", function() {
+ return $e
+ }), r.d(e, "Shader", function() {
+ return Ie
+ }), r.d(e, "SpriteMaskFilter", function() {
+ return Ne
+ }), r.d(e, "State", function() {
+ return Ce
+ }), r.d(e, "System", function() {
+ return Ut
+ }), r.d(e, "Texture", function() {
+ return Ht
+ }), r.d(e, "TextureMatrix", function() {
+ return ke
+ }), r.d(e, "TextureUvs", function() {
+ return Vt
+ }), r.d(e, "UniformGroup", function() {
+ return oe
+ }), r.d(e, "autoDetectRenderer", function() {
+ return autoDetectRenderer
+ }), r.d(e, "checkMaxIfStatementsInShader", function() {
+ return checkMaxIfStatementsInShader
+ }), r.d(e, "defaultFilterVertex", function() {
+ return er
+ }), r.d(e, "defaultVertex", function() {
+ return tr
+ }), r.d(e, "generateMultiTextureShader", function() {
+ return generateMultiTextureShader
+ }), r.d(e, "resources", function() {
+ return Bt
+ }), r.d(e, "systems", function() {
+ return Ze
+ }), r.d(e, "AppLoaderPlugin", function() {
+ return vn
+ }), r.d(e, "Loader", function() {
+ return mn
+ }), r.d(e, "LoaderResource", function() {
+ return gn
+ }), r.d(e, "TextureLoader", function() {
+ return pn
+ }), r.d(e, "ParticleContainer", function() {
+ return yn
+ }), r.d(e, "ParticleRenderer", function() {
+ return bn
+ }), r.d(e, "Spritesheet", function() {
+ return xn
+ }), r.d(e, "SpritesheetLoader", function() {
+ return Tn
+ }), r.d(e, "TilingSprite", function() {
+ return Mn
+ }), r.d(e, "TilingSpriteRenderer", function() {
+ return Pn
+ }), r.d(e, "BitmapFontLoader", function() {
+ return On
+ }), r.d(e, "BitmapText", function() {
+ return In
+ }), r.d(e, "Ticker", function() {
+ return xt
+ }), r.d(e, "TickerPlugin", function() {
+ return St
+ }), r.d(e, "UPDATE_PRIORITY", function() {
+ return _t
+ }), r.d(e, "BLEND_MODES", function() {
+ return y
+ }), r.d(e, "DRAW_MODES", function() {
+ return x
+ }), r.d(e, "ENV", function() {
+ return v
+ }), r.d(e, "FORMATS", function() {
+ return _
+ }), r.d(e, "GC_MODES", function() {
+ return A
+ }), r.d(e, "MIPMAP_MODES", function() {
+ return E
+ }), r.d(e, "PRECISION", function() {
+ return P
+ }), r.d(e, "RENDERER_TYPE", function() {
+ return g
+ }), r.d(e, "SCALE_MODES", function() {
+ return T
+ }), r.d(e, "TARGETS", function() {
+ return b
+ }), r.d(e, "TYPES", function() {
+ return w
+ }), r.d(e, "WRAP_MODES", function() {
+ return S
+ }), r.d(e, "Bounds", function() {
+ return ft
+ }), r.d(e, "Container", function() {
+ return pt
+ }), r.d(e, "DisplayObject", function() {
+ return dt
+ }), r.d(e, "GRAPHICS_CURVES", function() {
+ return xr
+ }), r.d(e, "Graphics", function() {
+ return Gr
+ }), r.d(e, "GraphicsData", function() {
+ return Tr
+ }), r.d(e, "GraphicsGeometry", function() {
+ return Rr
+ }), r.d(e, "Circle", function() {
+ return ut
+ }), r.d(e, "DEG_TO_RAD", function() {
+ return H
+ }), r.d(e, "Ellipse", function() {
+ return ht
+ }), r.d(e, "GroupD8", function() {
+ return rt
+ }), r.d(e, "Matrix", function() {
+ return Y
+ }), r.d(e, "ObservablePoint", function() {
+ return j
+ }), r.d(e, "PI_2", function() {
+ return X
+ }), r.d(e, "Point", function() {
+ return q
+ }), r.d(e, "Polygon", function() {
+ return ct
+ }), r.d(e, "RAD_TO_DEG", function() {
+ return V
+ }), r.d(e, "Rectangle", function() {
+ return ot
+ }), r.d(e, "RoundedRectangle", function() {
+ return lt
+ }), r.d(e, "SHAPES", function() {
+ return W
+ }), r.d(e, "Transform", function() {
+ return nt
+ }), r.d(e, "Mesh", function() {
+ return Hn
+ }), r.d(e, "MeshBatchUvs", function() {
+ return Xn
+ }), r.d(e, "MeshGeometry", function() {
+ return Yn
+ }), r.d(e, "MeshMaterial", function() {
+ return Wn
+ }), r.d(e, "NineSlicePlane", function() {
+ return ti
+ }), r.d(e, "PlaneGeometry", function() {
+ return Kn
+ }), r.d(e, "RopeGeometry", function() {
+ return Zn
+ }), r.d(e, "SimpleMesh", function() {
+ return $n
+ }), r.d(e, "SimplePlane", function() {
+ return Jn
+ }), r.d(e, "SimpleRope", function() {
+ return Qn
+ }), r.d(e, "Runner", function() {
+ return gt
+ }), r.d(e, "Sprite", function() {
+ return Xr
+ }), r.d(e, "AnimatedSprite", function() {
+ return ei
+ }), r.d(e, "TEXT_GRADIENT", function() {
+ return Vr
+ }), r.d(e, "Text", function() {
+ return Qr
+ }), r.d(e, "TextMetrics", function() {
+ return Yr
+ }), r.d(e, "TextStyle", function() {
+ return Hr
+ }), r.d(e, "isMobile", function() {
+ return h.a
+ }), r.d(e, "settings", function() {
+ return M
+ });
+
+ function useDeprecated() {
+ var e = this;
+ Object.defineProperties(e, {
+ SVG_SIZE: {
+ get: function() {
+ return deprecation(0, "PIXI.utils.SVG_SIZE has moved to PIXI.SVGResource.SVG_SIZE"), e.SVGResource.SVG_SIZE
+ }
+ },
+ TransformStatic: {
+ get: function() {
+ return deprecation(0, "PIXI.TransformStatic has been removed, use PIXI.Transform"), e.Transform
+ }
+ },
+ TransformBase: {
+ get: function() {
+ return deprecation(0, "PIXI.TransformBase has been removed, use PIXI.Transform"), e.Transform
+ }
+ },
+ TRANSFORM_MODE: {
+ get: function() {
+ return deprecation(0, "PIXI.TRANSFORM_MODE has been removed"), {
+ STATIC: 0,
+ DYNAMIC: 1
+ }
+ }
+ },
+ WebGLRenderer: {
+ get: function() {
+ return deprecation(0, "PIXI.WebGLRenderer has moved to PIXI.Renderer"), e.Renderer
+ }
+ },
+ CanvasRenderTarget: {
+ get: function() {
+ return deprecation(0, "PIXI.CanvasRenderTarget has moved to PIXI.utils.CanvasRenderTarget"), e.utils.CanvasRenderTarget
+ }
+ },
+ loader: {
+ get: function() {
+ return deprecation(0, "PIXI.loader has moved to PIXI.Loader.shared"), e.Loader.shared
+ }
+ },
+ FilterManager: {
+ get: function() {
+ return deprecation(0, "PIXI.FilterManager has moved to PIXI.systems.FilterSystem"), e.systems.FilterManager
+ }
+ }
+ }), e.extras = {}, Object.defineProperties(e.extras, {
+ TilingSprite: {
+ get: function() {
+ return deprecation(0, "PIXI.extras.TilingSprite has moved to PIXI.TilingSprite"), e.TilingSprite
+ }
+ },
+ TilingSpriteRenderer: {
+ get: function() {
+ return deprecation(0, "PIXI.extras.TilingSpriteRenderer has moved to PIXI.TilingSpriteRenderer"), e.TilingSpriteRenderer
+ }
+ },
+ AnimatedSprite: {
+ get: function() {
+ return deprecation(0, "PIXI.extras.AnimatedSprite has moved to PIXI.AnimatedSprite"), e.AnimatedSprite
+ }
+ },
+ BitmapText: {
+ get: function() {
+ return deprecation(0, "PIXI.extras.BitmapText has moved to PIXI.BitmapText"), e.BitmapText
+ }
+ }
+ }), Object.defineProperties(e.utils, {
+ getSvgSize: {
+ get: function() {
+ return deprecation(0, "PIXI.utils.getSvgSize has moved to PIXI.SVGResource.getSize"), e.SVGResource.getSize
+ }
+ }
+ }), e.mesh = {}, Object.defineProperties(e.mesh, {
+ Mesh: {
+ get: function() {
+ return deprecation(0, "PIXI.mesh.Mesh has moved to PIXI.SimpleMesh"), e.SimpleMesh
+ }
+ },
+ NineSlicePlane: {
+ get: function() {
+ return deprecation(0, "PIXI.mesh.NineSlicePlane has moved to PIXI.NineSlicePlane"), e.NineSlicePlane
+ }
+ },
+ Plane: {
+ get: function() {
+ return deprecation(0, "PIXI.mesh.Plane has moved to PIXI.SimplePlane"), e.SimplePlane
+ }
+ },
+ Rope: {
+ get: function() {
+ return deprecation(0, "PIXI.mesh.Rope has moved to PIXI.SimpleRope"), e.SimpleRope
+ }
+ },
+ RawMesh: {
+ get: function() {
+ return deprecation(0, "PIXI.mesh.RawMesh has moved to PIXI.Mesh"), e.Mesh
+ }
+ },
+ CanvasMeshRenderer: {
+ get: function() {
+ return deprecation(0, "PIXI.mesh.CanvasMeshRenderer has moved to PIXI.CanvasMeshRenderer"), e.CanvasMeshRenderer
+ }
+ },
+ MeshRenderer: {
+ get: function() {
+ return deprecation(0, "PIXI.mesh.MeshRenderer has moved to PIXI.MeshRenderer"), e.MeshRenderer
+ }
+ }
+ }), e.particles = {}, Object.defineProperties(e.particles, {
+ ParticleContainer: {
+ get: function() {
+ return deprecation(0, "PIXI.particles.ParticleContainer has moved to PIXI.ParticleContainer"), e.ParticleContainer
+ }
+ },
+ ParticleRenderer: {
+ get: function() {
+ return deprecation(0, "PIXI.particles.ParticleRenderer has moved to PIXI.ParticleRenderer"), e.ParticleRenderer
+ }
+ }
+ }), e.ticker = {}, Object.defineProperties(e.ticker, {
+ Ticker: {
+ get: function() {
+ return deprecation(0, "PIXI.ticker.Ticker has moved to PIXI.Ticker"), e.Ticker
+ }
+ },
+ shared: {
+ get: function() {
+ return deprecation(0, "PIXI.ticker.shared has moved to PIXI.Ticker.shared"), e.Ticker.shared
+ }
+ }
+ }), e.loaders = {}, Object.defineProperties(e.loaders, {
+ Loader: {
+ get: function() {
+ return deprecation(0, "PIXI.loaders.Loader has moved to PIXI.Loader"), e.Loader
+ }
+ },
+ Resource: {
+ get: function() {
+ return deprecation(0, "PIXI.loaders.Resource has moved to PIXI.LoaderResource"), e.LoaderResource
+ }
+ },
+ bitmapFontParser: {
+ get: function() {
+ return deprecation(0, "PIXI.loaders.bitmapFontParser has moved to PIXI.BitmapFontLoader.use"), e.BitmapFontLoader.use
+ }
+ },
+ parseBitmapFontData: {
+ get: function() {
+ return deprecation(0, "PIXI.loaders.parseBitmapFontData has moved to PIXI.BitmapFontLoader.parse"), e.BitmapFontLoader.parse
+ }
+ },
+ spritesheetParser: {
+ get: function() {
+ return deprecation(0, "PIXI.loaders.spritesheetParser has moved to PIXI.SpritesheetLoader.use"), e.SpritesheetLoader.use
+ }
+ },
+ getResourcePath: {
+ get: function() {
+ return deprecation(0, "PIXI.loaders.getResourcePath has moved to PIXI.SpritesheetLoader.getResourcePath"), e.SpritesheetLoader.getResourcePath
+ }
+ }
+ }), e.Loader.addPixiMiddleware = function(t) {
+ return deprecation(0, "PIXI.loaders.Loader.addPixiMiddleware is deprecated, use PIXI.loaders.Loader.registerPlugin"), e.loaders.Loader.registerPlugin({
+ use: t()
+ })
+ }, Object.defineProperty(e.extract, "WebGLExtract", {
+ get: function() {
+ return deprecation(0, "PIXI.extract.WebGLExtract has moved to PIXI.extract.Extract"), e.extract.Extract
+ }
+ }), Object.defineProperty(e.prepare, "WebGLPrepare", {
+ get: function() {
+ return deprecation(0, "PIXI.prepare.WebGLPrepare has moved to PIXI.prepare.Prepare"), e.prepare.Prepare
+ }
+ }), e.Container.prototype._renderWebGL = function(t) {
+ deprecation(0, "PIXI.Container#_renderWebGL has moved to PIXI.Container#_render"), this._render(t)
+ }, e.Container.prototype.renderWebGL = function(t) {
+ deprecation(0, "PIXI.Container#renderWebGL has moved to PIXI.Container#render"), this.render(t)
+ }, e.DisplayObject.prototype.renderWebGL = function(t) {
+ deprecation(0, "PIXI.DisplayObject#renderWebGL has moved to PIXI.DisplayObject#render"), this.render(t)
+ }, e.Container.prototype.renderAdvancedWebGL = function(t) {
+ deprecation(0, "PIXI.Container#renderAdvancedWebGL has moved to PIXI.Container#renderAdvanced"), this.renderAdvanced(t)
+ }, Object.defineProperties(e.settings, {
+ TRANSFORM_MODE: {
+ get: function() {
+ return deprecation(0, "PIXI.settings.TRANSFORM_MODE has been removed."), 0
+ },
+ set: function() {
+ deprecation(0, "PIXI.settings.TRANSFORM_MODE has been removed.")
+ }
+ }
+ });
+ var o = e.BaseTexture;
+ o.fromImage = function(t, e, r, n) {
+ deprecation(0, "PIXI.BaseTexture.fromImage has been replaced with PIXI.BaseTexture.from");
+ var i = {
+ scale: n,
+ crossorigin: e
+ };
+ return o.from(t, {
+ scaleMode: r,
+ resourceOptions: i
+ })
+ }, o.fromCanvas = function(t, e) {
+ return deprecation(0, "PIXI.BaseTexture.fromCanvas has been replaced with PIXI.BaseTexture.from"), o.from(t, {
+ scaleMode: e
+ })
+ }, o.fromSVG = function(t, e, r, n) {
+ deprecation(0, "PIXI.BaseTexture.fromSVG has been replaced with PIXI.BaseTexture.from");
+ var i = {
+ scale: n,
+ crossorigin: e
+ };
+ return o.from(t, {
+ scaleMode: r,
+ resourceOptions: i
+ })
+ }, e.Point.prototype.copy = function(t) {
+ return deprecation(0, "PIXI.Point.copy has been replaced with PIXI.Point#copyFrom"), this.copyFrom(t)
+ }, e.ObservablePoint.prototype.copy = function(t) {
+ return deprecation(0, "PIXI.ObservablePoint.copy has been replaced with PIXI.ObservablePoint#copyFrom"), this.copyFrom(t)
+ }, e.Rectangle.prototype.copy = function(t) {
+ return deprecation(0, "PIXI.Rectangle.copy has been replaced with PIXI.Rectangle#copyFrom"), this.copyFrom(t)
+ }, e.Matrix.prototype.copy = function(t) {
+ return deprecation(0, "PIXI.Matrix.copy has been replaced with PIXI.Matrix#copyTo"), this.copyTo(t)
+ }, Object.assign(e.systems.FilterSystem.prototype, {
+ getRenderTarget: function(t, e) {
+ return deprecation(0, "FilterManager#getRenderTarget has been replaced with FilterSystem#getFilterTexture"), this.getFilterTexture(e)
+ },
+ returnRenderTarget: function(t) {
+ deprecation(0, "FilterManager#returnRenderTarget has been replaced with FilterSystem#returnFilterTexture"), this.returnFilterTexture(t)
+ }
+ }), Object.defineProperties(e.RenderTexture.prototype, {
+ sourceFrame: {
+ get: function() {
+ return deprecation(0, "PIXI.RenderTexture#sourceFrame has been removed"), this.filterFrame
+ }
+ },
+ size: {
+ get: function() {
+ return deprecation(0, "PIXI.RenderTexture#size has been removed"), this._frame
+ }
+ }
+ });
+ var t = function(i) {
+ function BlurXFilter(t, e, r, n) {
+ deprecation(0, "PIXI.filters.BlurXFilter is deprecated, use PIXI.filters.BlurFilterPass"), i.call(this, !0, t, e, r, n)
+ }
+ return i && (BlurXFilter.__proto__ = i), (BlurXFilter.prototype = Object.create(i && i.prototype)).constructor = BlurXFilter
+ }(e.filters.BlurFilterPass),
+ r = function(i) {
+ function BlurYFilter(t, e, r, n) {
+ deprecation(0, "PIXI.filters.BlurYFilter is deprecated, use PIXI.filters.BlurFilterPass"), i.call(this, !1, t, e, r, n)
+ }
+ return i && (BlurYFilter.__proto__ = i), (BlurYFilter.prototype = Object.create(i && i.prototype)).constructor = BlurYFilter
+ }(e.filters.BlurFilterPass);
+ Object.assign(e.filters, {
+ BlurXFilter: t,
+ BlurYFilter: r
+ });
+ var i = e.Sprite,
+ a = e.Texture,
+ n = e.Graphics;
+
+ function spriteFrom(t, e, r, n) {
+ return deprecation(0, "PIXI.Sprite." + t + " is deprecated, use PIXI.Sprite.from"), i.from(e, {
+ resourceOptions: {
+ scale: n,
+ crossorigin: r
+ }
+ })
+ }
+
+ function textureFrom(t, e, r, n) {
+ return deprecation(0, "PIXI.Texture." + t + " is deprecated, use PIXI.Texture.from"), a.from(e, {
+ resourceOptions: {
+ scale: n,
+ crossorigin: r
+ }
+ })
+ }
+ n.prototype.generateCanvasTexture || (n.prototype.generateCanvasTexture = function() {
+ deprecation(0, 'PIXI.Graphics#generateCanvasTexture is only available in "pixi.js-legacy"')
+ }), i.fromImage = spriteFrom.bind(null, "fromImage"), i.fromSVG = spriteFrom.bind(null, "fromSVG"), i.fromCanvas = spriteFrom.bind(null, "fromCanvas"), i.fromVideo = spriteFrom.bind(null, "fromVideo"), i.fromFrame = spriteFrom.bind(null, "fromFrame"), a.fromImage = textureFrom.bind(null, "fromImage"), a.fromSVG = textureFrom.bind(null, "fromSVG"), a.fromCanvas = textureFrom.bind(null, "fromCanvas"), a.fromVideo = textureFrom.bind(null, "fromVideo"), a.fromFrame = textureFrom.bind(null, "fromFrame"), Object.defineProperty(e.AbstractRenderer.prototype, "autoResize", {
+ get: function() {
+ return deprecation(0, "PIXI.AbstractRenderer autoResize is deprecated, use autoDensity"), this.autoDensity
+ },
+ set: function(t) {
+ deprecation(0, "PIXI.AbstractRenderer autoResize is deprecated, use autoDensity"), this.autoDensity = t
+ }
+ }), e.utils.mixins = {
+ mixin: function() {
+ deprecation(0, "PIXI.utils.mixins.mixin no longer available")
+ },
+ delayMixin: function() {
+ deprecation(0, "PIXI.utils.mixins.delayMixin no longer available")
+ },
+ performMixins: function() {
+ deprecation(0, "PIXI.utils.mixins.performMixins no longer available")
+ }
+ }
+ }
+ $e.registerPlugin("accessibility", vt), $e.registerPlugin("extract", fr), $e.registerPlugin("interaction", br), $e.registerPlugin("particle", bn), $e.registerPlugin("prepare", tn), $e.registerPlugin("batch", cr), $e.registerPlugin("tilingSprite", Pn), mn.registerPlugin(On), mn.registerPlugin(Tn), rn.registerPlugin(St), rn.registerPlugin(vn);
+ var ri = "5.0.0-rc.3",
+ ni = {
+ AlphaFilter: Cn,
+ BlurFilter: Ln,
+ BlurFilterPass: kn,
+ ColorMatrixFilter: Nn,
+ DisplacementFilter: Bn,
+ FXAAFilter: Un,
+ NoiseFilter: Gn
+ }
+ }, function(t, e, r) {
+ var m = r(9),
+ v = r(32),
+ g = r(25),
+ y = r(26),
+ _ = r(33),
+ b = "prototype",
+ x = function(t, e, r) {
+ var n, i, o, a, s = t & x.F,
+ u = t & x.G,
+ h = t & x.S,
+ c = t & x.P,
+ l = t & x.B,
+ f = u ? m : h ? m[e] || (m[e] = {}) : (m[e] || {})[b],
+ d = u ? v : v[e] || (v[e] = {}),
+ p = d[b] || (d[b] = {});
+ for (n in u && (r = e), r) o = ((i = !s && f && void 0 !== f[n]) ? f : r)[n], a = l && i ? _(o, m) : c && "function" == typeof o ? _(Function.call, o) : o, f && y(f, n, o, t & x.U), d[n] != o && g(d, n, a), c && p[n] != o && (p[n] = o)
+ };
+ m.core = v, x.F = 1, x.G = 2, x.S = 4, x.P = 8, x.B = 16, x.W = 32, x.U = 64, x.R = 128, t.exports = x
+ }, function(t, e, r) {
+ "use strict";
+ var n = {};
+ r.r(n), r.d(n, "DEG2RAD", function() {
+ return u
+ }), r.d(n, "RAD2DEG", function() {
+ return h
+ }), r.d(n, "generateUUID", function() {
+ return generateUUID
+ }), r.d(n, "clamp", function() {
+ return Math_clamp
+ }), r.d(n, "euclideanModulo", function() {
+ return euclideanModulo
+ }), r.d(n, "mapLinear", function() {
+ return mapLinear
+ }), r.d(n, "lerp", function() {
+ return lerp
+ }), r.d(n, "smoothstep", function() {
+ return smoothstep
+ }), r.d(n, "smootherstep", function() {
+ return smootherstep
+ }), r.d(n, "randInt", function() {
+ return randInt
+ }), r.d(n, "randFloat", function() {
+ return randFloat
+ }), r.d(n, "randFloatSpread", function() {
+ return randFloatSpread
+ }), r.d(n, "degToRad", function() {
+ return degToRad
+ }), r.d(n, "radToDeg", function() {
+ return radToDeg
+ }), r.d(n, "isPowerOfTwo", function() {
+ return isPowerOfTwo
+ }), r.d(n, "ceilPowerOfTwo", function() {
+ return ceilPowerOfTwo
+ }), r.d(n, "floorPowerOfTwo", function() {
+ return floorPowerOfTwo
+ });
+ var i = r(90);
+
+ function _inheritsLoose(t, e) {
+ t.prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e
+ }
+
+ function _defineProperties(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n)
+ }
+ }
+ for (var o = function() {
+ function BufferAttribute(t, e, r) {
+ if (Array.isArray(t)) throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");
+ this.name = "", this.array = t, this.itemSize = e, this.count = void 0 !== t ? t.length / e : 0, this.normalized = !0 === r, this.dynamic = !1, this.updateRange = {
+ offset: 0,
+ count: -1
+ }, this.version = 0, this.isBufferAttribute = !0
+ }
+ var t, e, r, n = BufferAttribute.prototype;
+ return n.onUploadCallback = function() {}, n.setArray = function(t) {
+ if (Array.isArray(t)) throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");
+ return this.count = void 0 !== t ? t.length / this.itemSize : 0, this.array = t, this
+ }, n.setDynamic = function(t) {
+ return this.dynamic = t, this
+ }, n.copy = function(t) {
+ return this.name = t.name, this.array = new t.array.constructor(t.array), this.itemSize = t.itemSize, this.count = t.count, this.normalized = t.normalized, this.dynamic = t.dynamic, this
+ }, n.copyAt = function(t, e, r) {
+ t *= this.itemSize, r *= e.itemSize;
+ for (var n = 0, i = this.itemSize; n < i; n++) this.array[t + n] = e.array[r + n];
+ return this
+ }, n.copyArray = function(t) {
+ return this.array.set(t), this
+ }, n.copyColorsArray = function(t) {
+ for (var e = this.array, r = 0, n = 0, i = t.length; n < i; n++) {
+ var o = t[n];
+ void 0 === o && (o = new Color), e[r++] = o.r, e[r++] = o.g, e[r++] = o.b
+ }
+ return this
+ }, n.copyVector2sArray = function(t) {
+ for (var e = this.array, r = 0, n = 0, i = t.length; n < i; n++) {
+ var o = t[n];
+ void 0 === o && (o = new Vector2), e[r++] = o.x, e[r++] = o.y
+ }
+ return this
+ }, n.copyVector3sArray = function(t) {
+ for (var e = this.array, r = 0, n = 0, i = t.length; n < i; n++) {
+ var o = t[n];
+ void 0 === o && (o = new Vector3), e[r++] = o.x, e[r++] = o.y, e[r++] = o.z
+ }
+ return this
+ }, n.copyVector4sArray = function(t) {
+ for (var e = this.array, r = 0, n = 0, i = t.length; n < i; n++) {
+ var o = t[n];
+ void 0 === o && (o = new Vector4), e[r++] = o.x, e[r++] = o.y, e[r++] = o.z, e[r++] = o.w
+ }
+ return this
+ }, n.set = function(t, e) {
+ return void 0 === e && (e = 0), this.array.set(t, e), this
+ }, n.getX = function(t) {
+ return this.array[t * this.itemSize]
+ }, n.setX = function(t, e) {
+ return this.array[t * this.itemSize] = e, this
+ }, n.getY = function(t) {
+ return this.array[t * this.itemSize + 1]
+ }, n.setY = function(t, e) {
+ return this.array[t * this.itemSize + 1] = e, this
+ }, n.getZ = function(t) {
+ return this.array[t * this.itemSize + 2]
+ }, n.setZ = function(t, e) {
+ return this.array[t * this.itemSize + 2] = e, this
+ }, n.getW = function(t) {
+ return this.array[t * this.itemSize + 3]
+ }, n.setW = function(t, e) {
+ return this.array[t * this.itemSize + 3] = e, this
+ }, n.setXY = function(t, e, r) {
+ return t *= this.itemSize, this.array[t + 0] = e, this.array[t + 1] = r, this
+ }, n.setXYZ = function(t, e, r, n) {
+ return t *= this.itemSize, this.array[t + 0] = e, this.array[t + 1] = r, this.array[t + 2] = n, this
+ }, n.setXYZW = function(t, e, r, n, i) {
+ return t *= this.itemSize, this.array[t + 0] = e, this.array[t + 1] = r, this.array[t + 2] = n, this.array[t + 3] = i, this
+ }, n.onUpload = function(t) {
+ return this.onUploadCallback = t, this
+ }, n.clone = function() {
+ return new this.constructor(this.array, this.itemSize).copy(this)
+ }, t = BufferAttribute, (e = [{
+ key: "needsUpdate",
+ set: function(t) {
+ !0 === t && this.version++
+ }
+ }]) && _defineProperties(t.prototype, e), r && _defineProperties(t, r), BufferAttribute
+ }(), a = function(n) {
+ function Float32BufferAttribute(t, e, r) {
+ return n.call(this, new Float32Array(t), e, r) || this
+ }
+ return _inheritsLoose(Float32BufferAttribute, n), Float32BufferAttribute
+ }(o), s = function(n) {
+ function Uint16BufferAttribute(t, e, r) {
+ return n.call(this, new Uint16Array(t), e, r) || this
+ }
+ return _inheritsLoose(Uint16BufferAttribute, n), Uint16BufferAttribute
+ }(o), u = Math.PI / 180, h = 180 / Math.PI, c = [], l = 0; l < 256; l++) c[l] = (l < 16 ? "0" : "") + l.toString(16);
+
+ function generateUUID() {
+ var t = 4294967295 * Math.random() | 0,
+ e = 4294967295 * Math.random() | 0,
+ r = 4294967295 * Math.random() | 0,
+ n = 4294967295 * Math.random() | 0;
+ return (c[255 & t] + c[t >> 8 & 255] + c[t >> 16 & 255] + c[t >> 24 & 255] + "-" + c[255 & e] + c[e >> 8 & 255] + "-" + c[e >> 16 & 15 | 64] + c[e >> 24 & 255] + "-" + c[63 & r | 128] + c[r >> 8 & 255] + "-" + c[r >> 16 & 255] + c[r >> 24 & 255] + c[255 & n] + c[n >> 8 & 255] + c[n >> 16 & 255] + c[n >> 24 & 255]).toUpperCase()
+ }
+
+ function Math_clamp(t, e, r) {
+ return Math.max(e, Math.min(r, t))
+ }
+
+ function euclideanModulo(t, e) {
+ return (t % e + e) % e
+ }
+
+ function mapLinear(t, e, r, n, i) {
+ return n + (t - e) * (i - n) / (r - e)
+ }
+
+ function lerp(t, e, r) {
+ return (1 - r) * t + r * e
+ }
+
+ function smoothstep(t, e, r) {
+ return t <= e ? 0 : r <= t ? 1 : (t = (t - e) / (r - e)) * t * (3 - 2 * t)
+ }
+
+ function smootherstep(t, e, r) {
+ return t <= e ? 0 : r <= t ? 1 : (t = (t - e) / (r - e)) * t * t * (t * (6 * t - 15) + 10)
+ }
+
+ function randInt(t, e) {
+ return t + Math.floor(Math.random() * (e - t + 1))
+ }
+
+ function randFloat(t, e) {
+ return t + Math.random() * (e - t)
+ }
+
+ function randFloatSpread(t) {
+ return t * (.5 - Math.random())
+ }
+
+ function degToRad(t) {
+ return t * u
+ }
+
+ function radToDeg(t) {
+ return t * h
+ }
+
+ function isPowerOfTwo(t) {
+ return 0 == (t & t - 1) && 0 !== t
+ }
+
+ function ceilPowerOfTwo(t) {
+ return Math.pow(2, Math.ceil(Math.log(t) / Math.LN2))
+ }
+
+ function floorPowerOfTwo(t) {
+ return Math.pow(2, Math.floor(Math.log(t) / Math.LN2))
+ }
+ var f = {
+ aliceblue: 15792383,
+ antiquewhite: 16444375,
+ aqua: 65535,
+ aquamarine: 8388564,
+ azure: 15794175,
+ beige: 16119260,
+ bisque: 16770244,
+ black: 0,
+ blanchedalmond: 16772045,
+ blue: 255,
+ blueviolet: 9055202,
+ brown: 10824234,
+ burlywood: 14596231,
+ cadetblue: 6266528,
+ chartreuse: 8388352,
+ chocolate: 13789470,
+ coral: 16744272,
+ cornflowerblue: 6591981,
+ cornsilk: 16775388,
+ crimson: 14423100,
+ cyan: 65535,
+ darkblue: 139,
+ darkcyan: 35723,
+ darkgoldenrod: 12092939,
+ darkgray: 11119017,
+ darkgreen: 25600,
+ darkgrey: 11119017,
+ darkkhaki: 12433259,
+ darkmagenta: 9109643,
+ darkolivegreen: 5597999,
+ darkorange: 16747520,
+ darkorchid: 10040012,
+ darkred: 9109504,
+ darksalmon: 15308410,
+ darkseagreen: 9419919,
+ darkslateblue: 4734347,
+ darkslategray: 3100495,
+ darkslategrey: 3100495,
+ darkturquoise: 52945,
+ darkviolet: 9699539,
+ deeppink: 16716947,
+ deepskyblue: 49151,
+ dimgray: 6908265,
+ dimgrey: 6908265,
+ dodgerblue: 2003199,
+ firebrick: 11674146,
+ floralwhite: 16775920,
+ forestgreen: 2263842,
+ fuchsia: 16711935,
+ gainsboro: 14474460,
+ ghostwhite: 16316671,
+ gold: 16766720,
+ goldenrod: 14329120,
+ gray: 8421504,
+ green: 32768,
+ greenyellow: 11403055,
+ grey: 8421504,
+ honeydew: 15794160,
+ hotpink: 16738740,
+ indianred: 13458524,
+ indigo: 4915330,
+ ivory: 16777200,
+ khaki: 15787660,
+ lavender: 15132410,
+ lavenderblush: 16773365,
+ lawngreen: 8190976,
+ lemonchiffon: 16775885,
+ lightblue: 11393254,
+ lightcoral: 15761536,
+ lightcyan: 14745599,
+ lightgoldenrodyellow: 16448210,
+ lightgray: 13882323,
+ lightgreen: 9498256,
+ lightgrey: 13882323,
+ lightpink: 16758465,
+ lightsalmon: 16752762,
+ lightseagreen: 2142890,
+ lightskyblue: 8900346,
+ lightslategray: 7833753,
+ lightslategrey: 7833753,
+ lightsteelblue: 11584734,
+ lightyellow: 16777184,
+ lime: 65280,
+ limegreen: 3329330,
+ linen: 16445670,
+ magenta: 16711935,
+ maroon: 8388608,
+ mediumaquamarine: 6737322,
+ mediumblue: 205,
+ mediumorchid: 12211667,
+ mediumpurple: 9662683,
+ mediumseagreen: 3978097,
+ mediumslateblue: 8087790,
+ mediumspringgreen: 64154,
+ mediumturquoise: 4772300,
+ mediumvioletred: 13047173,
+ midnightblue: 1644912,
+ mintcream: 16121850,
+ mistyrose: 16770273,
+ moccasin: 16770229,
+ navajowhite: 16768685,
+ navy: 128,
+ oldlace: 16643558,
+ olive: 8421376,
+ olivedrab: 7048739,
+ orange: 16753920,
+ orangered: 16729344,
+ orchid: 14315734,
+ palegoldenrod: 15657130,
+ palegreen: 10025880,
+ paleturquoise: 11529966,
+ palevioletred: 14381203,
+ papayawhip: 16773077,
+ peachpuff: 16767673,
+ peru: 13468991,
+ pink: 16761035,
+ plum: 14524637,
+ powderblue: 11591910,
+ purple: 8388736,
+ rebeccapurple: 6697881,
+ red: 16711680,
+ rosybrown: 12357519,
+ royalblue: 4286945,
+ saddlebrown: 9127187,
+ salmon: 16416882,
+ sandybrown: 16032864,
+ seagreen: 3050327,
+ seashell: 16774638,
+ sienna: 10506797,
+ silver: 12632256,
+ skyblue: 8900331,
+ slateblue: 6970061,
+ slategray: 7372944,
+ slategrey: 7372944,
+ snow: 16775930,
+ springgreen: 65407,
+ steelblue: 4620980,
+ tan: 13808780,
+ teal: 32896,
+ thistle: 14204888,
+ tomato: 16737095,
+ turquoise: 4251856,
+ violet: 15631086,
+ wheat: 16113331,
+ white: 16777215,
+ whitesmoke: 16119285,
+ yellow: 16776960,
+ yellowgreen: 10145074
+ };
+
+ function hue2rgb(t, e, r) {
+ return r < 0 && (r += 1), 1 < r && (r -= 1), r < 1 / 6 ? t + 6 * (e - t) * r : r < .5 ? e : r < 2 / 3 ? t + 6 * (e - t) * (2 / 3 - r) : t
+ }
+
+ function SRGBToLinear(t) {
+ return t < .04045 ? .0773993808 * t : Math.pow(.9478672986 * t + .0521327014, 2.4)
+ }
+
+ function LinearToSRGB(t) {
+ return t < .0031308 ? 12.92 * t : 1.055 * Math.pow(t, .41666) - .055
+ }
+ var d = {
+ h: 0,
+ s: 0,
+ l: 0
+ },
+ p = {
+ h: 0,
+ s: 0,
+ l: 0
+ },
+ m = function() {
+ function Color() {}
+ var t = Color.prototype;
+ return t.copnstructor = function(t, e, r) {
+ return this.isColor = !0, this.r = 1, this.g = 1, this.b = 1, void 0 === e && void 0 === r ? this.set(t) : this.setRGB(t, e, r)
+ }, t.set = function(t) {
+ return t && t.isColor ? this.copy(t) : "number" == typeof t ? this.setHex(t) : "string" == typeof t && this.setStyle(t), this
+ }, t.setScalar = function(t) {
+ return this.r = t, this.g = t, this.b = t, this
+ }, t.setHex = function(t) {
+ return t = Math.floor(t), this.r = (t >> 16 & 255) / 255, this.g = (t >> 8 & 255) / 255, this.b = (255 & t) / 255, this
+ }, t.setRGB = function(t, e, r) {
+ return this.r = t, this.g = e, this.b = r, this
+ }, t.setHSL = function(t, e, r) {
+ if (t = euclideanModulo(t, 1), e = Math_clamp(e, 0, 1), r = Math_clamp(r, 0, 1), 0 === e) this.r = this.g = this.b = r;
+ else {
+ var n = r <= .5 ? r * (1 + e) : r + e - r * e,
+ i = 2 * r - n;
+ this.r = hue2rgb(i, n, t + 1 / 3), this.g = hue2rgb(i, n, t), this.b = hue2rgb(i, n, t - 1 / 3)
+ }
+ return this
+ }, t.setStyle = function(t) {
+ function handleAlpha(t) {
+ void 0 !== t && parseFloat(t)
+ }
+ var e;
+ if (e = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(t)) {
+ var r, n = e[1],
+ i = e[2];
+ switch (n) {
+ case "rgb":
+ case "rgba":
+ if (r = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(i)) return this.r = Math.min(255, parseInt(r[1], 10)) / 255, this.g = Math.min(255, parseInt(r[2], 10)) / 255, this.b = Math.min(255, parseInt(r[3], 10)) / 255, handleAlpha(r[5]), this;
+ if (r = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(i)) return this.r = Math.min(100, parseInt(r[1], 10)) / 100, this.g = Math.min(100, parseInt(r[2], 10)) / 100, this.b = Math.min(100, parseInt(r[3], 10)) / 100, handleAlpha(r[5]), this;
+ break;
+ case "hsl":
+ case "hsla":
+ if (r = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(i)) {
+ var o = parseFloat(r[1]) / 360,
+ a = parseInt(r[2], 10) / 100,
+ s = parseInt(r[3], 10) / 100;
+ return handleAlpha(r[5]), this.setHSL(o, a, s)
+ }
+ }
+ } else if (e = /^\#([A-Fa-f0-9]+)$/.exec(t)) {
+ var u = e[1],
+ h = u.length;
+ if (3 === h) return this.r = parseInt(u.charAt(0) + u.charAt(0), 16) / 255, this.g = parseInt(u.charAt(1) + u.charAt(1), 16) / 255, this.b = parseInt(u.charAt(2) + u.charAt(2), 16) / 255, this;
+ if (6 === h) return this.r = parseInt(u.charAt(0) + u.charAt(1), 16) / 255, this.g = parseInt(u.charAt(2) + u.charAt(3), 16) / 255, this.b = parseInt(u.charAt(4) + u.charAt(5), 16) / 255, this
+ }
+ if (t && 0 < t.length) {
+ var c = f[t];
+ void 0 !== c && this.setHex(c)
+ }
+ return this
+ }, t.clone = function() {
+ return new this.constructor(this.r, this.g, this.b)
+ }, t.copy = function(t) {
+ return this.r = t.r, this.g = t.g, this.b = t.b, this
+ }, t.copyGammaToLinear = function(t, e) {
+ return void 0 === e && (e = 2), this.r = Math.pow(t.r, e), this.g = Math.pow(t.g, e), this.b = Math.pow(t.b, e), this
+ }, t.copyLinearToGamma = function(t, e) {
+ void 0 === e && (e = 2);
+ var r = 0 < e ? 1 / e : 1;
+ return this.r = Math.pow(t.r, r), this.g = Math.pow(t.g, r), this.b = Math.pow(t.b, r), this
+ }, t.convertGammaToLinear = function(t) {
+ return this.copyGammaToLinear(this, t), this
+ }, t.convertLinearToGamma = function(t) {
+ return this.copyLinearToGamma(this, t), this
+ }, t.copySRGBToLinear = function(t) {
+ return this.r = SRGBToLinear(t.r), this.g = SRGBToLinear(t.g), this.b = SRGBToLinear(t.b), this
+ }, t.copyLinearToSRGB = function(t) {
+ this.r = LinearToSRGB(t.r), this.g = LinearToSRGB(t.g), this.b = LinearToSRGB(t.b)
+ }, t.convertSRGBToLinear = function() {
+ return this.copySRGBToLinear(this), this
+ }, t.convertLinearToSRGB = function() {
+ return this.copyLinearToSRGB(this), this
+ }, t.getHex = function() {
+ return 255 * this.r << 16 ^ 255 * this.g << 8 ^ 255 * this.b << 0
+ }, t.getHexString = function() {
+ return ("000000" + this.getHex().toString(16)).slice(-6)
+ }, t.getHSL = function(t) {
+ void 0 === t && (t = {
+ h: 0,
+ s: 0,
+ l: 0
+ });
+ var e, r, n = this.r,
+ i = this.g,
+ o = this.b,
+ a = Math.max(n, i, o),
+ s = Math.min(n, i, o),
+ u = (s + a) / 2;
+ if (s === a) r = e = 0;
+ else {
+ var h = a - s;
+ switch (r = u <= .5 ? h / (a + s) : h / (2 - a - s), a) {
+ case n:
+ e = (i - o) / h + (i < o ? 6 : 0);
+ break;
+ case i:
+ e = (o - n) / h + 2;
+ break;
+ case o:
+ e = (n - i) / h + 4
+ }
+ e /= 6
+ }
+ return t.h = e, t.s = r, t.l = u, t
+ }, t.getStyle = function() {
+ return "rgb(" + (255 * this.r | 0) + "," + (255 * this.g | 0) + "," + (255 * this.b | 0) + ")"
+ }, t.offsetHSL = function(t, e, r) {
+ var n = tempHsl;
+ return this.getHSL(n), n.h += t, n.s += e, n.l += r, this.setHSL(n.h, n.s, n.l), this
+ }, t.add = function(t) {
+ return this.r += t.r, this.g += t.g, this.b += t.b, this
+ }, t.addColors = function(t, e) {
+ return this.r = t.r + e.r, this.g = t.g + e.g, this.b = t.b + e.b, this
+ }, t.addScalar = function(t) {
+ return this.r += t, this.g += t, this.b += t, this
+ }, t.sub = function(t) {
+ return this.r = Math.max(0, this.r - t.r), this.g = Math.max(0, this.g - t.g), this.b = Math.max(0, this.b - t.b), this
+ }, t.multiply = function(t) {
+ return this.r *= t.r, this.g *= t.g, this.b *= t.b, this
+ }, t.multiplyScalar = function(t) {
+ return this.r *= t, this.g *= t, this.b *= t, this
+ }, t.lerp = function(t, e) {
+ return this.r += (t.r - this.r) * e, this.g += (t.g - this.g) * e, this.b += (t.b - this.b) * e, this
+ }, t.lerpHSL = function(t, e) {
+ var r = d,
+ n = p;
+ this.getHSL(r), t.getHSL(n);
+ var i = lerp(r.h, n.h, e),
+ o = lerp(r.s, n.s, e),
+ a = lerp(r.l, n.l, e);
+ return this.setHSL(i, o, a), this
+ }, t.equals = function(t) {
+ return t.r === this.r && t.g === this.g && t.b === this.b
+ }, t.fromArray = function(t, e) {
+ return void 0 === e && (e = 0), this.r = t[e], this.g = t[e + 1], this.b = t[e + 2], this
+ }, t.toArray = function(t, e) {
+ return void 0 === t && (t = []), void 0 === e && (e = 0), t[e] = this.r, t[e + 1] = this.g, t[e + 2] = this.b, t
+ }, t.toJSON = function() {
+ return this.getHex()
+ }, Color
+ }(),
+ v = function() {
+ function Vector3(t, e, r) {
+ this.x = t || 0, this.y = e || 0, this.z = r || 0, this.isVector3 = !0
+ }
+ var t = Vector3.prototype;
+ return t.set = function(t, e, r) {
+ return this.x = t, this.y = e, this.z = r, this
+ }, t.setScalar = function(t) {
+ return this.x = t, this.y = t, this.z = t, this
+ }, t.setX = function(t) {
+ return this.x = t, this
+ }, t.setY = function(t) {
+ return this.y = t, this
+ }, t.setZ = function(t) {
+ return this.z = t, this
+ }, t.setComponent = function(t, e) {
+ switch (t) {
+ case 0:
+ this.x = e;
+ break;
+ case 1:
+ this.y = e;
+ break;
+ case 2:
+ this.z = e;
+ break;
+ default:
+ throw new Error("index is out of range: " + t)
+ }
+ return this
+ }, t.getComponent = function(t) {
+ switch (t) {
+ case 0:
+ return this.x;
+ case 1:
+ return this.y;
+ case 2:
+ return this.z;
+ default:
+ throw new Error("index is out of range: " + t)
+ }
+ }, t.clone = function() {
+ return new this.constructor(this.x, this.y, this.z)
+ }, t.copy = function(t) {
+ return this.x = t.x, this.y = t.y, this.z = t.z, this
+ }, t.add = function(t, e) {
+ return void 0 !== e ? this.addVectors(t, e) : (this.x += t.x, this.y += t.y, this.z += t.z, this)
+ }, t.addScalar = function(t) {
+ return this.x += t, this.y += t, this.z += t, this
+ }, t.addVectors = function(t, e) {
+ return this.x = t.x + e.x, this.y = t.y + e.y, this.z = t.z + e.z, this
+ }, t.addScaledVector = function(t, e) {
+ return this.x += t.x * e, this.y += t.y * e, this.z += t.z * e, this
+ }, t.sub = function(t, e) {
+ return void 0 !== e ? this.subVectors(t, e) : (this.x -= t.x, this.y -= t.y, this.z -= t.z, this)
+ }, t.subScalar = function(t) {
+ return this.x -= t, this.y -= t, this.z -= t, this
+ }, t.subVectors = function(t, e) {
+ return this.x = t.x - e.x, this.y = t.y - e.y, this.z = t.z - e.z, this
+ }, t.multiply = function(t, e) {
+ return void 0 !== e ? this.multiplyVectors(t, e) : (this.x *= t.x, this.y *= t.y, this.z *= t.z, this)
+ }, t.multiplyScalar = function(t) {
+ return this.x *= t, this.y *= t, this.z *= t, this
+ }, t.multiplyVectors = function(t, e) {
+ return this.x = t.x * e.x, this.y = t.y * e.y, this.z = t.z * e.z, this
+ }, t.applyMatrix3 = function(t) {
+ var e = this.x,
+ r = this.y,
+ n = this.z,
+ i = t.elements;
+ return this.x = i[0] * e + i[3] * r + i[6] * n, this.y = i[1] * e + i[4] * r + i[7] * n, this.z = i[2] * e + i[5] * r + i[8] * n, this
+ }, t.applyMatrix4 = function(t) {
+ var e = this.x,
+ r = this.y,
+ n = this.z,
+ i = t.elements,
+ o = 1 / (i[3] * e + i[7] * r + i[11] * n + i[15]);
+ return this.x = (i[0] * e + i[4] * r + i[8] * n + i[12]) * o, this.y = (i[1] * e + i[5] * r + i[9] * n + i[13]) * o, this.z = (i[2] * e + i[6] * r + i[10] * n + i[14]) * o, this
+ }, t.applyQuaternion = function(t) {
+ var e = this.x,
+ r = this.y,
+ n = this.z,
+ i = t.x,
+ o = t.y,
+ a = t.z,
+ s = t.w,
+ u = s * e + o * n - a * r,
+ h = s * r + a * e - i * n,
+ c = s * n + i * r - o * e,
+ l = -i * e - o * r - a * n;
+ return this.x = u * s + l * -i + h * -a - c * -o, this.y = h * s + l * -o + c * -i - u * -a, this.z = c * s + l * -a + u * -o - h * -i, this
+ }, t.transformDirection = function(t) {
+ var e = this.x,
+ r = this.y,
+ n = this.z,
+ i = t.elements;
+ return this.x = i[0] * e + i[4] * r + i[8] * n, this.y = i[1] * e + i[5] * r + i[9] * n, this.z = i[2] * e + i[6] * r + i[10] * n, this.normalize()
+ }, t.divide = function(t) {
+ return this.x /= t.x, this.y /= t.y, this.z /= t.z, this
+ }, t.divideScalar = function(t) {
+ return this.multiplyScalar(1 / t)
+ }, t.min = function(t) {
+ return this.x = Math.min(this.x, t.x), this.y = Math.min(this.y, t.y), this.z = Math.min(this.z, t.z), this
+ }, t.max = function(t) {
+ return this.x = Math.max(this.x, t.x), this.y = Math.max(this.y, t.y), this.z = Math.max(this.z, t.z), this
+ }, t.clamp = function(t, e) {
+ return this.x = Math.max(t.x, Math.min(e.x, this.x)), this.y = Math.max(t.y, Math.min(e.y, this.y)), this.z = Math.max(t.z, Math.min(e.z, this.z)), this
+ }, t.clampScalar = function(t, e) {
+ var r = g,
+ n = y;
+ return r.set(t, t, t), n.set(e, e, e), this.clamp(r, n)
+ }, t.clampLength = function(t, e) {
+ var r = this.length();
+ return this.divideScalar(r || 1).multiplyScalar(Math.max(t, Math.min(e, r)))
+ }, t.floor = function() {
+ return this.x = Math.floor(this.x), this.y = Math.floor(this.y), this.z = Math.floor(this.z), this
+ }, t.ceil = function() {
+ return this.x = Math.ceil(this.x), this.y = Math.ceil(this.y), this.z = Math.ceil(this.z), this
+ }, t.round = function() {
+ return this.x = Math.round(this.x), this.y = Math.round(this.y), this.z = Math.round(this.z), this
+ }, t.roundToZero = function() {
+ return this.x = this.x < 0 ? Math.ceil(this.x) : Math.floor(this.x), this.y = this.y < 0 ? Math.ceil(this.y) : Math.floor(this.y), this.z = this.z < 0 ? Math.ceil(this.z) : Math.floor(this.z), this
+ }, t.negate = function() {
+ return this.x = -this.x, this.y = -this.y, this.z = -this.z, this
+ }, t.dot = function(t) {
+ return this.x * t.x + this.y * t.y + this.z * t.z
+ }, t.lengthSq = function() {
+ return this.x * this.x + this.y * this.y + this.z * this.z
+ }, t.length = function() {
+ return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z)
+ }, t.manhattanLength = function() {
+ return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z)
+ }, t.normalize = function() {
+ return this.divideScalar(this.length() || 1)
+ }, t.setLength = function(t) {
+ return this.normalize().multiplyScalar(t)
+ }, t.lerp = function(t, e) {
+ return this.x += (t.x - this.x) * e, this.y += (t.y - this.y) * e, this.z += (t.z - this.z) * e, this
+ }, t.lerpVectors = function(t, e, r) {
+ return this.subVectors(e, t).multiplyScalar(r).add(t)
+ }, t.cross = function(t, e) {
+ return void 0 !== e ? this.crossVectors(t, e) : this.crossVectors(this, t)
+ }, t.crossVectors = function(t, e) {
+ var r = t.x,
+ n = t.y,
+ i = t.z,
+ o = e.x,
+ a = e.y,
+ s = e.z;
+ return this.x = n * s - i * a, this.y = i * o - r * s, this.z = r * a - n * o, this
+ }, t.projectOnVector = function(t) {
+ var e = t.dot(this) / t.lengthSq();
+ return this.copy(t).multiplyScalar(e)
+ }, t.projectOnPlane = function(t) {
+ var e = g;
+ return e.copy(this).projectOnVector(t), this.sub(e)
+ }, t.reflect = function(t) {
+ var e = new g;
+ return this.sub(e.copy(t).multiplyScalar(2 * this.dot(t)))
+ }, t.angleTo = function(t) {
+ var e = this.dot(t) / Math.sqrt(this.lengthSq() * t.lengthSq());
+ return Math.acos(Math_clamp(e, -1, 1))
+ }, t.distanceTo = function(t) {
+ return Math.sqrt(this.distanceToSquared(t))
+ }, t.distanceToSquared = function(t) {
+ var e = this.x - t.x,
+ r = this.y - t.y,
+ n = this.z - t.z;
+ return e * e + r * r + n * n
+ }, t.manhattanDistanceTo = function(t) {
+ return Math.abs(this.x - t.x) + Math.abs(this.y - t.y) + Math.abs(this.z - t.z)
+ }, t.setFromSpherical = function(t) {
+ return this.setFromSphericalCoords(t.radius, t.phi, t.theta)
+ }, t.setFromSphericalCoords = function(t, e, r) {
+ var n = Math.sin(e) * t;
+ return this.x = n * Math.sin(r), this.y = Math.cos(e) * t, this.z = n * Math.cos(r), this
+ }, t.setFromCylindrical = function(t) {
+ return this.setFromCylindricalCoords(t.radius, t.theta, t.y)
+ }, t.setFromCylindricalCoords = function(t, e, r) {
+ return this.x = t * Math.sin(e), this.y = r, this.z = t * Math.cos(e), this
+ }, t.setFromMatrixPosition = function(t) {
+ var e = t.elements;
+ return this.x = e[12], this.y = e[13], this.z = e[14], this
+ }, t.setFromMatrixScale = function(t) {
+ var e = this.setFromMatrixColumn(t, 0).length(),
+ r = this.setFromMatrixColumn(t, 1).length(),
+ n = this.setFromMatrixColumn(t, 2).length();
+ return this.x = e, this.y = r, this.z = n, this
+ }, t.setFromMatrixColumn = function(t, e) {
+ return this.fromArray(t.elements, 4 * e)
+ }, t.equals = function(t) {
+ return t.x === this.x && t.y === this.y && t.z === this.z
+ }, t.fromArray = function(t, e) {
+ return void 0 === e && (e = 0), this.x = t[e], this.y = t[e + 1], this.z = t[e + 2], this
+ }, t.toArray = function(t, e) {
+ return void 0 === t && (t = []), void 0 === e && (e = 0), t[e] = this.x, t[e + 1] = this.y, t[e + 2] = this.z, t
+ }, t.fromBufferAttribute = function(t, e, r) {
+ return this.x = t.getX(e), this.y = t.getY(e), this.z = t.getZ(e), this
+ }, Vector3
+ }(),
+ g = new v,
+ y = new v,
+ _ = function() {
+ function Vector4(t, e, r, n) {
+ this.x = t || 0, this.y = e || 0, this.z = r || 0, this.w = void 0 !== n ? n : 1, this.isVector4 = !0
+ }
+ var t = Vector4.prototype;
+ return t.set = function(t, e, r, n) {
+ return this.x = t, this.y = e, this.z = r, this.w = n, this
+ }, t.setScalar = function(t) {
+ return this.x = t, this.y = t, this.z = t, this.w = t, this
+ }, t.setX = function(t) {
+ return this.x = t, this
+ }, t.setY = function(t) {
+ return this.y = t, this
+ }, t.setZ = function(t) {
+ return this.z = t, this
+ }, t.setW = function(t) {
+ return this.w = t, this
+ }, t.setComponent = function(t, e) {
+ switch (t) {
+ case 0:
+ this.x = e;
+ break;
+ case 1:
+ this.y = e;
+ break;
+ case 2:
+ this.z = e;
+ break;
+ case 3:
+ this.w = e;
+ break;
+ default:
+ throw new Error("index is out of range: " + t)
+ }
+ return this
+ }, t.getComponent = function(t) {
+ switch (t) {
+ case 0:
+ return this.x;
+ case 1:
+ return this.y;
+ case 2:
+ return this.z;
+ case 3:
+ return this.w;
+ default:
+ throw new Error("index is out of range: " + t)
+ }
+ }, t.clone = function() {
+ return new this.constructor(this.x, this.y, this.z, this.w)
+ }, t.copy = function(t) {
+ return this.x = t.x, this.y = t.y, this.z = t.z, this.w = void 0 !== t.w ? t.w : 1, this
+ }, t.add = function(t, e) {
+ return void 0 !== e ? this.addVectors(t, e) : (this.x += t.x, this.y += t.y, this.z += t.z, this.w += t.w, this)
+ }, t.addScalar = function(t) {
+ return this.x += t, this.y += t, this.z += t, this.w += t, this
+ }, t.addVectors = function(t, e) {
+ return this.x = t.x + e.x, this.y = t.y + e.y, this.z = t.z + e.z, this.w = t.w + e.w, this
+ }, t.addScaledVector = function(t, e) {
+ return this.x += t.x * e, this.y += t.y * e, this.z += t.z * e, this.w += t.w * e, this
+ }, t.sub = function(t, e) {
+ return void 0 !== e ? this.subVectors(t, e) : (this.x -= t.x, this.y -= t.y, this.z -= t.z, this.w -= t.w, this)
+ }, t.subScalar = function(t) {
+ return this.x -= t, this.y -= t, this.z -= t, this.w -= t, this
+ }, t.subVectors = function(t, e) {
+ return this.x = t.x - e.x, this.y = t.y - e.y, this.z = t.z - e.z, this.w = t.w - e.w, this
+ }, t.multiplyScalar = function(t) {
+ return this.x *= t, this.y *= t, this.z *= t, this.w *= t, this
+ }, t.applyMatrix4 = function(t) {
+ var e = this.x,
+ r = this.y,
+ n = this.z,
+ i = this.w,
+ o = t.elements;
+ return this.x = o[0] * e + o[4] * r + o[8] * n + o[12] * i, this.y = o[1] * e + o[5] * r + o[9] * n + o[13] * i, this.z = o[2] * e + o[6] * r + o[10] * n + o[14] * i, this.w = o[3] * e + o[7] * r + o[11] * n + o[15] * i, this
+ }, t.divideScalar = function(t) {
+ return this.multiplyScalar(1 / t)
+ }, t.setAxisAngleFromQuaternion = function(t) {
+ this.w = 2 * Math.acos(t.w);
+ var e = Math.sqrt(1 - t.w * t.w);
+ return this.z = e < 1e-4 ? (this.x = 1, this.y = 0) : (this.x = t.x / e, this.y = t.y / e, t.z / e), this
+ }, t.setAxisAngleFromRotationMatrix = function(t) {
+ var e, r, n, i, o = t.elements,
+ a = o[0],
+ s = o[4],
+ u = o[8],
+ h = o[1],
+ c = o[5],
+ l = o[9],
+ f = o[2],
+ d = o[6],
+ p = o[10];
+ if (Math.abs(s - h) < .01 && Math.abs(u - f) < .01 && Math.abs(l - d) < .01) {
+ if (Math.abs(s + h) < .1 && Math.abs(u + f) < .1 && Math.abs(l + d) < .1 && Math.abs(a + c + p - 3) < .1) return this.set(1, 0, 0, 0), this;
+ e = Math.PI;
+ var m = (a + 1) / 2,
+ v = (c + 1) / 2,
+ g = (p + 1) / 2,
+ y = (s + h) / 4,
+ _ = (u + f) / 4,
+ b = (l + d) / 4;
+ return v < m && g < m ? i = m < .01 ? (r = 0, n = .707106781) : (n = y / (r = Math.sqrt(m)), _ / r) : g < v ? i = v < .01 ? (n = 0, r = .707106781) : (r = y / (n = Math.sqrt(v)), b / n) : g < .01 ? (n = r = .707106781, i = 0) : (r = _ / (i = Math.sqrt(g)), n = b / i), this.set(r, n, i, e), this
+ }
+ var x = Math.sqrt((d - l) * (d - l) + (u - f) * (u - f) + (h - s) * (h - s));
+ return Math.abs(x) < .001 && (x = 1), this.x = (d - l) / x, this.y = (u - f) / x, this.z = (h - s) / x, this.w = Math.acos((a + c + p - 1) / 2), this
+ }, t.min = function(t) {
+ return this.x = Math.min(this.x, t.x), this.y = Math.min(this.y, t.y), this.z = Math.min(this.z, t.z), this.w = Math.min(this.w, t.w), this
+ }, t.max = function(t) {
+ return this.x = Math.max(this.x, t.x), this.y = Math.max(this.y, t.y), this.z = Math.max(this.z, t.z), this.w = Math.max(this.w, t.w), this
+ }, t.clamp = function(t, e) {
+ return this.x = Math.max(t.x, Math.min(e.x, this.x)), this.y = Math.max(t.y, Math.min(e.y, this.y)), this.z = Math.max(t.z, Math.min(e.z, this.z)), this.w = Math.max(t.w, Math.min(e.w, this.w)), this
+ }, t.clampScalar = function(t, e) {
+ var r = b,
+ n = x;
+ return r.set(t, t, t, t), n.set(e, e, e, e), this.clamp(r, n)
+ }, t.clampLength = function(t, e) {
+ var r = this.length();
+ return this.divideScalar(r || 1).multiplyScalar(Math.max(t, Math.min(e, r)))
+ }, t.floor = function() {
+ return this.x = Math.floor(this.x), this.y = Math.floor(this.y), this.z = Math.floor(this.z), this.w = Math.floor(this.w), this
+ }, t.ceil = function() {
+ return this.x = Math.ceil(this.x), this.y = Math.ceil(this.y), this.z = Math.ceil(this.z), this.w = Math.ceil(this.w), this
+ }, t.round = function() {
+ return this.x = Math.round(this.x), this.y = Math.round(this.y), this.z = Math.round(this.z), this.w = Math.round(this.w), this
+ }, t.roundToZero = function() {
+ return this.x = this.x < 0 ? Math.ceil(this.x) : Math.floor(this.x), this.y = this.y < 0 ? Math.ceil(this.y) : Math.floor(this.y), this.z = this.z < 0 ? Math.ceil(this.z) : Math.floor(this.z), this.w = this.w < 0 ? Math.ceil(this.w) : Math.floor(this.w), this
+ }, t.negate = function() {
+ return this.x = -this.x, this.y = -this.y, this.z = -this.z, this.w = -this.w, this
+ }, t.dot = function(t) {
+ return this.x * t.x + this.y * t.y + this.z * t.z + this.w * t.w
+ }, t.lengthSq = function() {
+ return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w
+ }, t.length = function() {
+ return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w)
+ }, t.manhattanLength = function() {
+ return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z) + Math.abs(this.w)
+ }, t.normalize = function() {
+ return this.divideScalar(this.length() || 1)
+ }, t.setLength = function(t) {
+ return this.normalize().multiplyScalar(t)
+ }, t.lerp = function(t, e) {
+ return this.x += (t.x - this.x) * e, this.y += (t.y - this.y) * e, this.z += (t.z - this.z) * e, this.w += (t.w - this.w) * e, this
+ }, t.lerpVectors = function(t, e, r) {
+ return this.subVectors(e, t).multiplyScalar(r).add(t)
+ }, t.equals = function(t) {
+ return t.x === this.x && t.y === this.y && t.z === this.z && t.w === this.w
+ }, t.fromArray = function(t, e) {
+ return void 0 === e && (e = 0), this.x = t[e], this.y = t[e + 1], this.z = t[e + 2], this.w = t[e + 3], this
+ }, t.toArray = function(t, e) {
+ return void 0 === t && (t = []), void 0 === e && (e = 0), t[e] = this.x, t[e + 1] = this.y, t[e + 2] = this.z, t[e + 3] = this.w, t
+ }, t.fromBufferAttribute = function(t, e, r) {
+ return this.x = t.getX(e), this.y = t.getY(e), this.z = t.getZ(e), this.w = t.getW(e), this
+ }, Vector4
+ }(),
+ b = new _,
+ x = new _,
+ w = function() {
+ function Matrix3() {
+ this.elements = [1, 0, 0, 0, 1, 0, 0, 0, 1], arguments.length, this.isMatrix3 = !0
+ }
+ var t = Matrix3.prototype;
+ return t.set = function(t, e, r, n, i, o, a, s, u) {
+ var h = this.elements;
+ return h[0] = t, h[1] = n, h[2] = a, h[3] = e, h[4] = i, h[5] = s, h[6] = r, h[7] = o, h[8] = u, this
+ }, t.identity = function() {
+ return this.set(1, 0, 0, 0, 1, 0, 0, 0, 1), this
+ }, t.clone = function() {
+ return (new this.constructor).fromArray(this.elements)
+ }, t.copy = function(t) {
+ var e = this.elements,
+ r = t.elements;
+ return e[0] = r[0], e[1] = r[1], e[2] = r[2], e[3] = r[3], e[4] = r[4], e[5] = r[5], e[6] = r[6], e[7] = r[7], e[8] = r[8], this
+ }, t.setFromMatrix4 = function(t) {
+ var e = t.elements;
+ return this.set(e[0], e[4], e[8], e[1], e[5], e[9], e[2], e[6], e[10]), this
+ }, t.applyToBufferAttribute = function(t) {
+ for (var e = T, r = 0, n = t.count; r < n; r++) e.x = t.getX(r), e.y = t.getY(r), e.z = t.getZ(r), e.applyMatrix3(this), t.setXYZ(r, e.x, e.y, e.z);
+ return t
+ }, t.multiply = function(t) {
+ return this.multiplyMatrices(this, t)
+ }, t.premultiply = function(t) {
+ return this.multiplyMatrices(t, this)
+ }, t.multiplyMatrices = function(t, e) {
+ var r = t.elements,
+ n = e.elements,
+ i = this.elements,
+ o = r[0],
+ a = r[3],
+ s = r[6],
+ u = r[1],
+ h = r[4],
+ c = r[7],
+ l = r[2],
+ f = r[5],
+ d = r[8],
+ p = n[0],
+ m = n[3],
+ v = n[6],
+ g = n[1],
+ y = n[4],
+ _ = n[7],
+ b = n[2],
+ x = n[5],
+ w = n[8];
+ return i[0] = o * p + a * g + s * b, i[3] = o * m + a * y + s * x, i[6] = o * v + a * _ + s * w, i[1] = u * p + h * g + c * b, i[4] = u * m + h * y + c * x, i[7] = u * v + h * _ + c * w, i[2] = l * p + f * g + d * b, i[5] = l * m + f * y + d * x, i[8] = l * v + f * _ + d * w, this
+ }, t.multiplyScalar = function(t) {
+ var e = this.elements;
+ return e[0] *= t, e[3] *= t, e[6] *= t, e[1] *= t, e[4] *= t, e[7] *= t, e[2] *= t, e[5] *= t, e[8] *= t, this
+ }, t.determinant = function() {
+ var t = this.elements,
+ e = t[0],
+ r = t[1],
+ n = t[2],
+ i = t[3],
+ o = t[4],
+ a = t[5],
+ s = t[6],
+ u = t[7],
+ h = t[8];
+ return e * o * h - e * a * u - r * i * h + r * a * s + n * i * u - n * o * s
+ }, t.getInverse = function(t, e) {
+ t && t.isMatrix4;
+ var r = t.elements,
+ n = this.elements,
+ i = r[0],
+ o = r[1],
+ a = r[2],
+ s = r[3],
+ u = r[4],
+ h = r[5],
+ c = r[6],
+ l = r[7],
+ f = r[8],
+ d = f * u - h * l,
+ p = h * c - f * s,
+ m = l * s - u * c,
+ v = i * d + o * p + a * m;
+ if (0 === v) {
+ var g = "THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";
+ if (!0 === e) throw new Error(g);
+ return this.identity()
+ }
+ var y = 1 / v;
+ return n[0] = d * y, n[1] = (a * l - f * o) * y, n[2] = (h * o - a * u) * y, n[3] = p * y, n[4] = (f * i - a * c) * y, n[5] = (a * s - h * i) * y, n[6] = m * y, n[7] = (o * c - l * i) * y, n[8] = (u * i - o * s) * y, this
+ }, t.transpose = function() {
+ var t, e = this.elements;
+ return t = e[1], e[1] = e[3], e[3] = t, t = e[2], e[2] = e[6], e[6] = t, t = e[5], e[5] = e[7], e[7] = t, this
+ }, t.getNormalMatrix = function(t) {
+ return this.setFromMatrix4(t).getInverse(this).transpose()
+ }, t.transposeIntoArray = function(t) {
+ var e = this.elements;
+ return t[0] = e[0], t[1] = e[3], t[2] = e[6], t[3] = e[1], t[4] = e[4], t[5] = e[7], t[6] = e[2], t[7] = e[5], t[8] = e[8], this
+ }, t.setUvTransform = function(t, e, r, n, i, o, a) {
+ var s = Math.cos(i),
+ u = Math.sin(i);
+ this.set(r * s, r * u, -r * (s * o + u * a) + o + t, -n * u, n * s, -n * (-u * o + s * a) + a + e, 0, 0, 1)
+ }, t.scale = function(t, e) {
+ var r = this.elements;
+ return r[0] *= t, r[3] *= t, r[6] *= t, r[1] *= e, r[4] *= e, r[7] *= e, this
+ }, t.rotate = function(t) {
+ var e = Math.cos(t),
+ r = Math.sin(t),
+ n = this.elements,
+ i = n[0],
+ o = n[3],
+ a = n[6],
+ s = n[1],
+ u = n[4],
+ h = n[7];
+ return n[0] = e * i + r * s, n[3] = e * o + r * u, n[6] = e * a + r * h, n[1] = -r * i + e * s, n[4] = -r * o + e * u, n[7] = -r * a + e * h, this
+ }, t.translate = function(t, e) {
+ var r = this.elements;
+ return r[0] += t * r[2], r[3] += t * r[5], r[6] += t * r[8], r[1] += e * r[2], r[4] += e * r[5], r[7] += e * r[8], this
+ }, t.equals = function(t) {
+ for (var e = this.elements, r = t.elements, n = 0; n < 9; n++)
+ if (e[n] !== r[n]) return !1;
+ return !0
+ }, t.fromArray = function(t, e) {
+ void 0 === e && (e = 0);
+ for (var r = 0; r < 9; r++) this.elements[r] = t[r + e];
+ return this
+ }, t.toArray = function(t, e) {
+ void 0 === t && (t = []), void 0 === e && (e = 0);
+ var r = this.elements;
+ return t[e] = r[0], t[e + 1] = r[1], t[e + 2] = r[2], t[e + 3] = r[3], t[e + 4] = r[4], t[e + 5] = r[5], t[e + 6] = r[6], t[e + 7] = r[7], t[e + 8] = r[8], t
+ }, Matrix3
+ }(),
+ T = new v,
+ S = function() {
+ function Matrix4() {
+ this.elements = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], arguments.length, this.isMatrix4 = !0
+ }
+ var t = Matrix4.prototype;
+ return t.set = function(t, e, r, n, i, o, a, s, u, h, c, l, f, d, p, m) {
+ var v = this.elements;
+ return v[0] = t, v[4] = e, v[8] = r, v[12] = n, v[1] = i, v[5] = o, v[9] = a, v[13] = s, v[2] = u, v[6] = h, v[10] = c, v[14] = l, v[3] = f, v[7] = d, v[11] = p, v[15] = m, this
+ }, t.identity = function() {
+ return this.set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1), this
+ }, t.clone = function() {
+ return (new Matrix4).fromArray(this.elements)
+ }, t.copy = function(t) {
+ var e = this.elements,
+ r = t.elements;
+ return e[0] = r[0], e[1] = r[1], e[2] = r[2], e[3] = r[3], e[4] = r[4], e[5] = r[5], e[6] = r[6], e[7] = r[7], e[8] = r[8], e[9] = r[9], e[10] = r[10], e[11] = r[11], e[12] = r[12], e[13] = r[13], e[14] = r[14], e[15] = r[15], this
+ }, t.copyPosition = function(t) {
+ var e = this.elements,
+ r = t.elements;
+ return e[12] = r[12], e[13] = r[13], e[14] = r[14], this
+ }, t.extractBasis = function(t, e, r) {
+ return t.setFromMatrixColumn(this, 0), e.setFromMatrixColumn(this, 1), r.setFromMatrixColumn(this, 2), this
+ }, t.makeBasis = function(t, e, r) {
+ return this.set(t.x, e.x, r.x, 0, t.y, e.y, r.y, 0, t.z, e.z, r.z, 0, 0, 0, 0, 1), this
+ }, t.extractRotation = function(t) {
+ var e = E,
+ r = this.elements,
+ n = t.elements,
+ i = 1 / e.setFromMatrixColumn(t, 0).length(),
+ o = 1 / e.setFromMatrixColumn(t, 1).length(),
+ a = 1 / e.setFromMatrixColumn(t, 2).length();
+ return r[0] = n[0] * i, r[1] = n[1] * i, r[2] = n[2] * i, r[3] = 0, r[4] = n[4] * o, r[5] = n[5] * o, r[6] = n[6] * o, r[7] = 0, r[8] = n[8] * a, r[9] = n[9] * a, r[10] = n[10] * a, r[11] = 0, r[12] = 0, r[13] = 0, r[14] = 0, r[15] = 1, this
+ }, t.makeRotationFromEuler = function(t) {
+ !t || t.isEuler;
+ var e = this.elements,
+ r = t.x,
+ n = t.y,
+ i = t.z,
+ o = Math.cos(r),
+ a = Math.sin(r),
+ s = Math.cos(n),
+ u = Math.sin(n),
+ h = Math.cos(i),
+ c = Math.sin(i);
+ if ("XYZ" === t.order) {
+ var l = o * h,
+ f = o * c,
+ d = a * h,
+ p = a * c;
+ e[0] = s * h, e[4] = -s * c, e[8] = u, e[1] = f + d * u, e[5] = l - p * u, e[9] = -a * s, e[2] = p - l * u, e[6] = d + f * u, e[10] = o * s
+ } else if ("YXZ" === t.order) {
+ var m = s * h,
+ v = s * c,
+ g = u * h,
+ y = u * c;
+ e[0] = m + y * a, e[4] = g * a - v, e[8] = o * u, e[1] = o * c, e[5] = o * h, e[9] = -a, e[2] = v * a - g, e[6] = y + m * a, e[10] = o * s
+ } else if ("ZXY" === t.order) {
+ var _ = s * h,
+ b = s * c,
+ x = u * h,
+ w = u * c;
+ e[0] = _ - w * a, e[4] = -o * c, e[8] = x + b * a, e[1] = b + x * a, e[5] = o * h, e[9] = w - _ * a, e[2] = -o * u, e[6] = a, e[10] = o * s
+ } else if ("ZYX" === t.order) {
+ var T = o * h,
+ S = o * c,
+ M = a * h,
+ E = a * c;
+ e[0] = s * h, e[4] = M * u - S, e[8] = T * u + E, e[1] = s * c, e[5] = E * u + T, e[9] = S * u - M, e[2] = -u, e[6] = a * s, e[10] = o * s
+ } else if ("YZX" === t.order) {
+ var A = o * s,
+ P = o * u,
+ I = a * s,
+ O = a * u;
+ e[0] = s * h, e[4] = O - A * c, e[8] = I * c + P, e[1] = c, e[5] = o * h, e[9] = -a * h, e[2] = -u * h, e[6] = P * c + I, e[10] = A - O * c
+ } else if ("XZY" === t.order) {
+ var C = o * s,
+ R = o * u,
+ D = a * s,
+ F = a * u;
+ e[0] = s * h, e[4] = -c, e[8] = u * h, e[1] = C * c + F, e[5] = o * h, e[9] = R * c - D, e[2] = D * c - R, e[6] = a * h, e[10] = F * c + C
+ }
+ return e[3] = 0, e[7] = 0, e[11] = 0, e[12] = 0, e[13] = 0, e[14] = 0, e[15] = 1, this
+ }, t.makeRotationFromQuaternion = function(t) {
+ return this.compose(I, t, O)
+ }, t.lookAt = function() {
+ var t = E,
+ e = A,
+ r = P,
+ n = this.elements;
+ return r.subVectors(eye, target), 0 === r.lengthSq() && (r.z = 1), r.normalize(), t.crossVectors(up, r), 0 === t.lengthSq() && (1 === Math.abs(up.z) ? r.x += 1e-4 : r.z += 1e-4, r.normalize(), t.crossVectors(up, r)), t.normalize(), e.crossVectors(r, t), n[0] = t.x, n[4] = e.x, n[8] = r.x, n[1] = t.y, n[5] = e.y, n[9] = r.y, n[2] = t.z, n[6] = e.z, n[10] = r.z, this
+ }, t.multiply = function(t, e) {
+ return void 0 !== e ? this.multiplyMatrices(t, e) : this.multiplyMatrices(this, t)
+ }, t.premultiply = function(t) {
+ return this.multiplyMatrices(t, this)
+ }, t.multiplyMatrices = function(t, e) {
+ var r = t.elements,
+ n = e.elements,
+ i = this.elements,
+ o = r[0],
+ a = r[4],
+ s = r[8],
+ u = r[12],
+ h = r[1],
+ c = r[5],
+ l = r[9],
+ f = r[13],
+ d = r[2],
+ p = r[6],
+ m = r[10],
+ v = r[14],
+ g = r[3],
+ y = r[7],
+ _ = r[11],
+ b = r[15],
+ x = n[0],
+ w = n[4],
+ T = n[8],
+ S = n[12],
+ M = n[1],
+ E = n[5],
+ A = n[9],
+ P = n[13],
+ I = n[2],
+ O = n[6],
+ C = n[10],
+ R = n[14],
+ D = n[3],
+ F = n[7],
+ k = n[11],
+ L = n[15];
+ return i[0] = o * x + a * M + s * I + u * D, i[4] = o * w + a * E + s * O + u * F, i[8] = o * T + a * A + s * C + u * k, i[12] = o * S + a * P + s * R + u * L, i[1] = h * x + c * M + l * I + f * D, i[5] = h * w + c * E + l * O + f * F, i[9] = h * T + c * A + l * C + f * k, i[13] = h * S + c * P + l * R + f * L, i[2] = d * x + p * M + m * I + v * D, i[6] = d * w + p * E + m * O + v * F, i[10] = d * T + p * A + m * C + v * k, i[14] = d * S + p * P + m * R + v * L, i[3] = g * x + y * M + _ * I + b * D, i[7] = g * w + y * E + _ * O + b * F, i[11] = g * T + y * A + _ * C + b * k, i[15] = g * S + y * P + _ * R + b * L, this
+ }, t.multiplyScalar = function(t) {
+ var e = this.elements;
+ return e[0] *= t, e[4] *= t, e[8] *= t, e[12] *= t, e[1] *= t, e[5] *= t, e[9] *= t, e[13] *= t, e[2] *= t, e[6] *= t, e[10] *= t, e[14] *= t, e[3] *= t, e[7] *= t, e[11] *= t, e[15] *= t, this
+ }, t.applyToBufferAttribute = function(t) {
+ for (var e = E, r = 0, n = t.count; r < n; r++) e.x = t.getX(r), e.y = t.getY(r), e.z = t.getZ(r), e.applyMatrix4(this), t.setXYZ(r, e.x, e.y, e.z);
+ return t
+ }, t.determinant = function() {
+ var t = this.elements,
+ e = t[0],
+ r = t[4],
+ n = t[8],
+ i = t[12],
+ o = t[1],
+ a = t[5],
+ s = t[9],
+ u = t[13],
+ h = t[2],
+ c = t[6],
+ l = t[10],
+ f = t[14];
+ return t[3] * (+i * s * c - n * u * c - i * a * l + r * u * l + n * a * f - r * s * f) + t[7] * (+e * s * f - e * u * l + i * o * l - n * o * f + n * u * h - i * s * h) + t[11] * (+e * u * c - e * a * f - i * o * c + r * o * f + i * a * h - r * u * h) + t[15] * (-n * a * h - e * s * c + e * a * l + n * o * c - r * o * l + r * s * h)
+ }, t.transpose = function() {
+ var t, e = this.elements;
+ return t = e[1], e[1] = e[4], e[4] = t, t = e[2], e[2] = e[8], e[8] = t, t = e[6], e[6] = e[9], e[9] = t, t = e[3], e[3] = e[12], e[12] = t, t = e[7], e[7] = e[13], e[13] = t, t = e[11], e[11] = e[14], e[14] = t, this
+ }, t.setPosition = function(t) {
+ var e = this.elements;
+ return e[12] = t.x, e[13] = t.y, e[14] = t.z, this
+ }, t.getInverse = function(t, e) {
+ var r = this.elements,
+ n = t.elements,
+ i = n[0],
+ o = n[1],
+ a = n[2],
+ s = n[3],
+ u = n[4],
+ h = n[5],
+ c = n[6],
+ l = n[7],
+ f = n[8],
+ d = n[9],
+ p = n[10],
+ m = n[11],
+ v = n[12],
+ g = n[13],
+ y = n[14],
+ _ = n[15],
+ b = d * y * l - g * p * l + g * c * m - h * y * m - d * c * _ + h * p * _,
+ x = v * p * l - f * y * l - v * c * m + u * y * m + f * c * _ - u * p * _,
+ w = f * g * l - v * d * l + v * h * m - u * g * m - f * h * _ + u * d * _,
+ T = v * d * c - f * g * c - v * h * p + u * g * p + f * h * y - u * d * y,
+ S = i * b + o * x + a * w + s * T;
+ if (0 === S) {
+ var M = "THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0";
+ if (!0 === e) throw new Error(M);
+ return this.identity()
+ }
+ var E = 1 / S;
+ return r[0] = b * E, r[1] = (g * p * s - d * y * s - g * a * m + o * y * m + d * a * _ - o * p * _) * E, r[2] = (h * y * s - g * c * s + g * a * l - o * y * l - h * a * _ + o * c * _) * E, r[3] = (d * c * s - h * p * s - d * a * l + o * p * l + h * a * m - o * c * m) * E, r[4] = x * E, r[5] = (f * y * s - v * p * s + v * a * m - i * y * m - f * a * _ + i * p * _) * E, r[6] = (v * c * s - u * y * s - v * a * l + i * y * l + u * a * _ - i * c * _) * E, r[7] = (u * p * s - f * c * s + f * a * l - i * p * l - u * a * m + i * c * m) * E, r[8] = w * E, r[9] = (v * d * s - f * g * s - v * o * m + i * g * m + f * o * _ - i * d * _) * E, r[10] = (u * g * s - v * h * s + v * o * l - i * g * l - u * o * _ + i * h * _) * E, r[11] = (f * h * s - u * d * s - f * o * l + i * d * l + u * o * m - i * h * m) * E, r[12] = T * E, r[13] = (f * g * a - v * d * a + v * o * p - i * g * p - f * o * y + i * d * y) * E, r[14] = (v * h * a - u * g * a - v * o * c + i * g * c + u * o * y - i * h * y) * E, r[15] = (u * d * a - f * h * a + f * o * c - i * d * c - u * o * p + i * h * p) * E, this
+ }, t.scale = function(t) {
+ var e = this.elements,
+ r = t.x,
+ n = t.y,
+ i = t.z;
+ return e[0] *= r, e[4] *= n, e[8] *= i, e[1] *= r, e[5] *= n, e[9] *= i, e[2] *= r, e[6] *= n, e[10] *= i, e[3] *= r, e[7] *= n, e[11] *= i, this
+ }, t.getMaxScaleOnAxis = function() {
+ var t = this.elements,
+ e = t[0] * t[0] + t[1] * t[1] + t[2] * t[2],
+ r = t[4] * t[4] + t[5] * t[5] + t[6] * t[6],
+ n = t[8] * t[8] + t[9] * t[9] + t[10] * t[10];
+ return Math.sqrt(Math.max(e, r, n))
+ }, t.makeTranslation = function(t, e, r) {
+ return this.set(1, 0, 0, t, 0, 1, 0, e, 0, 0, 1, r, 0, 0, 0, 1), this
+ }, t.makeRotationX = function(t) {
+ var e = Math.cos(t),
+ r = Math.sin(t);
+ return this.set(1, 0, 0, 0, 0, e, -r, 0, 0, r, e, 0, 0, 0, 0, 1), this
+ }, t.makeRotationY = function(t) {
+ var e = Math.cos(t),
+ r = Math.sin(t);
+ return this.set(e, 0, r, 0, 0, 1, 0, 0, -r, 0, e, 0, 0, 0, 0, 1), this
+ }, t.makeRotationZ = function(t) {
+ var e = Math.cos(t),
+ r = Math.sin(t);
+ return this.set(e, -r, 0, 0, r, e, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1), this
+ }, t.makeRotationAxis = function(t, e) {
+ var r = Math.cos(e),
+ n = Math.sin(e),
+ i = 1 - r,
+ o = t.x,
+ a = t.y,
+ s = t.z,
+ u = i * o,
+ h = i * a;
+ return this.set(u * o + r, u * a - n * s, u * s + n * a, 0, u * a + n * s, h * a + r, h * s - n * o, 0, u * s - n * a, h * s + n * o, i * s * s + r, 0, 0, 0, 0, 1), this
+ }, t.makeScale = function(t, e, r) {
+ return this.set(t, 0, 0, 0, 0, e, 0, 0, 0, 0, r, 0, 0, 0, 0, 1), this
+ }, t.makeShear = function(t, e, r) {
+ return this.set(1, e, r, 0, t, 1, r, 0, t, e, 1, 0, 0, 0, 0, 1), this
+ }, t.compose = function(t, e, r) {
+ var n = this.elements,
+ i = e._x,
+ o = e._y,
+ a = e._z,
+ s = e._w,
+ u = i + i,
+ h = o + o,
+ c = a + a,
+ l = i * u,
+ f = i * h,
+ d = i * c,
+ p = o * h,
+ m = o * c,
+ v = a * c,
+ g = s * u,
+ y = s * h,
+ _ = s * c,
+ b = r.x,
+ x = r.y,
+ w = r.z;
+ return n[0] = (1 - (p + v)) * b, n[1] = (f + _) * b, n[2] = (d - y) * b, n[3] = 0, n[4] = (f - _) * x, n[5] = (1 - (l + v)) * x, n[6] = (m + g) * x, n[7] = 0, n[8] = (d + y) * w, n[9] = (m - g) * w, n[10] = (1 - (l + p)) * w, n[11] = 0, n[12] = t.x, n[13] = t.y, n[14] = t.z, n[15] = 1, this
+ }, t.decompose = function(t, e, r) {
+ var n = E,
+ i = M,
+ o = this.elements,
+ a = n.set(o[0], o[1], o[2]).length(),
+ s = n.set(o[4], o[5], o[6]).length(),
+ u = n.set(o[8], o[9], o[10]).length();
+ this.determinant() < 0 && (a = -a), t.x = o[12], t.y = o[13], t.z = o[14], i.copy(this);
+ var h = 1 / a,
+ c = 1 / s,
+ l = 1 / u;
+ return i.elements[0] *= h, i.elements[1] *= h, i.elements[2] *= h, i.elements[4] *= c, i.elements[5] *= c, i.elements[6] *= c, i.elements[8] *= l, i.elements[9] *= l, i.elements[10] *= l, e.setFromRotationMatrix(i), r.x = a, r.y = s, r.z = u, this
+ }, t.makePerspective = function(t, e, r, n, i, o) {
+ var a = this.elements,
+ s = 2 * i / (e - t),
+ u = 2 * i / (r - n),
+ h = (e + t) / (e - t),
+ c = (r + n) / (r - n),
+ l = -(o + i) / (o - i),
+ f = -2 * o * i / (o - i);
+ return a[0] = s, a[4] = 0, a[8] = h, a[12] = 0, a[1] = 0, a[5] = u, a[9] = c, a[13] = 0, a[2] = 0, a[6] = 0, a[10] = l, a[14] = f, a[3] = 0, a[7] = 0, a[11] = -1, a[15] = 0, this
+ }, t.makeOrthographic = function(t, e, r, n, i, o) {
+ var a = this.elements,
+ s = 1 / (e - t),
+ u = 1 / (r - n),
+ h = 1 / (o - i),
+ c = (e + t) * s,
+ l = (r + n) * u,
+ f = (o + i) * h;
+ return a[0] = 2 * s, a[4] = 0, a[8] = 0, a[12] = -c, a[1] = 0, a[5] = 2 * u, a[9] = 0, a[13] = -l, a[2] = 0, a[6] = 0, a[10] = -2 * h, a[14] = -f, a[3] = 0, a[7] = 0, a[11] = 0, a[15] = 1, this
+ }, t.equals = function(t) {
+ for (var e = this.elements, r = t.elements, n = 0; n < 16; n++)
+ if (e[n] !== r[n]) return !1;
+ return !0
+ }, t.fromArray = function(t, e) {
+ void 0 === e && (e = 0);
+ for (var r = 0; r < 16; r++) this.elements[r] = t[r + e];
+ return this
+ }, t.toArray = function(t, e) {
+ void 0 === t && (t = []), void 0 === e && (e = 0);
+ var r = this.elements;
+ return t[e] = r[0], t[e + 1] = r[1], t[e + 2] = r[2], t[e + 3] = r[3], t[e + 4] = r[4], t[e + 5] = r[5], t[e + 6] = r[6], t[e + 7] = r[7], t[e + 8] = r[8], t[e + 9] = r[9], t[e + 10] = r[10], t[e + 11] = r[11], t[e + 12] = r[12], t[e + 13] = r[13], t[e + 14] = r[14], t[e + 15] = r[15], t
+ }, Matrix4
+ }(),
+ M = new S,
+ E = new v,
+ A = new v,
+ P = new v,
+ I = new v(0, 0, 0),
+ O = new v(1, 1, 1);
+
+ function Quaternion_defineProperties(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n)
+ }
+ }
+ v.prototype.project = function(t) {
+ return this.applyMatrix4(t.matrixWorldInverse).applyMatrix4(t.projectionMatrix)
+ }, v.prototype.unproject = function(t) {
+ var e = M;
+ return this.applyMatrix4(e.getInverse(t.projectionMatrix)).applyMatrix4(t.matrixWorld)
+ };
+ var C = function() {
+ function Quaternion(t, e, r, n) {
+ this._x = t || 0, this._y = e || 0, this._z = r || 0, this._w = void 0 !== n ? n : 1, this.isQuaternion = !0
+ }
+ var t, e, r, n = Quaternion.prototype;
+ return n.slerp = function(t, e, r, n) {
+ return r.copy(t).slerp(e, n)
+ }, Quaternion.slerpFlat = function(t, e, r, n, i, o, a) {
+ var s = r[n + 0],
+ u = r[n + 1],
+ h = r[n + 2],
+ c = r[n + 3],
+ l = i[o + 0],
+ f = i[o + 1],
+ d = i[o + 2],
+ p = i[o + 3];
+ if (c !== p || s !== l || u !== f || h !== d) {
+ var m = 1 - a,
+ v = s * l + u * f + h * d + c * p,
+ g = 0 <= v ? 1 : -1,
+ y = 1 - v * v;
+ if (y > Number.EPSILON) {
+ var _ = Math.sqrt(y),
+ b = Math.atan2(_, v * g);
+ m = Math.sin(m * b) / _, a = Math.sin(a * b) / _
+ }
+ var x = a * g;
+ if (s = s * m + l * x, u = u * m + f * x, h = h * m + d * x, c = c * m + p * x, m === 1 - a) {
+ var w = 1 / Math.sqrt(s * s + u * u + h * h + c * c);
+ s *= w, u *= w, h *= w, c *= w
+ }
+ }
+ t[e] = s, t[e + 1] = u, t[e + 2] = h, t[e + 3] = c
+ }, n.set = function(t, e, r, n) {
+ return this._x = t, this._y = e, this._z = r, this._w = n, this.onChangeCallback(), this
+ }, n.clone = function() {
+ return new this.constructor(this._x, this._y, this._z, this._w)
+ }, n.copy = function(t) {
+ return this._x = t.x, this._y = t.y, this._z = t.z, this._w = t.w, this.onChangeCallback(), this
+ }, n.setFromEuler = function(t, e) {
+ if (!t || !t.isEuler) throw new Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.");
+ var r = t._x,
+ n = t._y,
+ i = t._z,
+ o = t.order,
+ a = Math.cos,
+ s = Math.sin,
+ u = a(r / 2),
+ h = a(n / 2),
+ c = a(i / 2),
+ l = s(r / 2),
+ f = s(n / 2),
+ d = s(i / 2);
+ return "XYZ" === o ? (this._x = l * h * c + u * f * d, this._y = u * f * c - l * h * d, this._z = u * h * d + l * f * c, this._w = u * h * c - l * f * d) : "YXZ" === o ? (this._x = l * h * c + u * f * d, this._y = u * f * c - l * h * d, this._z = u * h * d - l * f * c, this._w = u * h * c + l * f * d) : "ZXY" === o ? (this._x = l * h * c - u * f * d, this._y = u * f * c + l * h * d, this._z = u * h * d + l * f * c, this._w = u * h * c - l * f * d) : "ZYX" === o ? (this._x = l * h * c - u * f * d, this._y = u * f * c + l * h * d, this._z = u * h * d - l * f * c, this._w = u * h * c + l * f * d) : "YZX" === o ? (this._x = l * h * c + u * f * d, this._y = u * f * c + l * h * d, this._z = u * h * d - l * f * c, this._w = u * h * c - l * f * d) : "XZY" === o && (this._x = l * h * c - u * f * d, this._y = u * f * c - l * h * d, this._z = u * h * d + l * f * c, this._w = u * h * c + l * f * d), !1 !== e && this.onChangeCallback(), this
+ }, n.setFromAxisAngle = function(t, e) {
+ var r = e / 2,
+ n = Math.sin(r);
+ return this._x = t.x * n, this._y = t.y * n, this._z = t.z * n, this._w = Math.cos(r), this.onChangeCallback(), this
+ }, n.setFromRotationMatrix = function(t) {
+ var e, r = t.elements,
+ n = r[0],
+ i = r[4],
+ o = r[8],
+ a = r[1],
+ s = r[5],
+ u = r[9],
+ h = r[2],
+ c = r[6],
+ l = r[10],
+ f = n + s + l;
+ return this._z = 0 < f ? (e = .5 / Math.sqrt(f + 1), this._w = .25 / e, this._x = (c - u) * e, this._y = (o - h) * e, (a - i) * e) : s < n && l < n ? (e = 2 * Math.sqrt(1 + n - s - l), this._w = (c - u) / e, this._x = .25 * e, this._y = (i + a) / e, (o + h) / e) : l < s ? (e = 2 * Math.sqrt(1 + s - n - l), this._w = (o - h) / e, this._x = (i + a) / e, this._y = .25 * e, (u + c) / e) : (e = 2 * Math.sqrt(1 + l - n - s), this._w = (a - i) / e, this._x = (o + h) / e, this._y = (u + c) / e, .25 * e), this.onChangeCallback(), this
+ }, n.setFromUnitVectors = function(t, e) {
+ var r, n = R;
+ return (r = t.dot(e) + 1) < 1e-6 ? (r = 0, Math.abs(t.x) > Math.abs(t.z) ? n.set(-t.y, t.x, 0) : n.set(0, -t.z, t.y)) : n.crossVectors(t, e), this._x = n.x, this._y = n.y, this._z = n.z, this._w = r, this.normalize()
+ }, n.angleTo = function(t) {
+ return 2 * Math.acos(Math.abs(Math_clamp(this.dot(t), -1, 1)))
+ }, n.rotateTowards = function(t, e) {
+ var r = this.angleTo(t);
+ if (0 === r) return this;
+ var n = Math.min(1, e / r);
+ return this.slerp(t, n), this
+ }, n.inverse = function() {
+ return this.conjugate()
+ }, n.conjugate = function() {
+ return this._x *= -1, this._y *= -1, this._z *= -1, this.onChangeCallback(), this
+ }, n.dot = function(t) {
+ return this._x * t._x + this._y * t._y + this._z * t._z + this._w * t._w
+ }, n.lengthSq = function() {
+ return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w
+ }, n.length = function() {
+ return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w)
+ }, n.normalize = function() {
+ var t = this.length();
+ return this._w = 0 === t ? (this._x = 0, this._y = 0, this._z = 0, 1) : (t = 1 / t, this._x = this._x * t, this._y = this._y * t, this._z = this._z * t, this._w * t), this.onChangeCallback(), this
+ }, n.multiply = function(t, e) {
+ return void 0 !== e ? this.multiplyQuaternions(t, e) : this.multiplyQuaternions(this, t)
+ }, n.premultiply = function(t) {
+ return this.multiplyQuaternions(t, this)
+ }, n.multiplyQuaternions = function(t, e) {
+ var r = t._x,
+ n = t._y,
+ i = t._z,
+ o = t._w,
+ a = e._x,
+ s = e._y,
+ u = e._z,
+ h = e._w;
+ return this._x = r * h + o * a + n * u - i * s, this._y = n * h + o * s + i * a - r * u, this._z = i * h + o * u + r * s - n * a, this._w = o * h - r * a - n * s - i * u, this.onChangeCallback(), this
+ }, n.slerp = function(t, e) {
+ if (0 === e) return this;
+ if (1 === e) return this.copy(t);
+ var r = this._x,
+ n = this._y,
+ i = this._z,
+ o = this._w,
+ a = o * t._w + r * t._x + n * t._y + i * t._z;
+ if (a < 0 ? (this._w = -t._w, this._x = -t._x, this._y = -t._y, this._z = -t._z, a = -a) : this.copy(t), 1 <= a) return this._w = o, this._x = r, this._y = n, this._z = i, this;
+ var s = 1 - a * a;
+ if (s <= Number.EPSILON) {
+ var u = 1 - e;
+ return this._w = u * o + e * this._w, this._x = u * r + e * this._x, this._y = u * n + e * this._y, this._z = u * i + e * this._z, this.normalize()
+ }
+ var h = Math.sqrt(s),
+ c = Math.atan2(h, a),
+ l = Math.sin((1 - e) * c) / h,
+ f = Math.sin(e * c) / h;
+ return this._w = o * l + this._w * f, this._x = r * l + this._x * f, this._y = n * l + this._y * f, this._z = i * l + this._z * f, this.onChangeCallback(), this
+ }, n.equals = function(t) {
+ return t._x === this._x && t._y === this._y && t._z === this._z && t._w === this._w
+ }, n.fromArray = function(t, e) {
+ return void 0 === e && (e = 0), this._x = t[e], this._y = t[e + 1], this._z = t[e + 2], this._w = t[e + 3], this.onChangeCallback(), this
+ }, n.toArray = function(t, e) {
+ return void 0 === t && (t = []), void 0 === e && (e = 0), t[e] = this._x, t[e + 1] = this._y, t[e + 2] = this._z, t[e + 3] = this._w, t
+ }, n.onChange = function(t) {
+ return this.onChangeCallback = t, this
+ }, n.onChangeCallback = function() {}, t = Quaternion, (e = [{
+ key: "x",
+ get: function() {
+ return this._z
+ },
+ set: function(t) {
+ this._x = t, this.onChangeCallback()
+ }
+ }, {
+ key: "y",
+ get: function() {
+ return this._y
+ },
+ set: function(t) {
+ this._y = t, this.onChangeCallback()
+ }
+ }, {
+ key: "z",
+ set: function(t) {
+ this._z = t, this.onChangeCallback()
+ }
+ }, {
+ key: "w",
+ get: function() {
+ return this._w
+ },
+ set: function(t) {
+ this._w = t, this.onChangeCallback()
+ }
+ }]) && Quaternion_defineProperties(t.prototype, e), r && Quaternion_defineProperties(t, r), Quaternion
+ }(),
+ R = new v,
+ D = new C;
+
+ function Euler_defineProperties(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n)
+ }
+ }
+ v.prototype.applyEuler = function(t) {
+ var e = D;
+ return !t || t.isEuler, this.applyQuaternion(e.setFromEuler(t))
+ }, v.prototype.applyAxisAngle = function(t, e) {
+ var r = D;
+ return this.applyQuaternion(r.setFromAxisAngle(t, e))
+ };
+ var F = function() {
+ function Euler(t, e, r, n) {
+ this._x = t || 0, this._y = e || 0, this._z = r || 0, this._order = n || Euler.DefaultOrder, this.isEuler = !0
+ }
+ var t, e, r, n = Euler.prototype;
+ return n.set = function(t) {
+ this._y = t, this.onChangeCallback()
+ }, n.set = function(t, e, r, n) {
+ return this._x = t, this._y = e, this._z = r, this._order = n || this._order, this.onChangeCallback(), this
+ }, n.clone = function() {
+ return new this.constructor(this._x, this._y, this._z, this._order)
+ }, n.copy = function(t) {
+ return this._x = t._x, this._y = t._y, this._z = t._z, this._order = t._order, this.onChangeCallback(), this
+ }, n.setFromRotationMatrix = function(t, e, r) {
+ var n = Math_clamp,
+ i = t.elements,
+ o = i[0],
+ a = i[4],
+ s = i[8],
+ u = i[1],
+ h = i[5],
+ c = i[9],
+ l = i[2],
+ f = i[6],
+ d = i[10];
+ return "XYZ" === (e = e || this._order) ? (this._y = Math.asin(n(s, -1, 1)), Math.abs(s) < .99999 ? (this._x = Math.atan2(-c, d), this._z = Math.atan2(-a, o)) : (this._x = Math.atan2(f, h), this._z = 0)) : "YXZ" === e ? (this._x = Math.asin(-n(c, -1, 1)), Math.abs(c) < .99999 ? (this._y = Math.atan2(s, d), this._z = Math.atan2(u, h)) : (this._y = Math.atan2(-l, o), this._z = 0)) : "ZXY" === e ? (this._x = Math.asin(n(f, -1, 1)), Math.abs(f) < .99999 ? (this._y = Math.atan2(-l, d), this._z = Math.atan2(-a, h)) : (this._y = 0, this._z = Math.atan2(u, o))) : "ZYX" === e ? (this._y = Math.asin(-n(l, -1, 1)), Math.abs(l) < .99999 ? (this._x = Math.atan2(f, d), this._z = Math.atan2(u, o)) : (this._x = 0, this._z = Math.atan2(-a, h))) : "YZX" === e ? (this._z = Math.asin(n(u, -1, 1)), Math.abs(u) < .99999 ? (this._x = Math.atan2(-c, h), this._y = Math.atan2(-l, o)) : (this._x = 0, this._y = Math.atan2(s, d))) : "XZY" === e && (this._z = Math.asin(-n(a, -1, 1)), Math.abs(a) < .99999 ? (this._x = Math.atan2(f, h), this._y = Math.atan2(s, o)) : (this._x = Math.atan2(-c, d), this._y = 0)), this._order = e, !1 !== r && this.onChangeCallback(), this
+ }, n.setFromQuaternion = function(t, e, r) {
+ return L.makeRotationFromQuaternion(t), this.setFromRotationMatrix(L, e, r)
+ }, n.setFromVector3 = function(t, e) {
+ return this.set(t.x, t.y, t.z, e || this._order)
+ }, n.reorder = function(t) {
+ return N.setFromEuler(this), this.setFromQuaternion(N, t)
+ }, n.equals = function(t) {
+ return t._x === this._x && t._y === this._y && t._z === this._z && t._order === this._order
+ }, n.fromArray = function(t) {
+ return this._x = t[0], this._y = t[1], this._z = t[2], void 0 !== t[3] && (this._order = t[3]), this.onChangeCallback(), this
+ }, n.toArray = function(t, e) {
+ return void 0 === t && (t = []), void 0 === e && (e = 0), t[e] = this._x, t[e + 1] = this._y, t[e + 2] = this._z, t[e + 3] = this._order, t
+ }, n.toVector3 = function(t) {
+ return t ? t.set(this._x, this._y, this._z) : new v(this._x, this._y, this._z)
+ }, n.onChange = function(t) {
+ return this.onChangeCallback = t, this
+ }, n.onChangeCallback = function() {}, t = Euler, (e = [{
+ key: "x",
+ get: function() {
+ return this._x
+ },
+ set: function(t) {
+ this._z = t, this.onChangeCallback()
+ }
+ }, {
+ key: "y",
+ get: function() {
+ return this._y
+ }
+ }, {
+ key: "z",
+ get: function() {
+ return this._z
+ }
+ }, {
+ key: "order",
+ get: function() {
+ return this._order
+ },
+ set: function(t) {
+ this._order = t, this.onChangeCallback()
+ }
+ }]) && Euler_defineProperties(t.prototype, e), r && Euler_defineProperties(t, r), Euler
+ }(),
+ L = new S,
+ N = new C;
+ F.RotationOrders = ["XYZ", "YZX", "ZXY", "XZY", "YXZ", "ZYX"], F.DefaultOrder = "XYZ";
+ var B = r(37),
+ U = r.n(B),
+ G = r(45),
+ j = r.n(G),
+ z = r(179),
+ X = r.n(z);
+ U.a.prototype.setValues = function(t) {};
+ var V = function() {
+ function Interpolant(t, e, r, n) {
+ this.parameterPositions = t, this._cachedIndex = 0, this.resultBuffer = void 0 !== n ? n : new e.constructor(r), this.sampleValues = e, this.valueSize = r, this.settings = null, this.DefaultSettings_ = {}
+ }
+ var t = Interpolant.prototype;
+ return t.evaluate = function(t) {
+ var e = this.parameterPositions,
+ r = this._cachedIndex,
+ n = e[r],
+ i = e[r - 1];
+ t: {
+ e: {
+ var o;r: {
+ n: if (!(t < n)) {
+ for (var a = r + 2;;) {
+ if (void 0 === n) {
+ if (t < i) break n;
+ return r = e.length, this._cachedIndex = r, this.afterEnd_(r - 1, t, i)
+ }
+ if (r === a) break;
+ if (i = n, t < (n = e[++r])) break e
+ }
+ o = e.length;
+ break r
+ }if (i <= t) break t;
+ var s = e[1];t < s && (r = 2, i = s);
+ for (a = r - 2;;) {
+ if (void 0 === i) return this._cachedIndex = 0, this.beforeStart_(0, t, n);
+ if (r === a) break;
+ if (n = i, (i = e[--r - 1]) <= t) break e
+ }
+ o = r,
+ r = 0
+ }
+ for (; r < o;) {
+ var u = r + o >>> 1;
+ t < e[u] ? o = u : r = u + 1
+ }
+ if (n = e[r], void 0 === (i = e[r - 1])) return this._cachedIndex = 0, this.beforeStart_(0, t, n);
+ if (void 0 === n) return r = e.length, this._cachedIndex = r, this.afterEnd_(r - 1, i, t)
+ }
+ this._cachedIndex = r,
+ this.intervalChanged_(r, i, n)
+ }
+ return this.interpolate_(r, i, t, n)
+ }, t.getSettings_ = function() {
+ return this.settings || this.DefaultSettings_
+ }, t.copySampleValue_ = function(t) {
+ for (var e = this.resultBuffer, r = this.sampleValues, n = this.valueSize, i = t * n, o = 0; o !== n; ++o) e[o] = r[i + o];
+ return e
+ }, t.interpolate_ = function() {
+ throw new Error("call to abstract method")
+ }, t.intervalChanged_ = function() {}, Interpolant
+ }();
+ Object.assign(V.prototype, {
+ beforeStart_: V.prototype.copySampleValue_,
+ afterEnd_: V.prototype.copySampleValue_
+ });
+ var q = function(o) {
+ var t, e;
+
+ function CubicInterpolant(t, e, r, n) {
+ var i;
+ return (i = o.call(this, t, e, r, n) || this)._weightPrev = -0, i._offsetPrev = -0, i._weightNext = -0, i._offsetNext = -0, i.DefaultSettings_ = {
+ endingStart: 2400,
+ endingEnd: 2400
+ }, i
+ }
+ e = o, (t = CubicInterpolant).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e;
+ var r = CubicInterpolant.prototype;
+ return r.intervalChanged = function(t, e, r) {
+ var n = this.parameterPositions,
+ i = t - 2,
+ o = t + 1,
+ a = n[i],
+ s = n[o];
+ if (void 0 === a) switch (this.getSettings_().endingStart) {
+ case 2401:
+ i = t, a = 2 * e - r;
+ break;
+ case 2402:
+ a = e + n[i = n.length - 2] - n[i + 1];
+ break;
+ default:
+ i = t, a = r
+ }
+ if (void 0 === s) switch (this.getSettings_().endingEnd) {
+ case 2401:
+ o = t, s = 2 * r - e;
+ break;
+ case 2402:
+ s = r + n[o = 1] - n[0];
+ break;
+ default:
+ o = t - 1, s = e
+ }
+ var u = .5 * (r - e),
+ h = this.valueSize;
+ this._weightPrev = u / (e - a), this._weightNext = u / (s - r), this._offsetPrev = i * h, this._offsetNext = o * h
+ }, r.interpolate_ = function(t, e, r, n) {
+ for (var i = this.resultBuffer, o = this.sampleValues, a = this.valueSize, s = t * a, u = s - a, h = this._offsetPrev, c = this._offsetNext, l = this._weightPrev, f = this._weightNext, d = (r - e) / (n - e), p = d * d, m = p * d, v = -l * m + 2 * l * p - l * d, g = (1 + l) * m + (-1.5 - 2 * l) * p + (-.5 + l) * d + 1, y = (-1 - f) * m + (1.5 + f) * p + .5 * d, _ = f * m - f * p, b = 0; b !== a; ++b) i[b] = v * o[h + b] + g * o[u + b] + y * o[s + b] + _ * o[c + b];
+ return i
+ }, CubicInterpolant
+ }(V);
+ var H = function(i) {
+ var t, e;
+
+ function LinearInterpolant(t, e, r, n) {
+ return i.call(this, t, e, r, n) || this
+ }
+ return e = i, (t = LinearInterpolant).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e, LinearInterpolant.prototype.interpolate_ = function(t, e, r, n) {
+ for (var i = this.resultBuffer, o = this.sampleValues, a = this.valueSize, s = t * a, u = s - a, h = (r - e) / (n - e), c = 1 - h, l = 0; l !== a; ++l) i[l] = o[u + l] * c + o[s + l] * h;
+ return i
+ }, LinearInterpolant
+ }(V);
+ var W = function(i) {
+ var t, e;
+
+ function DiscreteInterpolant(t, e, r, n) {
+ return i.call(this, t, e, r, n) || this
+ }
+ return e = i, (t = DiscreteInterpolant).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e, DiscreteInterpolant.prototype.interpolate_ = function(t) {
+ return this.copySampleValue_(t - 1)
+ }, DiscreteInterpolant
+ }(V),
+ Y = r(18),
+ K = function() {
+ function KeyframeTrack(t, e, r, n) {
+ if (void 0 === t) throw new Error("THREE.KeyframeTrack: track name is undefined");
+ if (void 0 === e || 0 === e.length) throw new Error("THREE.KeyframeTrack: no keyframes in track named " + t);
+ this.name = t, this.times = Y.b(e, this.TimeBufferType), this.values = Y.b(r, this.ValueBufferType), this.setInterpolation(n || this.DefaultInterpolation)
+ }
+ var t = KeyframeTrack.prototype;
+ return t.toJSON = function(t) {
+ var e, r = t.constructor;
+ if (void 0 !== r.toJSON) e = r.toJSON(t);
+ else {
+ e = {
+ name: t.name,
+ times: Y.b(t.times, Array),
+ values: Y.b(t.values, Array)
+ };
+ var n = t.getInterpolation();
+ n !== t.DefaultInterpolation && (e.interpolation = n)
+ }
+ return e.type = t.ValueTypeName, e
+ }, t.InterpolantFactoryMethodDiscrete = function(t) {
+ return new W(this.times, this.values, this.getValueSize(), t)
+ }, t.InterpolantFactoryMethodLinear = function(t) {
+ return new H(this.times, this.values, this.getValueSize(), t)
+ }, t.InterpolantFactoryMethodSmooth = function(t) {
+ return new q(this.times, this.values, this.getValueSize(), t)
+ }, t.setInterpolation = function(t) {
+ var e;
+ switch (t) {
+ case 2300:
+ e = this.InterpolantFactoryMethodDiscrete;
+ break;
+ case 2301:
+ e = this.InterpolantFactoryMethodLinear;
+ break;
+ case 2302:
+ e = this.InterpolantFactoryMethodSmooth
+ }
+ if (void 0 !== e) return this.createInterpolant = e, this;
+ var r = "unsupported interpolation for " + this.ValueTypeName + " keyframe track named " + this.name;
+ if (void 0 === this.createInterpolant) {
+ if (t === this.DefaultInterpolation) throw new Error(r);
+ this.setInterpolation(this.DefaultInterpolation)
+ }
+ return this
+ }, t.getInterpolation = function() {
+ switch (this.createInterpolant) {
+ case this.InterpolantFactoryMethodDiscrete:
+ return 2300;
+ case this.InterpolantFactoryMethodLinear:
+ return 2301;
+ case this.InterpolantFactoryMethodSmooth:
+ return 2302
+ }
+ }, t.getValueSize = function() {
+ return this.values.length / this.times.length
+ }, t.shift = function(t) {
+ if (0 !== t)
+ for (var e = this.times, r = 0, n = e.length; r !== n; ++r) e[r] += t;
+ return this
+ }, t.scale = function(t) {
+ if (1 !== t)
+ for (var e = this.times, r = 0, n = e.length; r !== n; ++r) e[r] *= t;
+ return this
+ }, t.trim = function(t, e) {
+ for (var r = this.times, n = r.length, i = 0, o = n - 1; i !== n && r[i] < t;) ++i;
+ for (; - 1 !== o && r[o] > e;) --o;
+ if (++o, 0 !== i || o !== n) {
+ o <= i && (i = (o = Math.max(o, 1)) - 1);
+ var a = this.getValueSize();
+ this.times = Y.a(r, i, o), this.values = Y.a(this.values, i * a, o * a)
+ }
+ return this
+ }, t.validate = function() {
+ var t = !0,
+ e = this.getValueSize();
+ e - Math.floor(e) != 0 && (t = !1);
+ var r = this.times,
+ n = this.values,
+ i = r.length;
+ 0 === i && (t = !1);
+ for (var o = null, a = 0; a !== i; a++) {
+ var s = r[a];
+ if ("number" == typeof s && isNaN(s)) {
+ t = !1;
+ break
+ }
+ if (null !== o && s < o) {
+ t = !1;
+ break
+ }
+ o = s
+ }
+ if (void 0 !== n && Y.e(n))
+ for (var u = 0, h = n.length; u !== h; ++u) {
+ var c = n[u];
+ if (isNaN(c)) {
+ t = !1;
+ break
+ }
+ }
+ return t
+ }, t.optimize = function() {
+ for (var t = this.times, e = this.values, r = this.getValueSize(), n = 2302 === this.getInterpolation(), i = 1, o = t.length - 1, a = 1; a < o; ++a) {
+ var s = !1,
+ u = t[a];
+ if (u !== t[a + 1] && (1 !== a || u !== u[0]))
+ if (n) s = !0;
+ else
+ for (var h = a * r, c = h - r, l = h + r, f = 0; f !== r; ++f) {
+ var d = e[h + f];
+ if (d !== e[c + f] || d !== e[l + f]) {
+ s = !0;
+ break
+ }
+ }
+ if (s) {
+ if (a !== i) {
+ t[i] = t[a];
+ for (var p = a * r, m = i * r, v = 0; v !== r; ++v) e[m + v] = e[p + v]
+ }++i
+ }
+ }
+ if (0 < o) {
+ t[i] = t[o];
+ for (var g = o * r, y = i * r, _ = 0; _ !== r; ++_) e[y + _] = e[g + _];
+ ++i
+ }
+ return i !== t.length && (this.times = Y.a(t, 0, i), this.values = Y.a(e, 0, i * r)), this
+ }, t.clone = function() {
+ var t = Y.a(this.times, 0),
+ e = Y.a(this.values, 0),
+ r = new this.constructor(this.name, t, e);
+ return r.createInterpolant = this.createInterpolant, r
+ }, KeyframeTrack
+ }();
+ Object.assign(K.prototype, {
+ TimeBufferType: Float32Array,
+ ValueBufferType: Float32Array,
+ DefaultInterpolation: 2301
+ });
+ var Z = function(n) {
+ var t, e;
+
+ function BooleanKeyframeTrack(t, e, r) {
+ return n.call(this, t, e, r) || this
+ }
+ return e = n, (t = BooleanKeyframeTrack).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e, BooleanKeyframeTrack
+ }(K);
+ Object.assign(Z.prototype, {
+ ValueTypeName: "bool",
+ ValueBufferType: Array,
+ DefaultInterpolation: 2300,
+ InterpolantFactoryMethodLinear: void 0,
+ InterpolantFactoryMethodSmooth: void 0
+ });
+ var Q = function(o) {
+ var t, e;
+
+ function ColorKeyframeTrack(t, e, r, n) {
+ var i;
+ return (i = o.call(this, t, e, r, n) || this).ValueTypeName = "color", i.ValueBufferType = Array, i
+ }
+ return e = o, (t = ColorKeyframeTrack).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e, ColorKeyframeTrack
+ }(K);
+ Object.assign(Q.prototype, {
+ ValueTypeName: "color",
+ ValueBufferType: Array
+ });
+ var J = function(i) {
+ var t, e;
+
+ function QuaternionLinearInterpolant(t, e, r, n) {
+ return i.call(this, t, e, r, n) || this
+ }
+ return e = i, (t = QuaternionLinearInterpolant).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e, QuaternionLinearInterpolant.prototype.interpolate_ = function(t, e, r, n) {
+ for (var i = this.resultBuffer, o = this.sampleValues, a = this.valueSize, s = t * a, u = (r - e) / (n - e), h = s + a; s !== h; s += 4) C.slerpFlat(i, 0, o, s - a, o, s, u);
+ return i
+ }, QuaternionLinearInterpolant
+ }(V);
+ var $ = function(i) {
+ var t, e;
+
+ function QuaternionKeyframeTrack(t, e, r, n) {
+ return i.call(this, t, e, r, n) || this
+ }
+ return e = i, (t = QuaternionKeyframeTrack).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e, QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodLinear = function(t) {
+ return new J(this.times, this.values, this.getValueSize(), t)
+ }, QuaternionKeyframeTrack
+ }(K);
+ Object.assign($.prototype, {
+ ValueTypeName: "quaternion",
+ DefaultInterpolation: 2301,
+ InterpolantFactoryMethodSmooth: void 0
+ });
+ var tt = function(o) {
+ var t, e;
+
+ function NumberKeyframeTrack(t, e, r, n) {
+ var i;
+ return (i = o.call(this, t, e, r, n) || this).ValueTypeName = "number", i
+ }
+ return e = o, (t = NumberKeyframeTrack).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e, NumberKeyframeTrack
+ }(K);
+ Object.assign(tt.prototype, {
+ ValueTypeName: "number"
+ });
+ var et = function(i) {
+ var t, e;
+
+ function VectorKeyframeTrack(t, e, r, n) {
+ return i.call(this, t, e, r, n) || this
+ }
+ return e = i, (t = VectorKeyframeTrack).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e, VectorKeyframeTrack
+ }(K);
+ Object.assign(Z.prototype, {
+ ValueTypeName: "vector"
+ });
+ var rt = function(i) {
+ var t, e;
+
+ function StringKeyframeTrack(t, e, r, n) {
+ return i.call(this, t, e, r, n) || this
+ }
+ return e = i, (t = StringKeyframeTrack).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e, StringKeyframeTrack
+ }(K);
+ Object.assign(rt.prototype, {
+ ValueTypeName: "string",
+ ValueBufferType: Array,
+ DefaultInterpolation: 2300,
+ InterpolantFactoryMethodLinear: void 0,
+ InterpolantFactoryMethodSmooth: void 0
+ });
+ var nt = function() {
+ function AnimationClip(t, e, r) {
+ this.name = t, this.tracks = r, this.duration = void 0 !== e ? e : -1, this.uuid = generateUUID(), this.duration < 0 && this.resetDuration()
+ }
+ var t = AnimationClip.prototype;
+ return t.resetDuration = function() {
+ for (var t = 0, e = 0, r = this.tracks.length; e !== r; ++e) {
+ var n = this.tracks[e];
+ t = Math.max(t, n.times[n.times.length - 1])
+ }
+ return this.duration = t, this
+ }, t.trim = function() {
+ for (var t = 0; t < this.tracks.length; t++) this.tracks[t].trim(0, this.duration);
+ return this
+ }, t.validate = function() {
+ for (var t = !0, e = 0; e < this.tracks.length; e++) t = t && this.tracks[e].validate();
+ return t
+ }, t.optimize = function() {
+ for (var t = 0; t < this.tracks.length; t++) this.tracks[t].optimize();
+ return this
+ }, t.clone = function() {
+ for (var t = [], e = 0; e < this.tracks.length; e++) t.push(this.tracks[e].clone());
+ return new AnimationClip(this.name, this.duration, t)
+ }, AnimationClip.parse = function(t) {
+ for (var e = [], r = t.tracks, n = 1 / (t.fps || 1), i = 0, o = r.length; i !== o; ++i) e.push(parseKeyframeTrack(r[i]).scale(n));
+ return new AnimationClip(t.name, t.duration, e)
+ }, AnimationClip.CreateFromMorphTargetSequence = function(t, e, r, n) {
+ for (var i = e.length, o = [], a = 0; a < i; a++) {
+ var s = [],
+ u = [];
+ s.push((a + i - 1) % i, a, (a + 1) % i), u.push(0, 1, 0);
+ var h = Y.d(s);
+ s = Y.f(s, 1, h), u = Y.f(u, 1, h), n || 0 !== s[0] || (s.push(i), u.push(u[0])), o.push(new tt(".morphTargetInfluences[" + e[a].name + "]", s, u).scale(1 / r))
+ }
+ return new AnimationClip(t, -1, o)
+ }, AnimationClip.findByName = function(t, e) {
+ var r = t;
+ if (!Array.isArray(t)) {
+ var n = t;
+ r = n.geometry && n.geometry.animations || n.animations
+ }
+ for (var i = 0; i < r.length; i++)
+ if (r[i].name === e) return r[i];
+ return null
+ }, AnimationClip.CreateClipsFromMorphTargetSequences = function(t, e, r) {
+ for (var n = {}, i = /^([\w-]*?)([\d]+)$/, o = 0, a = t.length; o < a; o++) {
+ var s = t[o],
+ u = s.name.match(i);
+ if (u && 1 < u.length) {
+ var h = u[1],
+ c = n[h];
+ c || (n[h] = c = []), c.push(s)
+ }
+ }
+ var l = [];
+ for (var f in n) l.push(AnimationClip.CreateFromMorphTargetSequence(f, n[f], e, r));
+ return l
+ }, AnimationClip.parseAnimation = function(t, e) {
+ if (!t) return null;
+ for (var r = function(t, e, r, n, i) {
+ if (0 !== r.length) {
+ var o = [],
+ a = [];
+ Y.c(r, o, a, n), 0 !== o.length && i.push(new t(e, o, a))
+ }
+ }, n = [], i = t.name || "default", o = t.length || -1, a = t.fps || 30, s = t.hierarchy || [], u = 0; u < s.length; u++) {
+ var h = s[u].keys;
+ if (h && 0 !== h.length)
+ if (h[0].morphTargets) {
+ for (var c = {}, l = 0; l < h.length; l++)
+ if (h[l].morphTargets)
+ for (var f = 0; f < h[l].morphTargets.length; f++) c[h[l].morphTargets[f]] = -1;
+ for (var d in c) {
+ for (var p = [], m = [], v = 0; v !== h[k].morphTargets.length; ++v) {
+ var g = h[k];
+ p.push(g.time), m.push(g.morphTarget === d ? 1 : 0)
+ }
+ n.push(new tt(".morphTargetInfluence[" + d + "]", p, m))
+ }
+ o = c.length * (a || 1)
+ } else {
+ var y = ".bones[" + e[u].name + "]";
+ r(et, y + ".position", h, "pos", n), r($, y + ".quaternion", h, "rot", n), r(et, y + ".scale", h, "scl", n)
+ }
+ }
+ return 0 === n.length ? null : new AnimationClip(i, o, n)
+ }, AnimationClip
+ }();
+
+ function parseKeyframeTrack(t) {
+ if (void 0 === t.type) throw new Error("THREE.KeyframeTrack: track type undefined, can not parse");
+ var e = function(t) {
+ switch (t.toLowerCase()) {
+ case "scalar":
+ case "double":
+ case "float":
+ case "number":
+ case "integer":
+ return tt;
+ case "vector":
+ case "vector2":
+ case "vector3":
+ case "vector4":
+ return et;
+ case "color":
+ return Q;
+ case "quaternion":
+ return $;
+ case "bool":
+ case "boolean":
+ return Z;
+ case "string":
+ return rt
+ }
+ throw new Error("THREE.KeyframeTrack: Unsupported typeName: " + t)
+ }(t.type);
+ if (void 0 === t.times) {
+ var r = [],
+ n = [];
+ Y.c(t.keys, r, n, "value"), t.times = r, t.values = n
+ }
+ return void 0 !== e.parse ? e.parse(t) : new e(t.name, t.times, t.values, t.interpolation)
+ }
+ var it = function() {
+ function AnimationAction(t, e, r) {
+ this._mixer = t, this._clip = e, this._localRoot = r || null;
+ for (var n = e.tracks, i = n.length, o = new Array(i), a = {
+ endingStart: 2400,
+ endingEnd: 2400
+ }, s = 0; s !== i; ++s) {
+ var u = n[s].createInterpolant(null);
+ (o[s] = u).settings = a
+ }
+ this._interpolantSettings = a, this._interpolants = o, this._propertyBindings = new Array(i), this._cacheIndex = null, this._byClipCacheIndex = null, this._timeScaleInterpolant = null, this._weightInterpolant = null, this.loop = 2201, this._loopCount = -1, this._startTime = null, this.time = 0, this.timeScale = 1, this._effectiveTimeScale = 1, this.weight = 1, this._effectiveWeight = 1, this.repetitions = 1 / 0, this.paused = !1, this.enabled = !0, this.clampWhenFinished = !1, this.zeroSlopeAtStart = !0, this.zeroSlopeAtEnd = !0
+ }
+ var t = AnimationAction.prototype;
+ return t.play = function() {
+ return this._mixer._activateAction(this), this
+ }, t.stop = function() {
+ return this._mixer._deactivateAction(this), this.reset()
+ }, t.reset = function() {
+ return this.paused = !1, this.enabled = !0, this.time = 0, this._loopCount = -1, this._startTime = null, this.stopFading().stopWarping()
+ }, t.isRunning = function() {
+ return this.enabled && !this.paused && 0 !== this.timeScale && null === this._startTime && this._mixer._isActiveAction(this)
+ }, t.isScheduled = function() {
+ return this._mixer._isActiveAction(this)
+ }, t.startAt = function(t) {
+ return this._startTime = t, this
+ }, t.setLoop = function(t, e) {
+ return this.loop = t, this.repetitions = e, this
+ }, t.setEffectiveWeight = function(t) {
+ return this.weight = t, this._effectiveWeight = this.enabled ? t : 0, this.stopFading()
+ }, t.getEffectiveWeight = function() {
+ return this._effectiveWeight
+ }, t.fadeIn = function(t) {
+ return this._scheduleFading(t, 0, 1)
+ }, t.fadeOut = function(t) {
+ return this._scheduleFading(t, 1, 0)
+ }, t.crossFadeFrom = function(t, e, r) {
+ if (t.fadeOut(e), this.fadeIn(e), r) {
+ var n = this._clip.duration,
+ i = t._clip.duration,
+ o = i / n,
+ a = n / i;
+ t.warp(1, o, e), this.warp(a, 1, e)
+ }
+ return this
+ }, t.crossFadeTo = function(t, e, r) {
+ return t.crossFadeFrom(this, e, r)
+ }, t.stopFading = function() {
+ var t = this._weightInterpolant;
+ return null !== t && (this._weightInterpolant = null, this._mixer._takeBackControlInterpolant(t)), this
+ }, t.setEffectiveTimeScale = function(t) {
+ return this.timeScale = t, this._effectiveTimeScale = this.paused ? 0 : t, this.stopWarping()
+ }, t.getEffectiveTimeScale = function() {
+ return this._effectiveTimeScale
+ }, t.setDuration = function(t) {
+ return this.timeScale = this._clip.duration / t, this.stopWarping()
+ }, t.syncWith = function(t) {
+ return this.time = t.time, this.timeScale = t.timeScale, this.stopWarping()
+ }, t.halt = function(t) {
+ return this.warp(this._effectiveTimeScale, 0, t)
+ }, t.warp = function(t, e, r) {
+ var n = this._mixer,
+ i = n.time,
+ o = this._timeScaleInterpolant,
+ a = this.timeScale;
+ null === o && (o = n._lendControlInterpolant(), this._timeScaleInterpolant = o);
+ var s = o.parameterPositions,
+ u = o.sampleValues;
+ return s[0] = i, s[1] = i + r, u[0] = t / a, u[1] = e / a, this
+ }, t.stopWarping = function() {
+ var t = this._timeScaleInterpolant;
+ return null !== t && (this._timeScaleInterpolant = null, this._mixer._takeBackControlInterpolant(t)), this
+ }, t.getMixer = function() {
+ return this._mixer
+ }, t.getClip = function() {
+ return this._clip
+ }, t.getRoot = function() {
+ return this._localRoot || this._mixer._root
+ }, t._update = function(t, e, r, n) {
+ if (this.enabled) {
+ var i = this._startTime;
+ if (null !== i) {
+ var o = (t - i) * r;
+ if (o < 0 || 0 === r) return;
+ this._startTime = null, e = r * o
+ }
+ e *= this._updateTimeScale(t);
+ var a = this._updateTime(e),
+ s = this._updateWeight(t);
+ if (0 < s)
+ for (var u = this._interpolants, h = this._propertyBindings, c = 0, l = u.length; c !== l; ++c) u[c].evaluate(a), h[c].accumulate(n, s)
+ } else this._updateWeight(t)
+ }, t._updateWeight = function(t) {
+ var e = 0;
+ if (this.enabled) {
+ e = this.weight;
+ var r = this._weightInterpolant;
+ if (null !== r) {
+ var n = r.evaluate(t)[0];
+ e *= n, t > r.parameterPositions[1] && (this.stopFading(), 0 === n && (this.enabled = !1))
+ }
+ }
+ return this._effectiveWeight = e
+ }, t._updateTimeScale = function(t) {
+ var e = 0;
+ if (!this.paused) {
+ e = this.timeScale;
+ var r = this._timeScaleInterpolant;
+ if (null !== r) e *= r.evaluate(t)[0], t > r.parameterPositions[1] && (this.stopWarping(), 0 === e ? this.paused = !0 : this.timeScale = e)
+ }
+ return this._effectiveTimeScale = e
+ }, t._updateTime = function(t) {
+ var e = this.time + t,
+ r = this._clip.duration,
+ n = this.loop,
+ i = this._loopCount,
+ o = 2202 === n;
+ if (0 === t) return -1 === i ? e : o && 1 == (1 & i) ? r - e : e;
+ if (2200 === n) {
+ -1 === i && (this._loopCount = 0, this._setEndings(!0, !0, !1));
+ t: {
+ if (r <= e) e = r;
+ else {
+ if (!(e < 0)) break t;
+ e = 0
+ }
+ this.clampWhenFinished ? this.paused = !0 : this.enabled = !1,
+ this._mixer.dispatchEvent({
+ type: "finished",
+ action: this,
+ direction: t < 0 ? -1 : 1
+ })
+ }
+ } else {
+ if (-1 === i && (0 <= t ? (i = 0, this._setEndings(!0, 0 === this.repetitions, o)) : this._setEndings(0 === this.repetitions, !0, o)), r <= e || e < 0) {
+ var a = Math.floor(e / r);
+ e -= r * a, i += Math.abs(a);
+ var s = this.repetitions - i;
+ if (s <= 0) this.clampWhenFinished ? this.paused = !0 : this.enabled = !1, e = 0 < t ? r : 0, this._mixer.dispatchEvent({
+ type: "finished",
+ action: this,
+ direction: 0 < t ? 1 : -1
+ });
+ else {
+ if (1 === s) {
+ var u = t < 0;
+ this._setEndings(u, !u, o)
+ } else this._setEndings(!1, !1, o);
+ this._loopCount = i, this._mixer.dispatchEvent({
+ type: "loop",
+ action: this,
+ loopDelta: a
+ })
+ }
+ }
+ if (o && 1 == (1 & i)) return r - (this.time = e)
+ }
+ return this.time = e
+ }, t._setEndings = function(t, e, r) {
+ var n = this._interpolantSettings;
+ n.endingEnd = r ? n.endingStart = 2401 : (n.endingStart = t ? this.zeroSlopeAtStart ? 2401 : 2400 : 2402, e ? this.zeroSlopeAtEnd ? 2401 : 2400 : 2402)
+ }, t._scheduleFading = function(t, e, r) {
+ var n = this._mixer,
+ i = n.time,
+ o = this._weightInterpolant;
+ null === o && (o = n._lendControlInterpolant(), this._weightInterpolant = o);
+ var a = o.parameterPositions,
+ s = o.sampleValues;
+ return a[0] = i, s[0] = e, a[1] = i + t, s[1] = r, this
+ }, AnimationAction
+ }(),
+ ot = "\\[\\]\\.:\\/",
+ at = new RegExp("[" + ot + "]", "g"),
+ st = "[^" + ot + "]",
+ ut = "[^" + ot.replace("\\.", "") + "]",
+ ht = /((?:WC+[\/:])*)/.source.replace("WC", st),
+ ct = /(WCOD+)?/.source.replace("WCOD", ut),
+ lt = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC", st),
+ ft = /\.(WC+)(?:\[(.+)\])?/.source.replace("WC", st),
+ dt = new RegExp("^" + ht + ct + lt + ft + "$"),
+ pt = ["material", "materials", "bones"],
+ mt = function() {
+ function Composite(t, e, r) {
+ var n = r || vt.parseTrackName(e);
+ this._targetGroup = t, this._bindings = t.subscribe_(e, n)
+ }
+ var t = Composite.prototype;
+ return t.getValue = function(t, e) {
+ this.bind();
+ var r = this._targetGroup.nCachedObjects_,
+ n = this._bindings[r];
+ void 0 !== n && n.getValue(t, e)
+ }, t.setValue = function(t, e) {
+ for (var r = this._bindings, n = this._targetGroup.nCachedObjects_, i = r.length; n !== i; ++n) r[n].setValue(t, e)
+ }, t.bind = function() {
+ for (var t = this._bindings, e = this._targetGroup.nCachedObjects_, r = t.length; e !== r; ++e) t[e].bind()
+ }, t.unbind = function() {
+ for (var t = this._bindings, e = this._targetGroup.nCachedObjects_, r = t.length; e !== r; ++e) t[e].unbind()
+ }, Composite
+ }(),
+ vt = function() {
+ function PropertyBinding(t, e, r) {
+ this.path = e, this.parsedPath = r || PropertyBinding.parseTrackName(e), this.node = PropertyBinding.findNode(t, this.parsedPath.nodeName) || t, this.rootNode = t
+ }
+ PropertyBinding.sanitizeNodeName = function(t) {
+ return t.replace(/\s/g, "_").replace(at, "")
+ }, PropertyBinding.create = function(t, e, r) {
+ return t && t.isAnimationObjectGroup ? new PropertyBinding.Composite(t, e, r) : new PropertyBinding(t, e, r)
+ }, PropertyBinding.parseTrackName = function(t) {
+ var e = dt.exec(t);
+ if (!e) throw new Error("PropertyBinding: Cannot parse trackName: " + t);
+ var r = {
+ nodeName: e[2],
+ objectName: e[3],
+ objectIndex: e[4],
+ propertyName: e[5],
+ propertyIndex: e[6]
+ },
+ n = r.nodeName && r.nodeName.lastIndexOf(".");
+ if (void 0 !== n && -1 !== n) {
+ var i = r.nodeName.substring(n + 1); - 1 !== pt.indexOf(i) && (r.nodeName = r.nodeName.substring(0, n), r.objectName = i)
+ }
+ if (null === r.propertyName || 0 === r.propertyName.length) throw new Error("PropertyBinding: can not parse propertyName from trackName: " + t);
+ return r
+ }, PropertyBinding.findNode = function(t, i) {
+ if (!i || "" === i || "root" === i || "." === i || -1 === i || i === t.name || i === t.uuid) return t;
+ if (t.skeleton) {
+ var e = t.skeleton.getBoneByName(i);
+ if (void 0 !== e) return e
+ }
+ if (t.children) {
+ var r = function searchNodeSubtree(t) {
+ for (var e = 0; e < t.length; e++) {
+ var r = t[e];
+ if (r.name === i || r.uuid === i) return r;
+ var n = searchNodeSubtree(r.children);
+ if (n) return n
+ }
+ return null
+ }(t.children);
+ if (r) return r
+ }
+ return null
+ };
+ var t = PropertyBinding.prototype;
+ return t._getValue_unavailable = function() {}, t._setValue_unavailable = function() {}, t.getValue = function(t, e) {
+ this.bind(), this.getValue(t, e)
+ }, t.setValue = function(t, e) {
+ this.bind(), this.setValue(t, e)
+ }, t.bind = function() {
+ var t = this.node,
+ e = this.parsedPath,
+ r = e.objectName,
+ n = e.propertyName,
+ i = e.propertyIndex;
+ if (t || (t = PropertyBinding.findNode(this.rootNode, e.nodeName) || this.rootNode, this.node = t), this.getValue = this._getValue_unavailable, this.setValue = this._setValue_unavailable, t) {
+ if (r) {
+ var o = e.objectIndex;
+ switch (r) {
+ case "materials":
+ if (!t.material) return;
+ if (!t.material.materials) return;
+ t = t.material.materials;
+ break;
+ case "bones":
+ if (!t.skeleton) return;
+ t = t.skeleton.bones;
+ for (var a = 0; a < t.length; a++)
+ if (t[a].name === o) {
+ o = a;
+ break
+ }
+ break;
+ default:
+ if (void 0 === t[r]) return;
+ t = t[r]
+ }
+ if (void 0 !== o) {
+ if (void 0 === t[o]) return;
+ t = t[o]
+ }
+ }
+ var s = t[n];
+ if (void 0 !== s) {
+ var u = this.Versioning.None;
+ void 0 !== (this.targetObject = t).needsUpdate ? u = this.Versioning.NeedsUpdate : void 0 !== t.matrixWorldNeedsUpdate && (u = this.Versioning.MatrixWorldNeedsUpdate);
+ var h = this.BindingType.Direct;
+ if (void 0 !== i) {
+ if ("morphTargetInfluences" === n) {
+ if (!t.geometry) return;
+ if (t.geometry.isBufferGeometry) {
+ if (!t.geometry.morphAttributes) return;
+ for (var c = 0; c < this.node.geometry.morphAttributes.position.length; c++)
+ if (t.geometry.morphAttributes.position[c].name === i) {
+ i = c;
+ break
+ }
+ } else {
+ if (!t.geometry.morphTargets) return;
+ for (var l = 0; l < this.node.geometry.morphTargets.length; l++)
+ if (t.geometry.morphTargets[l].name === i) {
+ i = l;
+ break
+ }
+ }
+ }
+ h = this.BindingType.ArrayElement, this.resolvedProperty = s, this.propertyIndex = i
+ } else void 0 !== s.fromArray && void 0 !== s.toArray ? (h = this.BindingType.HasFromToArray, this.resolvedProperty = s) : Array.isArray(s) ? (h = this.BindingType.EntireArray, this.resolvedProperty = s) : this.propertyName = n;
+ this.getValue = this.GetterByBindingType[h], this.setValue = this.SetterByBindingTypeAndVersioning[h][u]
+ } else e.nodeName
+ }
+ }, t.unbind = function() {
+ this.node = null, this.getValue = this._getValue_unbound, this.setValue = this._setValue_unbound
+ }, PropertyBinding
+ }();
+ Object.assign(vt.prototype, {
+ BindingType: {
+ Direct: 0,
+ EntireArray: 1,
+ ArrayElement: 2,
+ HasFromToArray: 3
+ },
+ Versioning: {
+ None: 0,
+ NeedsUpdate: 1,
+ MatrixWorldNeedsUpdate: 2
+ },
+ GetterByBindingType: [function(t, e) {
+ t[e] = this.node[this.propertyName]
+ }, function(t, e) {
+ for (var r = this.resolvedProperty, n = 0, i = r.length; n !== i; ++n) t[e++] = r[n]
+ }, function(t, e) {
+ t[e] = this.resolvedProperty[this.propertyIndex]
+ }, function(t, e) {
+ this.resolvedProperty.toArray(t, e)
+ }],
+ SetterByBindingTypeAndVersioning: [
+ [function(t, e) {
+ this.targetObject[this.propertyName] = t[e]
+ }, function(t, e) {
+ this.targetObject[this.propertyName] = t[e], this.targetObject.needsUpdate = !0
+ }, function(t, e) {
+ this.targetObject[this.propertyName] = t[e], this.targetObject.matrixWorldNeedsUpdate = !0
+ }],
+ [function(t, e) {
+ for (var r = this.resolvedProperty, n = 0, i = r.length; n !== i; ++n) r[n] = t[e++]
+ }, function(t, e) {
+ for (var r = this.resolvedProperty, n = 0, i = r.length; n !== i; ++n) r[n] = t[e++];
+ this.targetObject.needsUpdate = !0
+ }, function(t, e) {
+ for (var r = this.resolvedProperty, n = 0, i = r.length; n !== i; ++n) r[n] = t[e++];
+ this.targetObject.matrixWorldNeedsUpdate = !0
+ }],
+ [function(t, e) {
+ this.resolvedProperty[this.propertyIndex] = t[e]
+ }, function(t, e) {
+ this.resolvedProperty[this.propertyIndex] = t[e], this.targetObject.needsUpdate = !0
+ }, function(t, e) {
+ this.resolvedProperty[this.propertyIndex] = t[e], this.targetObject.matrixWorldNeedsUpdate = !0
+ }],
+ [function(t, e) {
+ this.resolvedProperty.fromArray(t, e)
+ }, function(t, e) {
+ this.resolvedProperty.fromArray(t, e), this.targetObject.needsUpdate = !0
+ }, function(t, e) {
+ this.resolvedProperty.fromArray(t, e), this.targetObject.matrixWorldNeedsUpdate = !0
+ }]
+ ]
+ }), Object.assign(vt, {
+ Composite: mt
+ });
+ var gt = function() {
+ function PropertyMixer(t, e, r) {
+ this.binding = t, this.valueSize = r;
+ var n, i = Float64Array;
+ switch (e) {
+ case "quaternion":
+ n = this._slerp;
+ break;
+ case "string":
+ case "bool":
+ i = Array, n = this._select;
+ break;
+ default:
+ n = this._lerp
+ }
+ this.buffer = new i(4 * r), this._mixBufferRegion = n, this.cumulativeWeight = 0, this.useCount = 0, this.referenceCount = 0
+ }
+ var t = PropertyMixer.prototype;
+ return t.accumulate = function(t, e) {
+ var r = this.buffer,
+ n = this.valueSize,
+ i = t * n + n,
+ o = this.cumulativeWeight;
+ if (0 === o) {
+ for (var a = 0; a !== n; ++a) r[i + a] = r[a];
+ o = e
+ } else {
+ var s = e / (o += e);
+ this._mixBufferRegion(r, i, 0, s, n)
+ }
+ this.cumulativeWeight = o
+ }, t.apply = function(t) {
+ var e = this.valueSize,
+ r = this.buffer,
+ n = t * e + e,
+ i = this.cumulativeWeight,
+ o = this.binding;
+ if (this.cumulativeWeight = 0, i < 1) {
+ var a = 3 * e;
+ this._mixBufferRegion(r, n, a, 1 - i, e)
+ }
+ for (var s = e, u = e + e; s !== u; ++s)
+ if (r[s] !== r[s + e]) {
+ o.setValue(r, n);
+ break
+ }
+ }, t.saveOriginalState = function() {
+ var t = this.binding,
+ e = this.buffer,
+ r = this.valueSize,
+ n = 3 * r;
+ t.getValue(e, n);
+ for (var i = r, o = n; i !== o; ++i) e[i] = e[n + i % r];
+ this.cumulativeWeight = 0
+ }, t.restoreOriginalState = function() {
+ var t = 3 * this.valueSize;
+ this.binding.setValue(this.buffer, t)
+ }, t._select = function(t, e, r, n, i) {
+ if (.5 <= n)
+ for (var o = 0; o !== i; ++o) t[e + o] = t[r + o]
+ }, t._slerp = function(t, e, r, n) {
+ C.slerpFlat(t, e, t, e, t, r, n)
+ }, t._lerp = function(t, e, r, n, i) {
+ for (var o = 1 - n, a = 0; a !== i; ++a) {
+ var s = e + a;
+ t[s] = t[s] * o + t[r + a] * n
+ }
+ }, PropertyMixer
+ }(),
+ yt = function() {
+ function AnimationMixer(t) {
+ this._root = t, this._initMemoryManager(), this._accuIndex = 0, this.time = 0, this.timeScale = 1
+ }
+ var t = AnimationMixer.prototype;
+ return t._bindAction = function(t, e) {
+ var r = t._localRoot || this._root,
+ n = t._clip.tracks,
+ i = n.length,
+ o = t._propertyBindings,
+ a = t._interpolants,
+ s = r.uuid,
+ u = this._bindingsByRootAndName,
+ h = u[s];
+ void 0 === h && (h = {}, u[s] = h);
+ for (var c = 0; c !== i; ++c) {
+ var l = n[c],
+ f = l.name,
+ d = h[f];
+ if (void 0 !== d) o[c] = d;
+ else {
+ if (void 0 !== (d = o[c])) {
+ null === d._cacheIndex && (++d.referenceCount, this._addInactiveBinding(d, s, f));
+ continue
+ }
+ var p = e && e._propertyBindings[c].binding.parsedPath;
+ ++(d = new gt(vt.create(r, f, p), l.ValueTypeName, l.getValueSize())).referenceCount, this._addInactiveBinding(d, s, f), o[c] = d
+ }
+ a[c].resultBuffer = d.buffer
+ }
+ }, t._activateAction = function(t) {
+ if (!this._isActiveAction(t)) {
+ if (null === t._cacheIndex) {
+ var e = (t._localRoot || this._root).uuid,
+ r = t._clip.uuid,
+ n = this._actionsByClip[r];
+ this._bindAction(t, n && n.knownActions[0]), this._addInactiveAction(t, r, e)
+ }
+ for (var i = t._propertyBindings, o = 0, a = i.length; o !== a; ++o) {
+ var s = i[o];
+ 0 == s.useCount++ && (this._lendBinding(s), s.saveOriginalState())
+ }
+ this._lendAction(t)
+ }
+ }, t._deactivateAction = function(t) {
+ if (this._isActiveAction(t)) {
+ for (var e = t._propertyBindings, r = 0, n = e.length; r !== n; ++r) {
+ var i = e[r];
+ 0 == --i.useCount && (i.restoreOriginalState(), this._takeBackBinding(i))
+ }
+ this._takeBackAction(t)
+ }
+ }, t._initMemoryManager = function() {
+ this._actions = [], this._nActiveActions = 0, this._actionsByClip = {}, this._bindings = [], this._nActiveBindings = 0, this._bindingsByRootAndName = {}, this._controlInterpolants = [], this._nActiveControlInterpolants = 0;
+ var t = this;
+ this.stats = {
+ actions: {
+ get total() {
+ return t._actions.length
+ },
+ get inUse() {
+ return t._nActiveActions
+ }
+ },
+ bindings: {
+ get total() {
+ return t._bindings.length
+ },
+ get inUse() {
+ return t._nActiveBindings
+ }
+ },
+ controlInterpolants: {
+ get total() {
+ return t._controlInterpolants.length
+ },
+ get inUse() {
+ return t._nActiveControlInterpolants
+ }
+ }
+ }
+ }, t._isActiveAction = function(t) {
+ var e = t._cacheIndex;
+ return null !== e && e < this._nActiveActions
+ }, t._addInactiveAction = function(t, e, r) {
+ var n = this._actions,
+ i = this._actionsByClip,
+ o = i[e];
+ if (void 0 === o) o = {
+ knownActions: [t],
+ actionByRoot: {}
+ }, t._byClipCacheIndex = 0, i[e] = o;
+ else {
+ var a = o.knownActions;
+ t._byClipCacheIndex = a.length, a.push(t)
+ }
+ t._cacheIndex = n.length, n.push(t), o.actionByRoot[r] = t
+ }, t._removeInactiveAction = function(t) {
+ var e = this._actions,
+ r = e[e.length - 1],
+ n = t._cacheIndex;
+ e[r._cacheIndex = n] = r, e.pop(), t._cacheIndex = null;
+ var i = t._clip.uuid,
+ o = this._actionsByClip,
+ a = o[i],
+ s = a.knownActions,
+ u = s[s.length - 1],
+ h = t._byClipCacheIndex;
+ s[u._byClipCacheIndex = h] = u, s.pop(), t._byClipCacheIndex = null, delete a.actionByRoot[(t._localRoot || this._root).uuid], 0 === s.length && delete o[i], this._removeInactiveBindingsForAction(t)
+ }, t._removeInactiveBindingsForAction = function(t) {
+ for (var e = t._propertyBindings, r = 0, n = e.length; r !== n; ++r) {
+ var i = e[r];
+ 0 == --i.referenceCount && this._removeInactiveBinding(i)
+ }
+ }, t._lendAction = function(t) {
+ var e = this._actions,
+ r = t._cacheIndex,
+ n = this._nActiveActions++,
+ i = e[n];
+ e[t._cacheIndex = n] = t, e[i._cacheIndex = r] = i
+ }, t._takeBackAction = function(t) {
+ var e = this._actions,
+ r = t._cacheIndex,
+ n = --this._nActiveActions,
+ i = e[n];
+ e[t._cacheIndex = n] = t, e[i._cacheIndex = r] = i
+ }, t._addInactiveBinding = function(t, e, r) {
+ var n = this._bindingsByRootAndName,
+ i = n[e],
+ o = this._bindings;
+ void 0 === i && (i = {}, n[e] = i), (i[r] = t)._cacheIndex = o.length, o.push(t)
+ }, t._removeInactiveBinding = function(t) {
+ var e = this._bindings,
+ r = t.binding,
+ n = r.rootNode.uuid,
+ i = r.path,
+ o = this._bindingsByRootAndName,
+ a = o[n],
+ s = e[e.length - 1],
+ u = t._cacheIndex;
+ e[s._cacheIndex = u] = s, e.pop(), delete a[i];
+ t: {
+ for (var h in a) break t;delete o[n]
+ }
+ }, t._lendBinding = function(t) {
+ var e = this._bindings,
+ r = t._cacheIndex,
+ n = this._nActiveBindings++,
+ i = e[n];
+ e[t._cacheIndex = n] = t, e[i._cacheIndex = r] = i
+ }, t._takeBackBinding = function(t) {
+ var e = this._bindings,
+ r = t._cacheIndex,
+ n = --this._nActiveBindings,
+ i = e[n];
+ e[t._cacheIndex = n] = t, e[i._cacheIndex = r] = i
+ }, t._lendControlInterpolant = function() {
+ var t = this._controlInterpolants,
+ e = this._nActiveControlInterpolants++,
+ r = t[e];
+ return void 0 === r && (t[(r = new H(new Float32Array(2), new Float32Array(2), 1, this._controlInterpolantsResultBuffer)).__cacheIndex = e] = r), r
+ }, t._takeBackControlInterpolant = function(t) {
+ var e = this._controlInterpolants,
+ r = t.__cacheIndex,
+ n = --this._nActiveControlInterpolants,
+ i = e[n];
+ e[t.__cacheIndex = n] = t, e[i.__cacheIndex = r] = i
+ }, t.clipAction = function(t, e) {
+ var r = e || this._root,
+ n = r.uuid,
+ i = "string" == typeof t ? nt.findByName(r, t) : t,
+ o = null !== i ? i.uuid : t,
+ a = this._actionsByClip[o],
+ s = null;
+ if (void 0 !== a) {
+ var u = a.actionByRoot[n];
+ if (void 0 !== u) return u;
+ s = a.knownActions[0], null === i && (i = s._clip)
+ }
+ if (null === i) return null;
+ var h = new it(this, i, e);
+ return this._bindAction(h, s), this._addInactiveAction(h, o, n), h
+ }, t.existingAction = function(t, e) {
+ var r = e || this._root,
+ n = r.uuid,
+ i = "string" == typeof t ? nt.findByName(r, t) : t,
+ o = i ? i.uuid : t,
+ a = this._actionsByClip[o];
+ return void 0 !== a && a.actionByRoot[n] || null
+ }, t.stopAllAction = function() {
+ var t = this._actions,
+ e = this._nActiveActions,
+ r = this._bindings,
+ n = this._nActiveBindings;
+ this._nActiveActions = 0;
+ for (var i = this._nActiveBindings = 0; i !== e; ++i) t[i].reset();
+ for (var o = 0; o !== n; ++o) r[o].useCount = 0;
+ return this
+ }, t.update = function(t) {
+ t *= this.timeScale;
+ for (var e = this._actions, r = this._nActiveActions, n = this.time += t, i = Math.sign(t), o = this._accuIndex ^= 1, a = 0; a !== r; ++a) {
+ e[a]._update(n, t, i, o)
+ }
+ for (var s = this._bindings, u = this._nActiveBindings, h = 0; h !== u; ++h) s[h].apply(o);
+ return this
+ }, t.getRoot = function() {
+ return this._root
+ }, t.uncacheClip = function(t) {
+ var e = this._actions,
+ r = t.uuid,
+ n = this._actionsByClip,
+ i = n[r];
+ if (void 0 !== i) {
+ for (var o = i.knownActions, a = 0, s = o.length; a !== s; ++a) {
+ var u = o[a];
+ this._deactivateAction(u);
+ var h = u._cacheIndex,
+ c = e[e.length - 1];
+ u._cacheIndex = null, u._byClipCacheIndex = null, e[c._cacheIndex = h] = c, e.pop(), this._removeInactiveBindingsForAction(u)
+ }
+ delete n[r]
+ }
+ }, t.uncacheRoot = function(t) {
+ var e = t.uuid,
+ r = this._actionsByClip;
+ for (var n in r) {
+ var i = r[n].actionByRoot[e];
+ void 0 !== i && (this._deactivateAction(i), this._removeInactiveAction(i))
+ }
+ var o = this._bindingsByRootAndName[e];
+ if (void 0 !== o)
+ for (var a in o) {
+ var s = o[a];
+ s.restoreOriginalState(), this._removeInactiveBinding(s)
+ }
+ }, t.uncacheAction = function(t, e) {
+ var r = this.existingAction(t, e);
+ null !== r && (this._deactivateAction(r), this._removeInactiveAction(r))
+ }, t.dispatchEvent = function() {}, AnimationMixer
+ }();
+ Object.assign(yt.prototype, {
+ _controlInterpolantsResultBuffer: new Float32Array(1)
+ });
+ var _t = 0,
+ bt = new C,
+ xt = new S,
+ wt = new v,
+ Tt = new v,
+ St = function() {
+ function Object3D() {
+ Object.defineProperty(this, "id", {
+ value: _t++
+ }), this.uuid = generateUUID(), this.name = "", this.type = "Object3D", this.parent = null, this.children = [], this.up = Object3D.DefaultUp.clone();
+ var t = new v,
+ e = new F,
+ r = new C,
+ n = new v(1, 1, 1);
+ e.onChange(function() {
+ r.setFromEuler(e, !1)
+ }), r.onChange(function() {
+ e.setFromQuaternion(r, void 0, !1)
+ }), this.position = void 0, this.rotation = void 0, this.quaternion = void 0, this.scale = void 0, this.modelViewMatrix = void 0, this.normalMatrix = void 0, Object.defineProperties(this, {
+ position: {
+ configurable: !0,
+ enumerable: !0,
+ value: t
+ },
+ rotation: {
+ configurable: !0,
+ enumerable: !0,
+ value: e
+ },
+ quaternion: {
+ configurable: !0,
+ enumerable: !0,
+ value: r
+ },
+ scale: {
+ configurable: !0,
+ enumerable: !0,
+ value: n
+ },
+ modelViewMatrix: {
+ value: new S
+ },
+ normalMatrix: {
+ value: new w
+ }
+ }), this.matrix = new S, this.matrixWorld = new S, this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate, this.matrixWorldNeedsUpdate = !1, this.visible = !0, this.userData = {}, this.isObject3D = !0
+ }
+ var t = Object3D.prototype;
+ return t.applyMatrix = function(t) {
+ this.matrix.multiplyMatrices(t, this.matrix), this.matrix.decompose(this.position, this.quaternion, this.scale)
+ }, t.lookAt = function(t, e, r) {
+ var n = bt,
+ i = xt,
+ o = wt,
+ a = Tt;
+ t.isVector3 ? o.copy(t) : o.set(t, e, r);
+ var s = this.parent;
+ this.updateWorldMatrix(!0, !1), a.setFromMatrixPosition(this.matrixWorld), this.isCamera || this.isLight ? i.lookAt(a, o, this.up) : i.lookAt(o, a, this.up), this.quaternion.setFromRotationMatrix(i), s && (i.extractRotation(s.matrixWorld), n.setFromRotationMatrix(i), this.quaternion.premultiply(n.inverse()))
+ }, t.add = function(t) {
+ if (1 < arguments.length) {
+ for (var e = 0; e < arguments.length; e++) this.add(arguments[e]);
+ return this
+ }
+ return t === this || t && t.isObject3D && (null !== t.parent && t.parent.remove(t), (t.parent = this).children.push(t)), this
+ }, t.remove = function(t) {
+ if (1 < arguments.length) {
+ for (var e = 0; e < arguments.length; e++) this.remove(arguments[e]);
+ return this
+ }
+ var r = this.children.indexOf(t);
+ return -1 !== r && (t.parent = null, t.dispatchEvent({
+ type: "removed"
+ }), this.children.splice(r, 1)), this
+ }, t.getObjectById = function(t) {
+ return this.getObjectByProperty("id", t)
+ }, t.getObjectByName = function(t) {
+ return this.getObjectByProperty("name", t)
+ }, t.getObjectByProperty = function(t, e) {
+ if (this[t] === e) return this;
+ for (var r = 0, n = this.children.length; r < n; r++) {
+ var i = this.children[r].getObjectByProperty(t, e);
+ if (void 0 !== i) return i
+ }
+ }, t.getWorldPosition = function(t) {
+ return void 0 === t && (t = new v), this.updateMatrixWorld(!0), t.setFromMatrixPosition(this.matrixWorld)
+ }, t.getWorldQuaternion = function(t) {
+ var e = wt,
+ r = Tt;
+ return void 0 === t && (t = new C), this.updateMatrixWorld(!0), this.matrixWorld.decompose(e, t, r), t
+ }, t.getWorldScale = function(t) {
+ var e = wt,
+ r = bt;
+ return void 0 === t && (t = new v), this.updateMatrixWorld(!0), this.matrixWorld.decompose(e, r, t), t
+ }, t.getWorldDirection = function(t) {
+ void 0 === t && (t = new v), this.updateMatrixWorld(!0);
+ var e = this.matrixWorld.elements;
+ return t.set(e[8], e[9], e[10]).normalize()
+ }, t.traverse = function(t) {
+ t(this);
+ for (var e = this.children, r = 0, n = e.length; r < n; r++) e[r].traverse(t)
+ }, t.traverseVisible = function(t) {
+ if (!1 !== this.visible) {
+ t(this);
+ for (var e = this.children, r = 0, n = e.length; r < n; r++) e[r].traverseVisible(t)
+ }
+ }, t.traverseAncestors = function(t) {
+ var e = this.parent;
+ null !== e && (t(e), e.traverseAncestors(t))
+ }, t.updateMatrix = function() {
+ this.matrix.compose(this.position, this.quaternion, this.scale), this.matrixWorldNeedsUpdate = !0
+ }, t.updateMatrixWorld = function(t) {
+ this.matrixAutoUpdate && this.updateMatrix(), (this.matrixWorldNeedsUpdate || t) && (null === this.parent ? this.matrixWorld.copy(this.matrix) : this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix), t = !(this.matrixWorldNeedsUpdate = !1));
+ for (var e = this.children, r = 0, n = e.length; r < n; r++) e[r].updateMatrixWorld(t)
+ }, t.updateWorldMatrix = function(t, e) {
+ var r = this.parent;
+ if (!0 === t && null !== r && r.updateWorldMatrix(!0, !1), this.matrixAutoUpdate && this.updateMatrix(), null === this.parent ? this.matrixWorld.copy(this.matrix) : this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix), !0 === e)
+ for (var n = this.children, i = 0, o = n.length; i < o; i++) n[i].updateWorldMatrix(!1, !0)
+ }, Object3D
+ }();
+ St.DefaultUp = new v(0, 1, 0), St.DefaultMatrixAutoUpdate = !0;
+ var Mt = function(e) {
+ var t, r;
+
+ function Group() {
+ var t;
+ return (t = e.call(this) || this).type = "Group", t.isGroup = !0, t
+ }
+ return r = e, (t = Group).prototype = Object.create(r.prototype), (t.prototype.constructor = t).__proto__ = r, Group
+ }(St);
+ var Et = function(e) {
+ var t, r;
+
+ function Bone() {
+ var t;
+ return (t = e.call(this) || this).type = "Bone", t.isBone = !0, t.root = !1, t
+ }
+ return r = e, (t = Bone).prototype = Object.create(r.prototype), (t.prototype.constructor = t).__proto__ = r, Bone
+ }(St),
+ At = 1,
+ Pt = function() {
+ function BufferGeometry() {
+ Object.defineProperty(this, "id", {
+ value: At += 2
+ }), this.uuid = generateUUID(), this.name = "", this.type = "BufferGeometry", this.index = null, this.attributes = {}, this.morphAttributes = {}, this.groups = [], this.isBufferGeometry = !0
+ }
+ var t = BufferGeometry.prototype;
+ return t.getIndex = function() {
+ return this.index
+ }, t.setIndex = function(t) {
+ Array.isArray(t) ? this.index = new(65535 < arrayMax(t) ? Uint32BufferAttribute : Uint16BufferAttribute)(t, 1) : this.index = t
+ }, t.addAttribute = function(t, e) {
+ return e && e.isBufferAttribute || e && e.isInterleavedBufferAttribute ? ("index" === t ? this.setIndex(e) : this.attributes[t] = e, this) : this.addAttribute(t, new o(e, arguments[2]))
+ }, t.getAttribute = function(t) {
+ return this.attributes[t]
+ }, t.removeAttribute = function(t) {
+ return delete this.attributes[t], this
+ }, t.addGroup = function(t, e, r) {
+ this.groups.push({
+ start: t,
+ count: e,
+ materialIndex: void 0 !== r ? r : 0
+ })
+ }, t.clearGroups = function() {
+ this.groups = []
+ }, t.applyMatrix = function(t) {
+ var e = this.attributes.position;
+ void 0 !== e && (t.applyToBufferAttribute(e), e.needsUpdate = !0);
+ var r = this.attributes.normal;
+ void 0 !== r && ((new w).getNormalMatrix(t).applyToBufferAttribute(r), r.needsUpdate = !0);
+ var n = this.attributes.tangent;
+ void 0 !== n && ((new w).getNormalMatrix(t).applyToBufferAttribute(n), n.needsUpdate = !0);
+ return this
+ }, BufferGeometry
+ }(),
+ It = 0,
+ Ot = function Texture(t, e, r, n, i, o, a, s, u, h) {
+ Object.defineProperty(this, "id", {
+ value: It++
+ }), this.uuid = generateUUID(), this.name = "", this.image = void 0 !== t ? t : Texture.DEFAULT_IMAGE, this.mapping = void 0 !== e ? e : Texture.DEFAULT_MAPPING, this.wrapS = void 0 !== r ? r : 33071, this.wrapT = void 0 !== n ? n : 33071, this.magFilter = void 0 !== i ? i : 1006, this.minFilter = void 0 !== o ? o : 1008, this.anisotropy = void 0 !== u ? u : 1, this.format = void 0 !== a ? a : 1023, this.type = void 0 !== s ? s : 1009, this.encoding = void 0 !== h ? h : 3e3
+ };
+ Ot.DEFAULT_IMAGE = void 0, Ot.DEFAULT_MAPPING = 300;
+ var Ct = new S,
+ Rt = new S,
+ Dt = function() {
+ function Skeleton(t, e) {
+ if (t = t || [], this.bones = t.slice(0), this.boneMatrices = new Float32Array(16 * this.bones.length), void 0 === e) this.calculateInverses();
+ else if (this.bones.length === e.length) this.boneInverses = e.slice(0);
+ else {
+ this.boneInverses = [];
+ for (var r = 0, n = this.bones.length; r < n; r++) this.boneInverses.push(new S)
+ }
+ }
+ var t = Skeleton.prototype;
+ return t.calculateInverses = function() {
+ this.boneInverses = [];
+ for (var t = 0, e = this.bones.length; t < e; t++) {
+ var r = new S;
+ this.bones[t] && r.getInverse(this.bones[t].matrixWorld), this.boneInverses.push(r)
+ }
+ }, t.pose = function() {
+ var t, e, r;
+ for (e = 0, r = this.bones.length; e < r; e++)(t = this.bones[e]) && t.matrixWorld.getInverse(this.boneInverses[e]);
+ for (e = 0, r = this.bones.length; e < r; e++)(t = this.bones[e]) && (t.parent && t.parent.isBone ? (t.matrix.getInverse(t.parent.matrixWorld), t.matrix.multiply(t.matrixWorld)) : t.matrix.copy(t.matrixWorld), t.matrix.decompose(t.position, t.quaternion, t.scale))
+ }, t.update = function() {
+ for (var t = Ct, e = Rt, r = this.bones, n = this.boneInverses, i = this.boneMatrices, o = this.boneTexture, a = 0, s = r.length; a < s; a++) {
+ var u = r[a] ? r[a].matrixWorld : e;
+ t.multiplyMatrices(u, n[a]), t.toArray(i, 16 * a)
+ }
+ void 0 !== o && (o.needsUpdate = !0)
+ }, t.clone = function() {
+ return new Skeleton(this.bones, this.boneInverses)
+ }, t.getBoneByName = function(t) {
+ for (var e = 0, r = this.bones.length; e < r; e++) {
+ var n = this.bones[e];
+ if (n.name === t) return n
+ }
+ }, Skeleton
+ }();
+ var Ft = function(n) {
+ var t, e;
+
+ function Mesh(t, e) {
+ var r;
+ return (r = n.call(this) || this).type = "Bone", r.isMesh = !0, r.geometry = void 0 !== t ? t : new Pt, r.material = void 0 !== e ? e : new MeshBasicMaterial({
+ color: 16777215 * Math.random()
+ }), r
+ }
+ return e = n, (t = Mesh).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e, Mesh
+ }(St);
+ var kt = function(n) {
+ var t, e;
+
+ function SkinnedMesh(t, e) {
+ var r;
+ return (r = n.call(this, t, e) || this).type = "SkinnedMesh", r.isSkinnedMesh = !0, r.bindMode = "attached", r.bindMatrix = new S, r.bindMatrixInverse = new S, r
+ }
+ e = n, (t = SkinnedMesh).prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e;
+ var r = SkinnedMesh.prototype;
+ return r.bind = function(t, e) {
+ this.skeleton = t, void 0 === e && (this.updateMatrixWorld(!0), this.skeleton.calculateInverses(), e = this.matrixWorld), this.bindMatrix.copy(e), this.bindMatrixInverse.getInverse(e)
+ }, r.pose = function() {
+ this.skeleton.pose()
+ }, r.normalizeSkinWeights = function() {
+ for (var t = new _, e = this.geometry.attributes.skinWeight, r = 0, n = e.count; r < n; r++) {
+ t.x = e.getX(r), t.y = e.getY(r), t.z = e.getZ(r), t.w = e.getW(r);
+ var i = 1 / t.manhattanLength();
+ i !== 1 / 0 ? t.multiplyScalar(i) : t.set(1, 0, 0, 0), e.setXYZW(r, t.x, t.y, t.z, t.w)
+ }
+ }, r.updateMatrixWorld = function(t) {
+ n.prototype.updateMatrixWorld.call(this, t), "attached" === this.bindMode ? this.bindMatrixInverse.getInverse(this.matrixWorld) : "detached" === this.bindMode && this.bindMatrixInverse.getInverse(this.bindMatrix)
+ }, SkinnedMesh
+ }(Ft);
+ r.d(e, "e", function() {
+ return o
+ }), r.d(e, "l", function() {
+ return a
+ }), r.d(e, "O", function() {
+ return s
+ }), r.d(e, "t", function() {
+ return n
+ }), r.d(e, "h", function() {
+ return m
+ }), r.d(e, "P", function() {
+ return v
+ }), r.d(e, "Q", function() {
+ return _
+ }), r.d(e, "u", function() {
+ return w
+ }), r.d(e, "v", function() {
+ return S
+ }), r.d(e, "G", function() {
+ return C
+ }), r.d(e, "k", function() {
+ return F
+ }), r.d(e, "I", function() {
+ return 10497
+ }), r.d(e, "g", function() {
+ return 33071
+ }), r.d(e, "S", function() {
+ return 2
+ }), r.d(e, "r", function() {
+ return 2200
+ }), r.d(e, "s", function() {
+ return 2201
+ }), r.d(e, "y", function() {
+ return j.a
+ }), r.d(e, "x", function() {
+ return X.a
+ }), r.d(e, "A", function() {
+ return tt
+ }), r.d(e, "H", function() {
+ return $
+ }), r.d(e, "R", function() {
+ return et
+ }), r.d(e, "b", function() {
+ return nt
+ }), r.d(e, "c", function() {
+ return yt
+ }), r.d(e, "F", function() {
+ return vt
+ }), r.d(e, "q", function() {
+ return i
+ }), r.d(e, "B", function() {
+ return St
+ }), r.d(e, "m", function() {
+ return Mt
+ }), r.d(e, "d", function() {
+ return Et
+ }), r.d(e, "f", function() {
+ return Pt
+ }), r.d(e, "N", function() {
+ return Ot
+ }), r.d(e, "J", function() {
+ return Dt
+ }), r.d(e, "w", function() {
+ return Ft
+ }), r.d(e, "K", function() {
+ return kt
+ })
+ }, function(t, e, r) {
+ "use strict";
+ e.__esModule = !0;
+ var i = function() {
+ function defineProperties(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n)
+ }
+ }
+ return function(t, e, r) {
+ return e && defineProperties(t.prototype, e), r && defineProperties(t, r), t
+ }
+ }(),
+ o = function(t) {
+ {
+ if (t && t.__esModule) return t;
+ var e = {};
+ if (null != t)
+ for (var r in t) Object.prototype.hasOwnProperty.call(t, r) && (e[r] = t[r]);
+ return e.default = t, e
+ }
+ }(r(0)),
+ n = _interopRequireDefault(r(418)),
+ a = _interopRequireDefault(r(423));
+
+ function _interopRequireDefault(t) {
+ return t && t.__esModule ? t : {
+ default: t
+ }
+ }
+ var s = function(n) {
+ function Entity3d(t) {
+ ! function(t, e) {
+ if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
+ }(this, Entity3d);
+ var e = function(t, e) {
+ if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return !e || "object" != typeof e && "function" != typeof e ? t : e
+ }(this, n.call(this));
+ if (t) {
+ if (!t.state) {
+ var r = new o.State;
+ r.depthTest = !0, r.blend = !1, r.culling = !0, t.state = r
+ }
+ e.add(a.default, t)
+ }
+ return e
+ }
+ return function(t, e) {
+ if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e);
+ t.prototype = Object.create(e && e.prototype, {
+ constructor: {
+ value: t,
+ enumerable: !1,
+ writable: !0,
+ configurable: !0
+ }
+ }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e)
+ }(Entity3d, n), i(Entity3d, [{
+ key: "x",
+ set: function(t) {
+ this.transform.position.x = t
+ },
+ get: function() {
+ return this.transform.position.x
+ }
+ }, {
+ key: "y",
+ set: function(t) {
+ this.transform.position.y = t
+ },
+ get: function() {
+ return this.transform.position.y
+ }
+ }, {
+ key: "z",
+ set: function(t) {
+ this.transform.position.z = t
+ },
+ get: function() {
+ return this.transform.position.z
+ }
+ }, {
+ key: "sx",
+ set: function(t) {
+ this.transform.scale.x = t
+ },
+ get: function() {
+ return this.transform.scale.x
+ }
+ }, {
+ key: "sy",
+ set: function(t) {
+ this.transform.scale.y = t
+ },
+ get: function() {
+ return this.transform.scale.y
+ }
+ }, {
+ key: "sz",
+ set: function(t) {
+ this.transform.scale.z = t
+ },
+ get: function() {
+ return this.transform.scale.z
+ }
+ }, {
+ key: "rx",
+ set: function(t) {
+ this.transform.rotation.x = t
+ },
+ get: function() {
+ return this.transform.rotation.x
+ }
+ }, {
+ key: "ry",
+ set: function(t) {
+ this.transform.rotation.y = t
+ },
+ get: function() {
+ return this.transform.rotation.y
+ }
+ }, {
+ key: "rz",
+ set: function(t) {
+ this.transform.rotation.z = t
+ },
+ get: function() {
+ return this.transform.rotation.z
+ }
+ }, {
+ key: "position",
+ get: function() {
+ return this.transform.position
+ }
+ }, {
+ key: "scale",
+ get: function() {
+ return this.transform.scale
+ }
+ }, {
+ key: "rotation",
+ get: function() {
+ return this.transform.rotation
+ }
+ }]), Entity3d
+ }(n.default);
+ e.default = s
+ }, function(t, e, r) {
+ "use strict";
+ r.r(e);
+ var n = {};
+ r.r(n), r.d(n, "EPSILON", function() {
+ return F
+ }), r.d(n, "ARRAY_TYPE", function() {
+ return g
+ }), r.d(n, "RANDOM", function() {
+ return d
+ }), r.d(n, "setMatrixArrayType", function() {
+ return setMatrixArrayType
+ }), r.d(n, "toRadian", function() {
+ return toRadian
+ }), r.d(n, "equals", function() {
+ return equals
+ });
+ var i = {};
+ r.r(i), r.d(i, "create", function() {
+ return create
+ }), r.d(i, "clone", function() {
+ return clone
+ }), r.d(i, "copy", function() {
+ return copy
+ }), r.d(i, "identity", function() {
+ return identity
+ }), r.d(i, "fromValues", function() {
+ return fromValues
+ }), r.d(i, "set", function() {
+ return set
+ }), r.d(i, "transpose", function() {
+ return transpose
+ }), r.d(i, "invert", function() {
+ return invert
+ }), r.d(i, "adjoint", function() {
+ return adjoint
+ }), r.d(i, "determinant", function() {
+ return determinant
+ }), r.d(i, "multiply", function() {
+ return multiply
+ }), r.d(i, "rotate", function() {
+ return rotate
+ }), r.d(i, "scale", function() {
+ return mat2_scale
+ }), r.d(i, "fromRotation", function() {
+ return fromRotation
+ }), r.d(i, "fromScaling", function() {
+ return fromScaling
+ }), r.d(i, "str", function() {
+ return str
+ }), r.d(i, "frob", function() {
+ return frob
+ }), r.d(i, "LDU", function() {
+ return LDU
+ }), r.d(i, "add", function() {
+ return add
+ }), r.d(i, "subtract", function() {
+ return subtract
+ }), r.d(i, "exactEquals", function() {
+ return exactEquals
+ }), r.d(i, "equals", function() {
+ return mat2_equals
+ }), r.d(i, "multiplyScalar", function() {
+ return multiplyScalar
+ }), r.d(i, "multiplyScalarAndAdd", function() {
+ return multiplyScalarAndAdd
+ }), r.d(i, "mul", function() {
+ return m
+ }), r.d(i, "sub", function() {
+ return v
+ });
+ var o = {};
+ r.r(o), r.d(o, "create", function() {
+ return mat2d_create
+ }), r.d(o, "clone", function() {
+ return mat2d_clone
+ }), r.d(o, "copy", function() {
+ return mat2d_copy
+ }), r.d(o, "identity", function() {
+ return mat2d_identity
+ }), r.d(o, "fromValues", function() {
+ return mat2d_fromValues
+ }), r.d(o, "set", function() {
+ return mat2d_set
+ }), r.d(o, "invert", function() {
+ return mat2d_invert
+ }), r.d(o, "determinant", function() {
+ return mat2d_determinant
+ }), r.d(o, "multiply", function() {
+ return mat2d_multiply
+ }), r.d(o, "rotate", function() {
+ return mat2d_rotate
+ }), r.d(o, "scale", function() {
+ return mat2d_scale
+ }), r.d(o, "translate", function() {
+ return translate
+ }), r.d(o, "fromRotation", function() {
+ return mat2d_fromRotation
+ }), r.d(o, "fromScaling", function() {
+ return mat2d_fromScaling
+ }), r.d(o, "fromTranslation", function() {
+ return fromTranslation
+ }), r.d(o, "str", function() {
+ return mat2d_str
+ }), r.d(o, "frob", function() {
+ return mat2d_frob
+ }), r.d(o, "add", function() {
+ return mat2d_add
+ }), r.d(o, "subtract", function() {
+ return mat2d_subtract
+ }), r.d(o, "multiplyScalar", function() {
+ return mat2d_multiplyScalar
+ }), r.d(o, "multiplyScalarAndAdd", function() {
+ return mat2d_multiplyScalarAndAdd
+ }), r.d(o, "exactEquals", function() {
+ return mat2d_exactEquals
+ }), r.d(o, "equals", function() {
+ return mat2d_equals
+ }), r.d(o, "mul", function() {
+ return y
+ }), r.d(o, "sub", function() {
+ return _
+ });
+ var a = {};
+ r.r(a), r.d(a, "create", function() {
+ return mat3_create
+ }), r.d(a, "fromMat4", function() {
+ return fromMat4
+ }), r.d(a, "clone", function() {
+ return mat3_clone
+ }), r.d(a, "copy", function() {
+ return mat3_copy
+ }), r.d(a, "fromValues", function() {
+ return mat3_fromValues
+ }), r.d(a, "set", function() {
+ return mat3_set
+ }), r.d(a, "identity", function() {
+ return mat3_identity
+ }), r.d(a, "transpose", function() {
+ return mat3_transpose
+ }), r.d(a, "invert", function() {
+ return mat3_invert
+ }), r.d(a, "adjoint", function() {
+ return mat3_adjoint
+ }), r.d(a, "determinant", function() {
+ return mat3_determinant
+ }), r.d(a, "multiply", function() {
+ return mat3_multiply
+ }), r.d(a, "translate", function() {
+ return mat3_translate
+ }), r.d(a, "rotate", function() {
+ return mat3_rotate
+ }), r.d(a, "scale", function() {
+ return mat3_scale
+ }), r.d(a, "fromTranslation", function() {
+ return mat3_fromTranslation
+ }), r.d(a, "fromRotation", function() {
+ return mat3_fromRotation
+ }), r.d(a, "fromScaling", function() {
+ return mat3_fromScaling
+ }), r.d(a, "fromMat2d", function() {
+ return fromMat2d
+ }), r.d(a, "fromQuat", function() {
+ return fromQuat
+ }), r.d(a, "normalFromMat4", function() {
+ return normalFromMat4
+ }), r.d(a, "projection", function() {
+ return projection
+ }), r.d(a, "str", function() {
+ return mat3_str
+ }), r.d(a, "frob", function() {
+ return mat3_frob
+ }), r.d(a, "add", function() {
+ return mat3_add
+ }), r.d(a, "subtract", function() {
+ return mat3_subtract
+ }), r.d(a, "multiplyScalar", function() {
+ return mat3_multiplyScalar
+ }), r.d(a, "multiplyScalarAndAdd", function() {
+ return mat3_multiplyScalarAndAdd
+ }), r.d(a, "exactEquals", function() {
+ return mat3_exactEquals
+ }), r.d(a, "equals", function() {
+ return mat3_equals
+ }), r.d(a, "mul", function() {
+ return b
+ }), r.d(a, "sub", function() {
+ return x
+ });
+ var s = {};
+ r.r(s), r.d(s, "create", function() {
+ return mat4_create
+ }), r.d(s, "clone", function() {
+ return mat4_clone
+ }), r.d(s, "copy", function() {
+ return mat4_copy
+ }), r.d(s, "fromValues", function() {
+ return mat4_fromValues
+ }), r.d(s, "set", function() {
+ return mat4_set
+ }), r.d(s, "identity", function() {
+ return mat4_identity
+ }), r.d(s, "transpose", function() {
+ return mat4_transpose
+ }), r.d(s, "invert", function() {
+ return mat4_invert
+ }), r.d(s, "adjoint", function() {
+ return mat4_adjoint
+ }), r.d(s, "determinant", function() {
+ return mat4_determinant
+ }), r.d(s, "multiply", function() {
+ return mat4_multiply
+ }), r.d(s, "translate", function() {
+ return mat4_translate
+ }), r.d(s, "scale", function() {
+ return mat4_scale
+ }), r.d(s, "rotate", function() {
+ return mat4_rotate
+ }), r.d(s, "rotateX", function() {
+ return rotateX
+ }), r.d(s, "rotateY", function() {
+ return rotateY
+ }), r.d(s, "rotateZ", function() {
+ return rotateZ
+ }), r.d(s, "fromTranslation", function() {
+ return mat4_fromTranslation
+ }), r.d(s, "fromScaling", function() {
+ return mat4_fromScaling
+ }), r.d(s, "fromRotation", function() {
+ return mat4_fromRotation
+ }), r.d(s, "fromXRotation", function() {
+ return fromXRotation
+ }), r.d(s, "fromYRotation", function() {
+ return fromYRotation
+ }), r.d(s, "fromZRotation", function() {
+ return fromZRotation
+ }), r.d(s, "fromRotationTranslation", function() {
+ return fromRotationTranslation
+ }), r.d(s, "fromQuat2", function() {
+ return fromQuat2
+ }), r.d(s, "getTranslation", function() {
+ return getTranslation
+ }), r.d(s, "getScaling", function() {
+ return getScaling
+ }), r.d(s, "getRotation", function() {
+ return getRotation
+ }), r.d(s, "fromRotationTranslationScale", function() {
+ return fromRotationTranslationScale
+ }), r.d(s, "fromRotationTranslationScaleOrigin", function() {
+ return fromRotationTranslationScaleOrigin
+ }), r.d(s, "fromQuat", function() {
+ return mat4_fromQuat
+ }), r.d(s, "frustum", function() {
+ return frustum
+ }), r.d(s, "perspective", function() {
+ return perspective
+ }), r.d(s, "perspectiveFromFieldOfView", function() {
+ return perspectiveFromFieldOfView
+ }), r.d(s, "ortho", function() {
+ return ortho
+ }), r.d(s, "lookAt", function() {
+ return lookAt
+ }), r.d(s, "targetTo", function() {
+ return targetTo
+ }), r.d(s, "str", function() {
+ return mat4_str
+ }), r.d(s, "frob", function() {
+ return mat4_frob
+ }), r.d(s, "add", function() {
+ return mat4_add
+ }), r.d(s, "subtract", function() {
+ return mat4_subtract
+ }), r.d(s, "multiplyScalar", function() {
+ return mat4_multiplyScalar
+ }), r.d(s, "multiplyScalarAndAdd", function() {
+ return mat4_multiplyScalarAndAdd
+ }), r.d(s, "exactEquals", function() {
+ return mat4_exactEquals
+ }), r.d(s, "equals", function() {
+ return mat4_equals
+ }), r.d(s, "mul", function() {
+ return w
+ }), r.d(s, "sub", function() {
+ return T
+ });
+ var u = {};
+ r.r(u), r.d(u, "create", function() {
+ return vec3_create
+ }), r.d(u, "clone", function() {
+ return vec3_clone
+ }), r.d(u, "length", function() {
+ return vec3_length
+ }), r.d(u, "fromValues", function() {
+ return vec3_fromValues
+ }), r.d(u, "copy", function() {
+ return vec3_copy
+ }), r.d(u, "set", function() {
+ return vec3_set
+ }), r.d(u, "add", function() {
+ return vec3_add
+ }), r.d(u, "subtract", function() {
+ return vec3_subtract
+ }), r.d(u, "multiply", function() {
+ return vec3_multiply
+ }), r.d(u, "divide", function() {
+ return divide
+ }), r.d(u, "ceil", function() {
+ return ceil
+ }), r.d(u, "floor", function() {
+ return floor
+ }), r.d(u, "min", function() {
+ return min
+ }), r.d(u, "max", function() {
+ return max
+ }), r.d(u, "round", function() {
+ return round
+ }), r.d(u, "scale", function() {
+ return vec3_scale
+ }), r.d(u, "scaleAndAdd", function() {
+ return scaleAndAdd
+ }), r.d(u, "distance", function() {
+ return distance
+ }), r.d(u, "squaredDistance", function() {
+ return squaredDistance
+ }), r.d(u, "squaredLength", function() {
+ return squaredLength
+ }), r.d(u, "negate", function() {
+ return negate
+ }), r.d(u, "inverse", function() {
+ return inverse
+ }), r.d(u, "normalize", function() {
+ return normalize
+ }), r.d(u, "dot", function() {
+ return vec3_dot
+ }), r.d(u, "cross", function() {
+ return cross
+ }), r.d(u, "lerp", function() {
+ return lerp
+ }), r.d(u, "hermite", function() {
+ return hermite
+ }), r.d(u, "bezier", function() {
+ return bezier
+ }), r.d(u, "random", function() {
+ return random
+ }), r.d(u, "transformMat4", function() {
+ return transformMat4
+ }), r.d(u, "transformMat3", function() {
+ return transformMat3
+ }), r.d(u, "transformQuat", function() {
+ return transformQuat
+ }), r.d(u, "rotateX", function() {
+ return vec3_rotateX
+ }), r.d(u, "rotateY", function() {
+ return vec3_rotateY
+ }), r.d(u, "rotateZ", function() {
+ return vec3_rotateZ
+ }), r.d(u, "angle", function() {
+ return angle
+ }), r.d(u, "str", function() {
+ return vec3_str
+ }), r.d(u, "exactEquals", function() {
+ return vec3_exactEquals
+ }), r.d(u, "equals", function() {
+ return vec3_equals
+ }), r.d(u, "sub", function() {
+ return M
+ }), r.d(u, "mul", function() {
+ return E
+ }), r.d(u, "div", function() {
+ return A
+ }), r.d(u, "dist", function() {
+ return P
+ }), r.d(u, "sqrDist", function() {
+ return I
+ }), r.d(u, "len", function() {
+ return O
+ }), r.d(u, "sqrLen", function() {
+ return C
+ }), r.d(u, "forEach", function() {
+ return R
+ });
+ var h = {};
+ r.r(h), r.d(h, "create", function() {
+ return vec4_create
+ }), r.d(h, "clone", function() {
+ return vec4_clone
+ }), r.d(h, "fromValues", function() {
+ return vec4_fromValues
+ }), r.d(h, "copy", function() {
+ return vec4_copy
+ }), r.d(h, "set", function() {
+ return vec4_set
+ }), r.d(h, "add", function() {
+ return vec4_add
+ }), r.d(h, "subtract", function() {
+ return vec4_subtract
+ }), r.d(h, "multiply", function() {
+ return vec4_multiply
+ }), r.d(h, "divide", function() {
+ return vec4_divide
+ }), r.d(h, "ceil", function() {
+ return vec4_ceil
+ }), r.d(h, "floor", function() {
+ return vec4_floor
+ }), r.d(h, "min", function() {
+ return vec4_min
+ }), r.d(h, "max", function() {
+ return vec4_max
+ }), r.d(h, "round", function() {
+ return vec4_round
+ }), r.d(h, "scale", function() {
+ return vec4_scale
+ }), r.d(h, "scaleAndAdd", function() {
+ return vec4_scaleAndAdd
+ }), r.d(h, "distance", function() {
+ return vec4_distance
+ }), r.d(h, "squaredDistance", function() {
+ return vec4_squaredDistance
+ }), r.d(h, "length", function() {
+ return vec4_length
+ }), r.d(h, "squaredLength", function() {
+ return vec4_squaredLength
+ }), r.d(h, "negate", function() {
+ return vec4_negate
+ }), r.d(h, "inverse", function() {
+ return vec4_inverse
+ }), r.d(h, "normalize", function() {
+ return vec4_normalize
+ }), r.d(h, "dot", function() {
+ return vec4_dot
+ }), r.d(h, "lerp", function() {
+ return vec4_lerp
+ }), r.d(h, "random", function() {
+ return vec4_random
+ }), r.d(h, "transformMat4", function() {
+ return vec4_transformMat4
+ }), r.d(h, "transformQuat", function() {
+ return vec4_transformQuat
+ }), r.d(h, "str", function() {
+ return vec4_str
+ }), r.d(h, "exactEquals", function() {
+ return vec4_exactEquals
+ }), r.d(h, "equals", function() {
+ return vec4_equals
+ }), r.d(h, "sub", function() {
+ return k
+ }), r.d(h, "mul", function() {
+ return L
+ }), r.d(h, "div", function() {
+ return N
+ }), r.d(h, "dist", function() {
+ return B
+ }), r.d(h, "sqrDist", function() {
+ return U
+ }), r.d(h, "len", function() {
+ return G
+ }), r.d(h, "sqrLen", function() {
+ return j
+ }), r.d(h, "forEach", function() {
+ return z
+ });
+ var c = {};
+ r.r(c), r.d(c, "create", function() {
+ return quat_create
+ }), r.d(c, "identity", function() {
+ return quat_identity
+ }), r.d(c, "setAxisAngle", function() {
+ return setAxisAngle
+ }), r.d(c, "getAxisAngle", function() {
+ return getAxisAngle
+ }), r.d(c, "multiply", function() {
+ return quat_multiply
+ }), r.d(c, "rotateX", function() {
+ return quat_rotateX
+ }), r.d(c, "rotateY", function() {
+ return quat_rotateY
+ }), r.d(c, "rotateZ", function() {
+ return quat_rotateZ
+ }), r.d(c, "calculateW", function() {
+ return calculateW
+ }), r.d(c, "slerp", function() {
+ return slerp
+ }), r.d(c, "random", function() {
+ return quat_random
+ }), r.d(c, "invert", function() {
+ return quat_invert
+ }), r.d(c, "conjugate", function() {
+ return conjugate
+ }), r.d(c, "fromMat3", function() {
+ return fromMat3
+ }), r.d(c, "fromEuler", function() {
+ return fromEuler
+ }), r.d(c, "str", function() {
+ return quat_str
+ }), r.d(c, "clone", function() {
+ return K
+ }), r.d(c, "fromValues", function() {
+ return Z
+ }), r.d(c, "copy", function() {
+ return Q
+ }), r.d(c, "set", function() {
+ return J
+ }), r.d(c, "add", function() {
+ return $
+ }), r.d(c, "mul", function() {
+ return tt
+ }), r.d(c, "scale", function() {
+ return et
+ }), r.d(c, "dot", function() {
+ return rt
+ }), r.d(c, "lerp", function() {
+ return nt
+ }), r.d(c, "length", function() {
+ return it
+ }), r.d(c, "len", function() {
+ return ot
+ }), r.d(c, "squaredLength", function() {
+ return at
+ }), r.d(c, "sqrLen", function() {
+ return st
+ }), r.d(c, "normalize", function() {
+ return ut
+ }), r.d(c, "exactEquals", function() {
+ return ht
+ }), r.d(c, "equals", function() {
+ return ct
+ }), r.d(c, "rotationTo", function() {
+ return lt
+ }), r.d(c, "sqlerp", function() {
+ return ft
+ }), r.d(c, "setAxes", function() {
+ return dt
+ });
+ var l = {};
+ r.r(l), r.d(l, "create", function() {
+ return quat2_create
+ }), r.d(l, "clone", function() {
+ return quat2_clone
+ }), r.d(l, "fromValues", function() {
+ return quat2_fromValues
+ }), r.d(l, "fromRotationTranslationValues", function() {
+ return fromRotationTranslationValues
+ }), r.d(l, "fromRotationTranslation", function() {
+ return quat2_fromRotationTranslation
+ }), r.d(l, "fromTranslation", function() {
+ return quat2_fromTranslation
+ }), r.d(l, "fromRotation", function() {
+ return quat2_fromRotation
+ }), r.d(l, "fromMat4", function() {
+ return quat2_fromMat4
+ }), r.d(l, "copy", function() {
+ return quat2_copy
+ }), r.d(l, "identity", function() {
+ return quat2_identity
+ }), r.d(l, "set", function() {
+ return quat2_set
+ }), r.d(l, "getReal", function() {
+ return pt
+ }), r.d(l, "getDual", function() {
+ return getDual
+ }), r.d(l, "setReal", function() {
+ return mt
+ }), r.d(l, "setDual", function() {
+ return setDual
+ }), r.d(l, "getTranslation", function() {
+ return quat2_getTranslation
+ }), r.d(l, "translate", function() {
+ return quat2_translate
+ }), r.d(l, "rotateX", function() {
+ return quat2_rotateX
+ }), r.d(l, "rotateY", function() {
+ return quat2_rotateY
+ }), r.d(l, "rotateZ", function() {
+ return quat2_rotateZ
+ }), r.d(l, "rotateByQuatAppend", function() {
+ return rotateByQuatAppend
+ }), r.d(l, "rotateByQuatPrepend", function() {
+ return rotateByQuatPrepend
+ }), r.d(l, "rotateAroundAxis", function() {
+ return rotateAroundAxis
+ }), r.d(l, "add", function() {
+ return quat2_add
+ }), r.d(l, "multiply", function() {
+ return quat2_multiply
+ }), r.d(l, "mul", function() {
+ return vt
+ }), r.d(l, "scale", function() {
+ return quat2_scale
+ }), r.d(l, "dot", function() {
+ return gt
+ }), r.d(l, "lerp", function() {
+ return quat2_lerp
+ }), r.d(l, "invert", function() {
+ return quat2_invert
+ }), r.d(l, "conjugate", function() {
+ return quat2_conjugate
+ }), r.d(l, "length", function() {
+ return yt
+ }), r.d(l, "len", function() {
+ return _t
+ }), r.d(l, "squaredLength", function() {
+ return bt
+ }), r.d(l, "sqrLen", function() {
+ return xt
+ }), r.d(l, "normalize", function() {
+ return quat2_normalize
+ }), r.d(l, "str", function() {
+ return quat2_str
+ }), r.d(l, "exactEquals", function() {
+ return quat2_exactEquals
+ }), r.d(l, "equals", function() {
+ return quat2_equals
+ });
+ var f = {};
+ r.r(f), r.d(f, "create", function() {
+ return vec2_create
+ }), r.d(f, "clone", function() {
+ return vec2_clone
+ }), r.d(f, "fromValues", function() {
+ return vec2_fromValues
+ }), r.d(f, "copy", function() {
+ return vec2_copy
+ }), r.d(f, "set", function() {
+ return vec2_set
+ }), r.d(f, "add", function() {
+ return vec2_add
+ }), r.d(f, "subtract", function() {
+ return vec2_subtract
+ }), r.d(f, "multiply", function() {
+ return vec2_multiply
+ }), r.d(f, "divide", function() {
+ return vec2_divide
+ }), r.d(f, "ceil", function() {
+ return vec2_ceil
+ }), r.d(f, "floor", function() {
+ return vec2_floor
+ }), r.d(f, "min", function() {
+ return vec2_min
+ }), r.d(f, "max", function() {
+ return vec2_max
+ }), r.d(f, "round", function() {
+ return vec2_round
+ }), r.d(f, "scale", function() {
+ return vec2_scale
+ }), r.d(f, "scaleAndAdd", function() {
+ return vec2_scaleAndAdd
+ }), r.d(f, "distance", function() {
+ return vec2_distance
+ }), r.d(f, "squaredDistance", function() {
+ return vec2_squaredDistance
+ }), r.d(f, "length", function() {
+ return vec2_length
+ }), r.d(f, "squaredLength", function() {
+ return vec2_squaredLength
+ }), r.d(f, "negate", function() {
+ return vec2_negate
+ }), r.d(f, "inverse", function() {
+ return vec2_inverse
+ }), r.d(f, "normalize", function() {
+ return vec2_normalize
+ }), r.d(f, "dot", function() {
+ return vec2_dot
+ }), r.d(f, "cross", function() {
+ return vec2_cross
+ }), r.d(f, "lerp", function() {
+ return vec2_lerp
+ }), r.d(f, "random", function() {
+ return vec2_random
+ }), r.d(f, "transformMat2", function() {
+ return transformMat2
+ }), r.d(f, "transformMat2d", function() {
+ return transformMat2d
+ }), r.d(f, "transformMat3", function() {
+ return vec2_transformMat3
+ }), r.d(f, "transformMat4", function() {
+ return vec2_transformMat4
+ }), r.d(f, "rotate", function() {
+ return vec2_rotate
+ }), r.d(f, "angle", function() {
+ return vec2_angle
+ }), r.d(f, "str", function() {
+ return vec2_str
+ }), r.d(f, "exactEquals", function() {
+ return vec2_exactEquals
+ }), r.d(f, "equals", function() {
+ return vec2_equals
+ }), r.d(f, "len", function() {
+ return Tt
+ }), r.d(f, "sub", function() {
+ return St
+ }), r.d(f, "mul", function() {
+ return Mt
+ }), r.d(f, "div", function() {
+ return Et
+ }), r.d(f, "dist", function() {
+ return At
+ }), r.d(f, "sqrDist", function() {
+ return Pt
+ }), r.d(f, "sqrLen", function() {
+ return It
+ }), r.d(f, "forEach", function() {
+ return Ot
+ });
+ var F = 1e-6,
+ g = "undefined" != typeof Float32Array ? Float32Array : Array,
+ d = Math.random;
+
+ function setMatrixArrayType(t) {
+ g = t
+ }
+ var p = Math.PI / 180;
+
+ function toRadian(t) {
+ return t * p
+ }
+
+ function equals(t, e) {
+ return Math.abs(t - e) <= F * Math.max(1, Math.abs(t), Math.abs(e))
+ }
+
+ function create() {
+ var t = new g(4);
+ return g != Float32Array && (t[1] = 0, t[2] = 0), t[0] = 1, t[3] = 1, t
+ }
+
+ function clone(t) {
+ var e = new g(4);
+ return e[0] = t[0], e[1] = t[1], e[2] = t[2], e[3] = t[3], e
+ }
+
+ function copy(t, e) {
+ return t[0] = e[0], t[1] = e[1], t[2] = e[2], t[3] = e[3], t
+ }
+
+ function identity(t) {
+ return t[0] = 1, t[1] = 0, t[2] = 0, t[3] = 1, t
+ }
+
+ function fromValues(t, e, r, n) {
+ var i = new g(4);
+ return i[0] = t, i[1] = e, i[2] = r, i[3] = n, i
+ }
+
+ function set(t, e, r, n, i) {
+ return t[0] = e, t[1] = r, t[2] = n, t[3] = i, t
+ }
+
+ function transpose(t, e) {
+ if (t === e) {
+ var r = e[1];
+ t[1] = e[2], t[2] = r
+ } else t[0] = e[0], t[1] = e[2], t[2] = e[1], t[3] = e[3];
+ return t
+ }
+
+ function invert(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[3],
+ a = r * o - i * n;
+ return a ? (a = 1 / a, t[0] = o * a, t[1] = -n * a, t[2] = -i * a, t[3] = r * a, t) : null
+ }
+
+ function adjoint(t, e) {
+ var r = e[0];
+ return t[0] = e[3], t[1] = -e[1], t[2] = -e[2], t[3] = r, t
+ }
+
+ function determinant(t) {
+ return t[0] * t[3] - t[2] * t[1]
+ }
+
+ function multiply(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = r[0],
+ u = r[1],
+ h = r[2],
+ c = r[3];
+ return t[0] = n * s + o * u, t[1] = i * s + a * u, t[2] = n * h + o * c, t[3] = i * h + a * c, t
+ }
+
+ function rotate(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = Math.sin(r),
+ u = Math.cos(r);
+ return t[0] = n * u + o * s, t[1] = i * u + a * s, t[2] = n * -s + o * u, t[3] = i * -s + a * u, t
+ }
+
+ function mat2_scale(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = r[0],
+ u = r[1];
+ return t[0] = n * s, t[1] = i * s, t[2] = o * u, t[3] = a * u, t
+ }
+
+ function fromRotation(t, e) {
+ var r = Math.sin(e),
+ n = Math.cos(e);
+ return t[0] = n, t[1] = r, t[2] = -r, t[3] = n, t
+ }
+
+ function fromScaling(t, e) {
+ return t[0] = e[0], t[1] = 0, t[2] = 0, t[3] = e[1], t
+ }
+
+ function str(t) {
+ return "mat2(" + t[0] + ", " + t[1] + ", " + t[2] + ", " + t[3] + ")"
+ }
+
+ function frob(t) {
+ return Math.sqrt(Math.pow(t[0], 2) + Math.pow(t[1], 2) + Math.pow(t[2], 2) + Math.pow(t[3], 2))
+ }
+
+ function LDU(t, e, r, n) {
+ return t[2] = n[2] / n[0], r[0] = n[0], r[1] = n[1], r[3] = n[3] - t[2] * r[1], [t, e, r]
+ }
+
+ function add(t, e, r) {
+ return t[0] = e[0] + r[0], t[1] = e[1] + r[1], t[2] = e[2] + r[2], t[3] = e[3] + r[3], t
+ }
+
+ function subtract(t, e, r) {
+ return t[0] = e[0] - r[0], t[1] = e[1] - r[1], t[2] = e[2] - r[2], t[3] = e[3] - r[3], t
+ }
+
+ function exactEquals(t, e) {
+ return t[0] === e[0] && t[1] === e[1] && t[2] === e[2] && t[3] === e[3]
+ }
+
+ function mat2_equals(t, e) {
+ var r = t[0],
+ n = t[1],
+ i = t[2],
+ o = t[3],
+ a = e[0],
+ s = e[1],
+ u = e[2],
+ h = e[3];
+ return Math.abs(r - a) <= F * Math.max(1, Math.abs(r), Math.abs(a)) && Math.abs(n - s) <= F * Math.max(1, Math.abs(n), Math.abs(s)) && Math.abs(i - u) <= F * Math.max(1, Math.abs(i), Math.abs(u)) && Math.abs(o - h) <= F * Math.max(1, Math.abs(o), Math.abs(h))
+ }
+
+ function multiplyScalar(t, e, r) {
+ return t[0] = e[0] * r, t[1] = e[1] * r, t[2] = e[2] * r, t[3] = e[3] * r, t
+ }
+
+ function multiplyScalarAndAdd(t, e, r, n) {
+ return t[0] = e[0] + r[0] * n, t[1] = e[1] + r[1] * n, t[2] = e[2] + r[2] * n, t[3] = e[3] + r[3] * n, t
+ }
+ var m = multiply,
+ v = subtract;
+
+ function mat2d_create() {
+ var t = new g(6);
+ return g != Float32Array && (t[1] = 0, t[2] = 0, t[4] = 0, t[5] = 0), t[0] = 1, t[3] = 1, t
+ }
+
+ function mat2d_clone(t) {
+ var e = new g(6);
+ return e[0] = t[0], e[1] = t[1], e[2] = t[2], e[3] = t[3], e[4] = t[4], e[5] = t[5], e
+ }
+
+ function mat2d_copy(t, e) {
+ return t[0] = e[0], t[1] = e[1], t[2] = e[2], t[3] = e[3], t[4] = e[4], t[5] = e[5], t
+ }
+
+ function mat2d_identity(t) {
+ return t[0] = 1, t[1] = 0, t[2] = 0, t[3] = 1, t[4] = 0, t[5] = 0, t
+ }
+
+ function mat2d_fromValues(t, e, r, n, i, o) {
+ var a = new g(6);
+ return a[0] = t, a[1] = e, a[2] = r, a[3] = n, a[4] = i, a[5] = o, a
+ }
+
+ function mat2d_set(t, e, r, n, i, o, a) {
+ return t[0] = e, t[1] = r, t[2] = n, t[3] = i, t[4] = o, t[5] = a, t
+ }
+
+ function mat2d_invert(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[3],
+ a = e[4],
+ s = e[5],
+ u = r * o - n * i;
+ return u ? (u = 1 / u, t[0] = o * u, t[1] = -n * u, t[2] = -i * u, t[3] = r * u, t[4] = (i * s - o * a) * u, t[5] = (n * a - r * s) * u, t) : null
+ }
+
+ function mat2d_determinant(t) {
+ return t[0] * t[3] - t[1] * t[2]
+ }
+
+ function mat2d_multiply(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = r[0],
+ c = r[1],
+ l = r[2],
+ f = r[3],
+ d = r[4],
+ p = r[5];
+ return t[0] = n * h + o * c, t[1] = i * h + a * c, t[2] = n * l + o * f, t[3] = i * l + a * f, t[4] = n * d + o * p + s, t[5] = i * d + a * p + u, t
+ }
+
+ function mat2d_rotate(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = Math.sin(r),
+ c = Math.cos(r);
+ return t[0] = n * c + o * h, t[1] = i * c + a * h, t[2] = n * -h + o * c, t[3] = i * -h + a * c, t[4] = s, t[5] = u, t
+ }
+
+ function mat2d_scale(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = r[0],
+ c = r[1];
+ return t[0] = n * h, t[1] = i * h, t[2] = o * c, t[3] = a * c, t[4] = s, t[5] = u, t
+ }
+
+ function translate(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = r[0],
+ c = r[1];
+ return t[0] = n, t[1] = i, t[2] = o, t[3] = a, t[4] = n * h + o * c + s, t[5] = i * h + a * c + u, t
+ }
+
+ function mat2d_fromRotation(t, e) {
+ var r = Math.sin(e),
+ n = Math.cos(e);
+ return t[0] = n, t[1] = r, t[2] = -r, t[3] = n, t[4] = 0, t[5] = 0, t
+ }
+
+ function mat2d_fromScaling(t, e) {
+ return t[0] = e[0], t[1] = 0, t[2] = 0, t[3] = e[1], t[4] = 0, t[5] = 0, t
+ }
+
+ function fromTranslation(t, e) {
+ return t[0] = 1, t[1] = 0, t[2] = 0, t[3] = 1, t[4] = e[0], t[5] = e[1], t
+ }
+
+ function mat2d_str(t) {
+ return "mat2d(" + t[0] + ", " + t[1] + ", " + t[2] + ", " + t[3] + ", " + t[4] + ", " + t[5] + ")"
+ }
+
+ function mat2d_frob(t) {
+ return Math.sqrt(Math.pow(t[0], 2) + Math.pow(t[1], 2) + Math.pow(t[2], 2) + Math.pow(t[3], 2) + Math.pow(t[4], 2) + Math.pow(t[5], 2) + 1)
+ }
+
+ function mat2d_add(t, e, r) {
+ return t[0] = e[0] + r[0], t[1] = e[1] + r[1], t[2] = e[2] + r[2], t[3] = e[3] + r[3], t[4] = e[4] + r[4], t[5] = e[5] + r[5], t
+ }
+
+ function mat2d_subtract(t, e, r) {
+ return t[0] = e[0] - r[0], t[1] = e[1] - r[1], t[2] = e[2] - r[2], t[3] = e[3] - r[3], t[4] = e[4] - r[4], t[5] = e[5] - r[5], t
+ }
+
+ function mat2d_multiplyScalar(t, e, r) {
+ return t[0] = e[0] * r, t[1] = e[1] * r, t[2] = e[2] * r, t[3] = e[3] * r, t[4] = e[4] * r, t[5] = e[5] * r, t
+ }
+
+ function mat2d_multiplyScalarAndAdd(t, e, r, n) {
+ return t[0] = e[0] + r[0] * n, t[1] = e[1] + r[1] * n, t[2] = e[2] + r[2] * n, t[3] = e[3] + r[3] * n, t[4] = e[4] + r[4] * n, t[5] = e[5] + r[5] * n, t
+ }
+
+ function mat2d_exactEquals(t, e) {
+ return t[0] === e[0] && t[1] === e[1] && t[2] === e[2] && t[3] === e[3] && t[4] === e[4] && t[5] === e[5]
+ }
+
+ function mat2d_equals(t, e) {
+ var r = t[0],
+ n = t[1],
+ i = t[2],
+ o = t[3],
+ a = t[4],
+ s = t[5],
+ u = e[0],
+ h = e[1],
+ c = e[2],
+ l = e[3],
+ f = e[4],
+ d = e[5];
+ return Math.abs(r - u) <= F * Math.max(1, Math.abs(r), Math.abs(u)) && Math.abs(n - h) <= F * Math.max(1, Math.abs(n), Math.abs(h)) && Math.abs(i - c) <= F * Math.max(1, Math.abs(i), Math.abs(c)) && Math.abs(o - l) <= F * Math.max(1, Math.abs(o), Math.abs(l)) && Math.abs(a - f) <= F * Math.max(1, Math.abs(a), Math.abs(f)) && Math.abs(s - d) <= F * Math.max(1, Math.abs(s), Math.abs(d))
+ }
+ var y = mat2d_multiply,
+ _ = mat2d_subtract;
+
+ function mat3_create() {
+ var t = new g(9);
+ return g != Float32Array && (t[1] = 0, t[2] = 0, t[3] = 0, t[5] = 0, t[6] = 0, t[7] = 0), t[0] = 1, t[4] = 1, t[8] = 1, t
+ }
+
+ function fromMat4(t, e) {
+ return t[0] = e[0], t[1] = e[1], t[2] = e[2], t[3] = e[4], t[4] = e[5], t[5] = e[6], t[6] = e[8], t[7] = e[9], t[8] = e[10], t
+ }
+
+ function mat3_clone(t) {
+ var e = new g(9);
+ return e[0] = t[0], e[1] = t[1], e[2] = t[2], e[3] = t[3], e[4] = t[4], e[5] = t[5], e[6] = t[6], e[7] = t[7], e[8] = t[8], e
+ }
+
+ function mat3_copy(t, e) {
+ return t[0] = e[0], t[1] = e[1], t[2] = e[2], t[3] = e[3], t[4] = e[4], t[5] = e[5], t[6] = e[6], t[7] = e[7], t[8] = e[8], t
+ }
+
+ function mat3_fromValues(t, e, r, n, i, o, a, s, u) {
+ var h = new g(9);
+ return h[0] = t, h[1] = e, h[2] = r, h[3] = n, h[4] = i, h[5] = o, h[6] = a, h[7] = s, h[8] = u, h
+ }
+
+ function mat3_set(t, e, r, n, i, o, a, s, u, h) {
+ return t[0] = e, t[1] = r, t[2] = n, t[3] = i, t[4] = o, t[5] = a, t[6] = s, t[7] = u, t[8] = h, t
+ }
+
+ function mat3_identity(t) {
+ return t[0] = 1, t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 1, t[5] = 0, t[6] = 0, t[7] = 0, t[8] = 1, t
+ }
+
+ function mat3_transpose(t, e) {
+ if (t === e) {
+ var r = e[1],
+ n = e[2],
+ i = e[5];
+ t[1] = e[3], t[2] = e[6], t[3] = r, t[5] = e[7], t[6] = n, t[7] = i
+ } else t[0] = e[0], t[1] = e[3], t[2] = e[6], t[3] = e[1], t[4] = e[4], t[5] = e[7], t[6] = e[2], t[7] = e[5], t[8] = e[8];
+ return t
+ }
+
+ function mat3_invert(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[3],
+ a = e[4],
+ s = e[5],
+ u = e[6],
+ h = e[7],
+ c = e[8],
+ l = c * a - s * h,
+ f = -c * o + s * u,
+ d = h * o - a * u,
+ p = r * l + n * f + i * d;
+ return p ? (p = 1 / p, t[0] = l * p, t[1] = (-c * n + i * h) * p, t[2] = (s * n - i * a) * p, t[3] = f * p, t[4] = (c * r - i * u) * p, t[5] = (-s * r + i * o) * p, t[6] = d * p, t[7] = (-h * r + n * u) * p, t[8] = (a * r - n * o) * p, t) : null
+ }
+
+ function mat3_adjoint(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[3],
+ a = e[4],
+ s = e[5],
+ u = e[6],
+ h = e[7],
+ c = e[8];
+ return t[0] = a * c - s * h, t[1] = i * h - n * c, t[2] = n * s - i * a, t[3] = s * u - o * c, t[4] = r * c - i * u, t[5] = i * o - r * s, t[6] = o * h - a * u, t[7] = n * u - r * h, t[8] = r * a - n * o, t
+ }
+
+ function mat3_determinant(t) {
+ var e = t[0],
+ r = t[1],
+ n = t[2],
+ i = t[3],
+ o = t[4],
+ a = t[5],
+ s = t[6],
+ u = t[7],
+ h = t[8];
+ return e * (h * o - a * u) + r * (-h * i + a * s) + n * (u * i - o * s)
+ }
+
+ function mat3_multiply(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = e[6],
+ c = e[7],
+ l = e[8],
+ f = r[0],
+ d = r[1],
+ p = r[2],
+ m = r[3],
+ v = r[4],
+ g = r[5],
+ y = r[6],
+ _ = r[7],
+ b = r[8];
+ return t[0] = f * n + d * a + p * h, t[1] = f * i + d * s + p * c, t[2] = f * o + d * u + p * l, t[3] = m * n + v * a + g * h, t[4] = m * i + v * s + g * c, t[5] = m * o + v * u + g * l, t[6] = y * n + _ * a + b * h, t[7] = y * i + _ * s + b * c, t[8] = y * o + _ * u + b * l, t
+ }
+
+ function mat3_translate(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = e[6],
+ c = e[7],
+ l = e[8],
+ f = r[0],
+ d = r[1];
+ return t[0] = n, t[1] = i, t[2] = o, t[3] = a, t[4] = s, t[5] = u, t[6] = f * n + d * a + h, t[7] = f * i + d * s + c, t[8] = f * o + d * u + l, t
+ }
+
+ function mat3_rotate(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = e[6],
+ c = e[7],
+ l = e[8],
+ f = Math.sin(r),
+ d = Math.cos(r);
+ return t[0] = d * n + f * a, t[1] = d * i + f * s, t[2] = d * o + f * u, t[3] = d * a - f * n, t[4] = d * s - f * i, t[5] = d * u - f * o, t[6] = h, t[7] = c, t[8] = l, t
+ }
+
+ function mat3_scale(t, e, r) {
+ var n = r[0],
+ i = r[1];
+ return t[0] = n * e[0], t[1] = n * e[1], t[2] = n * e[2], t[3] = i * e[3], t[4] = i * e[4], t[5] = i * e[5], t[6] = e[6], t[7] = e[7], t[8] = e[8], t
+ }
+
+ function mat3_fromTranslation(t, e) {
+ return t[0] = 1, t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 1, t[5] = 0, t[6] = e[0], t[7] = e[1], t[8] = 1, t
+ }
+
+ function mat3_fromRotation(t, e) {
+ var r = Math.sin(e),
+ n = Math.cos(e);
+ return t[0] = n, t[1] = r, t[2] = 0, t[3] = -r, t[4] = n, t[5] = 0, t[6] = 0, t[7] = 0, t[8] = 1, t
+ }
+
+ function mat3_fromScaling(t, e) {
+ return t[0] = e[0], t[1] = 0, t[2] = 0, t[3] = 0, t[4] = e[1], t[5] = 0, t[6] = 0, t[7] = 0, t[8] = 1, t
+ }
+
+ function fromMat2d(t, e) {
+ return t[0] = e[0], t[1] = e[1], t[2] = 0, t[3] = e[2], t[4] = e[3], t[5] = 0, t[6] = e[4], t[7] = e[5], t[8] = 1, t
+ }
+
+ function fromQuat(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[3],
+ a = r + r,
+ s = n + n,
+ u = i + i,
+ h = r * a,
+ c = n * a,
+ l = n * s,
+ f = i * a,
+ d = i * s,
+ p = i * u,
+ m = o * a,
+ v = o * s,
+ g = o * u;
+ return t[0] = 1 - l - p, t[3] = c - g, t[6] = f + v, t[1] = c + g, t[4] = 1 - h - p, t[7] = d - m, t[2] = f - v, t[5] = d + m, t[8] = 1 - h - l, t
+ }
+
+ function normalFromMat4(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[3],
+ a = e[4],
+ s = e[5],
+ u = e[6],
+ h = e[7],
+ c = e[8],
+ l = e[9],
+ f = e[10],
+ d = e[11],
+ p = e[12],
+ m = e[13],
+ v = e[14],
+ g = e[15],
+ y = r * s - n * a,
+ _ = r * u - i * a,
+ b = r * h - o * a,
+ x = n * u - i * s,
+ w = n * h - o * s,
+ T = i * h - o * u,
+ S = c * m - l * p,
+ M = c * v - f * p,
+ E = c * g - d * p,
+ A = l * v - f * m,
+ P = l * g - d * m,
+ I = f * g - d * v,
+ O = y * I - _ * P + b * A + x * E - w * M + T * S;
+ return O ? (O = 1 / O, t[0] = (s * I - u * P + h * A) * O, t[1] = (u * E - a * I - h * M) * O, t[2] = (a * P - s * E + h * S) * O, t[3] = (i * P - n * I - o * A) * O, t[4] = (r * I - i * E + o * M) * O, t[5] = (n * E - r * P - o * S) * O, t[6] = (m * T - v * w + g * x) * O, t[7] = (v * b - p * T - g * _) * O, t[8] = (p * w - m * b + g * y) * O, t) : null
+ }
+
+ function projection(t, e, r) {
+ return t[0] = 2 / e, t[1] = 0, t[2] = 0, t[3] = 0, t[4] = -2 / r, t[5] = 0, t[6] = -1, t[7] = 1, t[8] = 1, t
+ }
+
+ function mat3_str(t) {
+ return "mat3(" + t[0] + ", " + t[1] + ", " + t[2] + ", " + t[3] + ", " + t[4] + ", " + t[5] + ", " + t[6] + ", " + t[7] + ", " + t[8] + ")"
+ }
+
+ function mat3_frob(t) {
+ return Math.sqrt(Math.pow(t[0], 2) + Math.pow(t[1], 2) + Math.pow(t[2], 2) + Math.pow(t[3], 2) + Math.pow(t[4], 2) + Math.pow(t[5], 2) + Math.pow(t[6], 2) + Math.pow(t[7], 2) + Math.pow(t[8], 2))
+ }
+
+ function mat3_add(t, e, r) {
+ return t[0] = e[0] + r[0], t[1] = e[1] + r[1], t[2] = e[2] + r[2], t[3] = e[3] + r[3], t[4] = e[4] + r[4], t[5] = e[5] + r[5], t[6] = e[6] + r[6], t[7] = e[7] + r[7], t[8] = e[8] + r[8], t
+ }
+
+ function mat3_subtract(t, e, r) {
+ return t[0] = e[0] - r[0], t[1] = e[1] - r[1], t[2] = e[2] - r[2], t[3] = e[3] - r[3], t[4] = e[4] - r[4], t[5] = e[5] - r[5], t[6] = e[6] - r[6], t[7] = e[7] - r[7], t[8] = e[8] - r[8], t
+ }
+
+ function mat3_multiplyScalar(t, e, r) {
+ return t[0] = e[0] * r, t[1] = e[1] * r, t[2] = e[2] * r, t[3] = e[3] * r, t[4] = e[4] * r, t[5] = e[5] * r, t[6] = e[6] * r, t[7] = e[7] * r, t[8] = e[8] * r, t
+ }
+
+ function mat3_multiplyScalarAndAdd(t, e, r, n) {
+ return t[0] = e[0] + r[0] * n, t[1] = e[1] + r[1] * n, t[2] = e[2] + r[2] * n, t[3] = e[3] + r[3] * n, t[4] = e[4] + r[4] * n, t[5] = e[5] + r[5] * n, t[6] = e[6] + r[6] * n, t[7] = e[7] + r[7] * n, t[8] = e[8] + r[8] * n, t
+ }
+
+ function mat3_exactEquals(t, e) {
+ return t[0] === e[0] && t[1] === e[1] && t[2] === e[2] && t[3] === e[3] && t[4] === e[4] && t[5] === e[5] && t[6] === e[6] && t[7] === e[7] && t[8] === e[8]
+ }
+
+ function mat3_equals(t, e) {
+ var r = t[0],
+ n = t[1],
+ i = t[2],
+ o = t[3],
+ a = t[4],
+ s = t[5],
+ u = t[6],
+ h = t[7],
+ c = t[8],
+ l = e[0],
+ f = e[1],
+ d = e[2],
+ p = e[3],
+ m = e[4],
+ v = e[5],
+ g = e[6],
+ y = e[7],
+ _ = e[8];
+ return Math.abs(r - l) <= F * Math.max(1, Math.abs(r), Math.abs(l)) && Math.abs(n - f) <= F * Math.max(1, Math.abs(n), Math.abs(f)) && Math.abs(i - d) <= F * Math.max(1, Math.abs(i), Math.abs(d)) && Math.abs(o - p) <= F * Math.max(1, Math.abs(o), Math.abs(p)) && Math.abs(a - m) <= F * Math.max(1, Math.abs(a), Math.abs(m)) && Math.abs(s - v) <= F * Math.max(1, Math.abs(s), Math.abs(v)) && Math.abs(u - g) <= F * Math.max(1, Math.abs(u), Math.abs(g)) && Math.abs(h - y) <= F * Math.max(1, Math.abs(h), Math.abs(y)) && Math.abs(c - _) <= F * Math.max(1, Math.abs(c), Math.abs(_))
+ }
+ var b = mat3_multiply,
+ x = mat3_subtract;
+
+ function mat4_create() {
+ var t = new g(16);
+ return g != Float32Array && (t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 0, t[6] = 0, t[7] = 0, t[8] = 0, t[9] = 0, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0), t[0] = 1, t[5] = 1, t[10] = 1, t[15] = 1, t
+ }
+
+ function mat4_clone(t) {
+ var e = new g(16);
+ return e[0] = t[0], e[1] = t[1], e[2] = t[2], e[3] = t[3], e[4] = t[4], e[5] = t[5], e[6] = t[6], e[7] = t[7], e[8] = t[8], e[9] = t[9], e[10] = t[10], e[11] = t[11], e[12] = t[12], e[13] = t[13], e[14] = t[14], e[15] = t[15], e
+ }
+
+ function mat4_copy(t, e) {
+ return t[0] = e[0], t[1] = e[1], t[2] = e[2], t[3] = e[3], t[4] = e[4], t[5] = e[5], t[6] = e[6], t[7] = e[7], t[8] = e[8], t[9] = e[9], t[10] = e[10], t[11] = e[11], t[12] = e[12], t[13] = e[13], t[14] = e[14], t[15] = e[15], t
+ }
+
+ function mat4_fromValues(t, e, r, n, i, o, a, s, u, h, c, l, f, d, p, m) {
+ var v = new g(16);
+ return v[0] = t, v[1] = e, v[2] = r, v[3] = n, v[4] = i, v[5] = o, v[6] = a, v[7] = s, v[8] = u, v[9] = h, v[10] = c, v[11] = l, v[12] = f, v[13] = d, v[14] = p, v[15] = m, v
+ }
+
+ function mat4_set(t, e, r, n, i, o, a, s, u, h, c, l, f, d, p, m, v) {
+ return t[0] = e, t[1] = r, t[2] = n, t[3] = i, t[4] = o, t[5] = a, t[6] = s, t[7] = u, t[8] = h, t[9] = c, t[10] = l, t[11] = f, t[12] = d, t[13] = p, t[14] = m, t[15] = v, t
+ }
+
+ function mat4_identity(t) {
+ return t[0] = 1, t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 0, t[5] = 1, t[6] = 0, t[7] = 0, t[8] = 0, t[9] = 0, t[10] = 1, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, t
+ }
+
+ function mat4_transpose(t, e) {
+ if (t === e) {
+ var r = e[1],
+ n = e[2],
+ i = e[3],
+ o = e[6],
+ a = e[7],
+ s = e[11];
+ t[1] = e[4], t[2] = e[8], t[3] = e[12], t[4] = r, t[6] = e[9], t[7] = e[13], t[8] = n, t[9] = o, t[11] = e[14], t[12] = i, t[13] = a, t[14] = s
+ } else t[0] = e[0], t[1] = e[4], t[2] = e[8], t[3] = e[12], t[4] = e[1], t[5] = e[5], t[6] = e[9], t[7] = e[13], t[8] = e[2], t[9] = e[6], t[10] = e[10], t[11] = e[14], t[12] = e[3], t[13] = e[7], t[14] = e[11], t[15] = e[15];
+ return t
+ }
+
+ function mat4_invert(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[3],
+ a = e[4],
+ s = e[5],
+ u = e[6],
+ h = e[7],
+ c = e[8],
+ l = e[9],
+ f = e[10],
+ d = e[11],
+ p = e[12],
+ m = e[13],
+ v = e[14],
+ g = e[15],
+ y = r * s - n * a,
+ _ = r * u - i * a,
+ b = r * h - o * a,
+ x = n * u - i * s,
+ w = n * h - o * s,
+ T = i * h - o * u,
+ S = c * m - l * p,
+ M = c * v - f * p,
+ E = c * g - d * p,
+ A = l * v - f * m,
+ P = l * g - d * m,
+ I = f * g - d * v,
+ O = y * I - _ * P + b * A + x * E - w * M + T * S;
+ return O ? (O = 1 / O, t[0] = (s * I - u * P + h * A) * O, t[1] = (i * P - n * I - o * A) * O, t[2] = (m * T - v * w + g * x) * O, t[3] = (f * w - l * T - d * x) * O, t[4] = (u * E - a * I - h * M) * O, t[5] = (r * I - i * E + o * M) * O, t[6] = (v * b - p * T - g * _) * O, t[7] = (c * T - f * b + d * _) * O, t[8] = (a * P - s * E + h * S) * O, t[9] = (n * E - r * P - o * S) * O, t[10] = (p * w - m * b + g * y) * O, t[11] = (l * b - c * w - d * y) * O, t[12] = (s * M - a * A - u * S) * O, t[13] = (r * A - n * M + i * S) * O, t[14] = (m * _ - p * x - v * y) * O, t[15] = (c * x - l * _ + f * y) * O, t) : null
+ }
+
+ function mat4_adjoint(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[3],
+ a = e[4],
+ s = e[5],
+ u = e[6],
+ h = e[7],
+ c = e[8],
+ l = e[9],
+ f = e[10],
+ d = e[11],
+ p = e[12],
+ m = e[13],
+ v = e[14],
+ g = e[15];
+ return t[0] = s * (f * g - d * v) - l * (u * g - h * v) + m * (u * d - h * f), t[1] = -(n * (f * g - d * v) - l * (i * g - o * v) + m * (i * d - o * f)), t[2] = n * (u * g - h * v) - s * (i * g - o * v) + m * (i * h - o * u), t[3] = -(n * (u * d - h * f) - s * (i * d - o * f) + l * (i * h - o * u)), t[4] = -(a * (f * g - d * v) - c * (u * g - h * v) + p * (u * d - h * f)), t[5] = r * (f * g - d * v) - c * (i * g - o * v) + p * (i * d - o * f), t[6] = -(r * (u * g - h * v) - a * (i * g - o * v) + p * (i * h - o * u)), t[7] = r * (u * d - h * f) - a * (i * d - o * f) + c * (i * h - o * u), t[8] = a * (l * g - d * m) - c * (s * g - h * m) + p * (s * d - h * l), t[9] = -(r * (l * g - d * m) - c * (n * g - o * m) + p * (n * d - o * l)), t[10] = r * (s * g - h * m) - a * (n * g - o * m) + p * (n * h - o * s), t[11] = -(r * (s * d - h * l) - a * (n * d - o * l) + c * (n * h - o * s)), t[12] = -(a * (l * v - f * m) - c * (s * v - u * m) + p * (s * f - u * l)), t[13] = r * (l * v - f * m) - c * (n * v - i * m) + p * (n * f - i * l), t[14] = -(r * (s * v - u * m) - a * (n * v - i * m) + p * (n * u - i * s)), t[15] = r * (s * f - u * l) - a * (n * f - i * l) + c * (n * u - i * s), t
+ }
+
+ function mat4_determinant(t) {
+ var e = t[0],
+ r = t[1],
+ n = t[2],
+ i = t[3],
+ o = t[4],
+ a = t[5],
+ s = t[6],
+ u = t[7],
+ h = t[8],
+ c = t[9],
+ l = t[10],
+ f = t[11],
+ d = t[12],
+ p = t[13],
+ m = t[14],
+ v = t[15];
+ return (e * a - r * o) * (l * v - f * m) - (e * s - n * o) * (c * v - f * p) + (e * u - i * o) * (c * m - l * p) + (r * s - n * a) * (h * v - f * d) - (r * u - i * a) * (h * m - l * d) + (n * u - i * s) * (h * p - c * d)
+ }
+
+ function mat4_multiply(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = e[6],
+ c = e[7],
+ l = e[8],
+ f = e[9],
+ d = e[10],
+ p = e[11],
+ m = e[12],
+ v = e[13],
+ g = e[14],
+ y = e[15],
+ _ = r[0],
+ b = r[1],
+ x = r[2],
+ w = r[3];
+ return t[0] = _ * n + b * s + x * l + w * m, t[1] = _ * i + b * u + x * f + w * v, t[2] = _ * o + b * h + x * d + w * g, t[3] = _ * a + b * c + x * p + w * y, _ = r[4], b = r[5], x = r[6], w = r[7], t[4] = _ * n + b * s + x * l + w * m, t[5] = _ * i + b * u + x * f + w * v, t[6] = _ * o + b * h + x * d + w * g, t[7] = _ * a + b * c + x * p + w * y, _ = r[8], b = r[9], x = r[10], w = r[11], t[8] = _ * n + b * s + x * l + w * m, t[9] = _ * i + b * u + x * f + w * v, t[10] = _ * o + b * h + x * d + w * g, t[11] = _ * a + b * c + x * p + w * y, _ = r[12], b = r[13], x = r[14], w = r[15], t[12] = _ * n + b * s + x * l + w * m, t[13] = _ * i + b * u + x * f + w * v, t[14] = _ * o + b * h + x * d + w * g, t[15] = _ * a + b * c + x * p + w * y, t
+ }
+
+ function mat4_translate(t, e, r) {
+ var n = r[0],
+ i = r[1],
+ o = r[2],
+ a = void 0,
+ s = void 0,
+ u = void 0,
+ h = void 0,
+ c = void 0,
+ l = void 0,
+ f = void 0,
+ d = void 0,
+ p = void 0,
+ m = void 0,
+ v = void 0,
+ g = void 0;
+ return t[15] = e === t ? (t[12] = e[0] * n + e[4] * i + e[8] * o + e[12], t[13] = e[1] * n + e[5] * i + e[9] * o + e[13], t[14] = e[2] * n + e[6] * i + e[10] * o + e[14], e[3] * n + e[7] * i + e[11] * o + e[15]) : (a = e[0], s = e[1], u = e[2], h = e[3], c = e[4], l = e[5], f = e[6], d = e[7], p = e[8], m = e[9], v = e[10], g = e[11], t[0] = a, t[1] = s, t[2] = u, t[3] = h, t[4] = c, t[5] = l, t[6] = f, t[7] = d, t[8] = p, t[9] = m, t[10] = v, t[11] = g, t[12] = a * n + c * i + p * o + e[12], t[13] = s * n + l * i + m * o + e[13], t[14] = u * n + f * i + v * o + e[14], h * n + d * i + g * o + e[15]), t
+ }
+
+ function mat4_scale(t, e, r) {
+ var n = r[0],
+ i = r[1],
+ o = r[2];
+ return t[0] = e[0] * n, t[1] = e[1] * n, t[2] = e[2] * n, t[3] = e[3] * n, t[4] = e[4] * i, t[5] = e[5] * i, t[6] = e[6] * i, t[7] = e[7] * i, t[8] = e[8] * o, t[9] = e[9] * o, t[10] = e[10] * o, t[11] = e[11] * o, t[12] = e[12], t[13] = e[13], t[14] = e[14], t[15] = e[15], t
+ }
+
+ function mat4_rotate(t, e, r, n) {
+ var i, o, a, s, u, h, c, l, f, d, p, m, v, g, y, _, b, x, w, T, S, M, E, A, P = n[0],
+ I = n[1],
+ O = n[2],
+ C = Math.sqrt(P * P + I * I + O * O);
+ return C < F ? null : (P *= C = 1 / C, I *= C, O *= C, i = Math.sin(r), a = 1 - (o = Math.cos(r)), s = e[0], u = e[1], h = e[2], c = e[3], l = e[4], f = e[5], d = e[6], p = e[7], m = e[8], v = e[9], g = e[10], y = e[11], _ = P * P * a + o, b = I * P * a + O * i, x = O * P * a - I * i, w = P * I * a - O * i, T = I * I * a + o, S = O * I * a + P * i, M = P * O * a + I * i, E = I * O * a - P * i, A = O * O * a + o, t[0] = s * _ + l * b + m * x, t[1] = u * _ + f * b + v * x, t[2] = h * _ + d * b + g * x, t[3] = c * _ + p * b + y * x, t[4] = s * w + l * T + m * S, t[5] = u * w + f * T + v * S, t[6] = h * w + d * T + g * S, t[7] = c * w + p * T + y * S, t[8] = s * M + l * E + m * A, t[9] = u * M + f * E + v * A, t[10] = h * M + d * E + g * A, t[11] = c * M + p * E + y * A, e !== t && (t[12] = e[12], t[13] = e[13], t[14] = e[14], t[15] = e[15]), t)
+ }
+
+ function rotateX(t, e, r) {
+ var n = Math.sin(r),
+ i = Math.cos(r),
+ o = e[4],
+ a = e[5],
+ s = e[6],
+ u = e[7],
+ h = e[8],
+ c = e[9],
+ l = e[10],
+ f = e[11];
+ return e !== t && (t[0] = e[0], t[1] = e[1], t[2] = e[2], t[3] = e[3], t[12] = e[12], t[13] = e[13], t[14] = e[14], t[15] = e[15]), t[4] = o * i + h * n, t[5] = a * i + c * n, t[6] = s * i + l * n, t[7] = u * i + f * n, t[8] = h * i - o * n, t[9] = c * i - a * n, t[10] = l * i - s * n, t[11] = f * i - u * n, t
+ }
+
+ function rotateY(t, e, r) {
+ var n = Math.sin(r),
+ i = Math.cos(r),
+ o = e[0],
+ a = e[1],
+ s = e[2],
+ u = e[3],
+ h = e[8],
+ c = e[9],
+ l = e[10],
+ f = e[11];
+ return e !== t && (t[4] = e[4], t[5] = e[5], t[6] = e[6], t[7] = e[7], t[12] = e[12], t[13] = e[13], t[14] = e[14], t[15] = e[15]), t[0] = o * i - h * n, t[1] = a * i - c * n, t[2] = s * i - l * n, t[3] = u * i - f * n, t[8] = o * n + h * i, t[9] = a * n + c * i, t[10] = s * n + l * i, t[11] = u * n + f * i, t
+ }
+
+ function rotateZ(t, e, r) {
+ var n = Math.sin(r),
+ i = Math.cos(r),
+ o = e[0],
+ a = e[1],
+ s = e[2],
+ u = e[3],
+ h = e[4],
+ c = e[5],
+ l = e[6],
+ f = e[7];
+ return e !== t && (t[8] = e[8], t[9] = e[9], t[10] = e[10], t[11] = e[11], t[12] = e[12], t[13] = e[13], t[14] = e[14], t[15] = e[15]), t[0] = o * i + h * n, t[1] = a * i + c * n, t[2] = s * i + l * n, t[3] = u * i + f * n, t[4] = h * i - o * n, t[5] = c * i - a * n, t[6] = l * i - s * n, t[7] = f * i - u * n, t
+ }
+
+ function mat4_fromTranslation(t, e) {
+ return t[0] = 1, t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 0, t[5] = 1, t[6] = 0, t[7] = 0, t[8] = 0, t[9] = 0, t[10] = 1, t[11] = 0, t[12] = e[0], t[13] = e[1], t[14] = e[2], t[15] = 1, t
+ }
+
+ function mat4_fromScaling(t, e) {
+ return t[0] = e[0], t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 0, t[5] = e[1], t[6] = 0, t[7] = 0, t[8] = 0, t[9] = 0, t[10] = e[2], t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, t
+ }
+
+ function mat4_fromRotation(t, e, r) {
+ var n, i, o, a = r[0],
+ s = r[1],
+ u = r[2],
+ h = Math.sqrt(a * a + s * s + u * u);
+ return h < F ? null : (a *= h = 1 / h, s *= h, u *= h, n = Math.sin(e), o = 1 - (i = Math.cos(e)), t[0] = a * a * o + i, t[1] = s * a * o + u * n, t[2] = u * a * o - s * n, t[3] = 0, t[4] = a * s * o - u * n, t[5] = s * s * o + i, t[6] = u * s * o + a * n, t[7] = 0, t[8] = a * u * o + s * n, t[9] = s * u * o - a * n, t[10] = u * u * o + i, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, t)
+ }
+
+ function fromXRotation(t, e) {
+ var r = Math.sin(e),
+ n = Math.cos(e);
+ return t[0] = 1, t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 0, t[5] = n, t[6] = r, t[7] = 0, t[8] = 0, t[9] = -r, t[10] = n, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, t
+ }
+
+ function fromYRotation(t, e) {
+ var r = Math.sin(e),
+ n = Math.cos(e);
+ return t[0] = n, t[1] = 0, t[2] = -r, t[3] = 0, t[4] = 0, t[5] = 1, t[6] = 0, t[7] = 0, t[8] = r, t[9] = 0, t[10] = n, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, t
+ }
+
+ function fromZRotation(t, e) {
+ var r = Math.sin(e),
+ n = Math.cos(e);
+ return t[0] = n, t[1] = r, t[2] = 0, t[3] = 0, t[4] = -r, t[5] = n, t[6] = 0, t[7] = 0, t[8] = 0, t[9] = 0, t[10] = 1, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, t
+ }
+
+ function fromRotationTranslation(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = n + n,
+ u = i + i,
+ h = o + o,
+ c = n * s,
+ l = n * u,
+ f = n * h,
+ d = i * u,
+ p = i * h,
+ m = o * h,
+ v = a * s,
+ g = a * u,
+ y = a * h;
+ return t[0] = 1 - (d + m), t[1] = l + y, t[2] = f - g, t[3] = 0, t[4] = l - y, t[5] = 1 - (c + m), t[6] = p + v, t[7] = 0, t[8] = f + g, t[9] = p - v, t[10] = 1 - (c + d), t[11] = 0, t[12] = r[0], t[13] = r[1], t[14] = r[2], t[15] = 1, t
+ }
+
+ function fromQuat2(t, e) {
+ var r = new g(3),
+ n = -e[0],
+ i = -e[1],
+ o = -e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = e[6],
+ c = e[7],
+ l = n * n + i * i + o * o + a * a;
+ return r[2] = 0 < l ? (r[0] = 2 * (s * a + c * n + u * o - h * i) / l, r[1] = 2 * (u * a + c * i + h * n - s * o) / l, 2 * (h * a + c * o + s * i - u * n) / l) : (r[0] = 2 * (s * a + c * n + u * o - h * i), r[1] = 2 * (u * a + c * i + h * n - s * o), 2 * (h * a + c * o + s * i - u * n)), fromRotationTranslation(t, e, r), t
+ }
+
+ function getTranslation(t, e) {
+ return t[0] = e[12], t[1] = e[13], t[2] = e[14], t
+ }
+
+ function getScaling(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[4],
+ a = e[5],
+ s = e[6],
+ u = e[8],
+ h = e[9],
+ c = e[10];
+ return t[0] = Math.sqrt(r * r + n * n + i * i), t[1] = Math.sqrt(o * o + a * a + s * s), t[2] = Math.sqrt(u * u + h * h + c * c), t
+ }
+
+ function getRotation(t, e) {
+ var r = e[0] + e[5] + e[10],
+ n = 0;
+ return 0 < r ? (n = 2 * Math.sqrt(r + 1), t[3] = .25 * n, t[0] = (e[6] - e[9]) / n, t[1] = (e[8] - e[2]) / n, t[2] = (e[1] - e[4]) / n) : e[0] > e[5] && e[0] > e[10] ? (n = 2 * Math.sqrt(1 + e[0] - e[5] - e[10]), t[3] = (e[6] - e[9]) / n, t[0] = .25 * n, t[1] = (e[1] + e[4]) / n, t[2] = (e[8] + e[2]) / n) : e[5] > e[10] ? (n = 2 * Math.sqrt(1 + e[5] - e[0] - e[10]), t[3] = (e[8] - e[2]) / n, t[0] = (e[1] + e[4]) / n, t[1] = .25 * n, t[2] = (e[6] + e[9]) / n) : (n = 2 * Math.sqrt(1 + e[10] - e[0] - e[5]), t[3] = (e[1] - e[4]) / n, t[0] = (e[8] + e[2]) / n, t[1] = (e[6] + e[9]) / n, t[2] = .25 * n), t
+ }
+
+ function fromRotationTranslationScale(t, e, r, n) {
+ var i = e[0],
+ o = e[1],
+ a = e[2],
+ s = e[3],
+ u = i + i,
+ h = o + o,
+ c = a + a,
+ l = i * u,
+ f = i * h,
+ d = i * c,
+ p = o * h,
+ m = o * c,
+ v = a * c,
+ g = s * u,
+ y = s * h,
+ _ = s * c,
+ b = n[0],
+ x = n[1],
+ w = n[2];
+ return t[0] = (1 - (p + v)) * b, t[1] = (f + _) * b, t[2] = (d - y) * b, t[3] = 0, t[4] = (f - _) * x, t[5] = (1 - (l + v)) * x, t[6] = (m + g) * x, t[7] = 0, t[8] = (d + y) * w, t[9] = (m - g) * w, t[10] = (1 - (l + p)) * w, t[11] = 0, t[12] = r[0], t[13] = r[1], t[14] = r[2], t[15] = 1, t
+ }
+
+ function fromRotationTranslationScaleOrigin(t, e, r, n, i) {
+ var o = e[0],
+ a = e[1],
+ s = e[2],
+ u = e[3],
+ h = o + o,
+ c = a + a,
+ l = s + s,
+ f = o * h,
+ d = o * c,
+ p = o * l,
+ m = a * c,
+ v = a * l,
+ g = s * l,
+ y = u * h,
+ _ = u * c,
+ b = u * l,
+ x = n[0],
+ w = n[1],
+ T = n[2],
+ S = i[0],
+ M = i[1],
+ E = i[2],
+ A = (1 - (m + g)) * x,
+ P = (d + b) * x,
+ I = (p - _) * x,
+ O = (d - b) * w,
+ C = (1 - (f + g)) * w,
+ R = (v + y) * w,
+ D = (p + _) * T,
+ F = (v - y) * T,
+ k = (1 - (f + m)) * T;
+ return t[0] = A, t[1] = P, t[2] = I, t[3] = 0, t[4] = O, t[5] = C, t[6] = R, t[7] = 0, t[8] = D, t[9] = F, t[10] = k, t[11] = 0, t[12] = r[0] + S - (A * S + O * M + D * E), t[13] = r[1] + M - (P * S + C * M + F * E), t[14] = r[2] + E - (I * S + R * M + k * E), t[15] = 1, t
+ }
+
+ function mat4_fromQuat(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[3],
+ a = r + r,
+ s = n + n,
+ u = i + i,
+ h = r * a,
+ c = n * a,
+ l = n * s,
+ f = i * a,
+ d = i * s,
+ p = i * u,
+ m = o * a,
+ v = o * s,
+ g = o * u;
+ return t[0] = 1 - l - p, t[1] = c + g, t[2] = f - v, t[3] = 0, t[4] = c - g, t[5] = 1 - h - p, t[6] = d + m, t[7] = 0, t[8] = f + v, t[9] = d - m, t[10] = 1 - h - l, t[11] = 0, t[12] = 0, t[13] = 0, t[14] = 0, t[15] = 1, t
+ }
+
+ function frustum(t, e, r, n, i, o, a) {
+ var s = 1 / (r - e),
+ u = 1 / (i - n),
+ h = 1 / (o - a);
+ return t[0] = 2 * o * s, t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 0, t[5] = 2 * o * u, t[6] = 0, t[7] = 0, t[8] = (r + e) * s, t[9] = (i + n) * u, t[10] = (a + o) * h, t[11] = -1, t[12] = 0, t[13] = 0, t[14] = a * o * 2 * h, t[15] = 0, t
+ }
+
+ function perspective(t, e, r, n, i) {
+ var o = 1 / Math.tan(e / 2),
+ a = void 0;
+ return t[0] = o / r, t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 0, t[5] = o, t[6] = 0, t[7] = 0, t[8] = 0, t[9] = 0, t[11] = -1, t[12] = 0, t[13] = 0, t[15] = 0, t[14] = null != i && i !== 1 / 0 ? (a = 1 / (n - i), t[10] = (i + n) * a, 2 * i * n * a) : (t[10] = -1, -2 * n), t
+ }
+
+ function perspectiveFromFieldOfView(t, e, r, n) {
+ var i = Math.tan(e.upDegrees * Math.PI / 180),
+ o = Math.tan(e.downDegrees * Math.PI / 180),
+ a = Math.tan(e.leftDegrees * Math.PI / 180),
+ s = Math.tan(e.rightDegrees * Math.PI / 180),
+ u = 2 / (a + s),
+ h = 2 / (i + o);
+ return t[0] = u, t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 0, t[5] = h, t[6] = 0, t[7] = 0, t[8] = -(a - s) * u * .5, t[9] = (i - o) * h * .5, t[10] = n / (r - n), t[11] = -1, t[12] = 0, t[13] = 0, t[14] = n * r / (r - n), t[15] = 0, t
+ }
+
+ function ortho(t, e, r, n, i, o, a) {
+ var s = 1 / (e - r),
+ u = 1 / (n - i),
+ h = 1 / (o - a);
+ return t[0] = -2 * s, t[1] = 0, t[2] = 0, t[3] = 0, t[4] = 0, t[5] = -2 * u, t[6] = 0, t[7] = 0, t[8] = 0, t[9] = 0, t[10] = 2 * h, t[11] = 0, t[12] = (e + r) * s, t[13] = (i + n) * u, t[14] = (a + o) * h, t[15] = 1, t
+ }
+
+ function lookAt(t, e, r, n) {
+ var i = void 0,
+ o = void 0,
+ a = void 0,
+ s = void 0,
+ u = void 0,
+ h = void 0,
+ c = void 0,
+ l = void 0,
+ f = void 0,
+ d = void 0,
+ p = e[0],
+ m = e[1],
+ v = e[2],
+ g = n[0],
+ y = n[1],
+ _ = n[2],
+ b = r[0],
+ x = r[1],
+ w = r[2];
+ return Math.abs(p - b) < F && Math.abs(m - x) < F && Math.abs(v - w) < F ? mat4_identity(t) : (c = p - b, l = m - x, f = v - w, i = y * (f *= d = 1 / Math.sqrt(c * c + l * l + f * f)) - _ * (l *= d), o = _ * (c *= d) - g * f, a = g * l - y * c, (d = Math.sqrt(i * i + o * o + a * a)) ? (i *= d = 1 / d, o *= d, a *= d) : a = o = i = 0, s = l * a - f * o, u = f * i - c * a, h = c * o - l * i, (d = Math.sqrt(s * s + u * u + h * h)) ? (s *= d = 1 / d, u *= d, h *= d) : h = u = s = 0, t[0] = i, t[1] = s, t[2] = c, t[3] = 0, t[4] = o, t[5] = u, t[6] = l, t[7] = 0, t[8] = a, t[9] = h, t[10] = f, t[11] = 0, t[12] = -(i * p + o * m + a * v), t[13] = -(s * p + u * m + h * v), t[14] = -(c * p + l * m + f * v), t[15] = 1, t)
+ }
+
+ function targetTo(t, e, r, n) {
+ var i = e[0],
+ o = e[1],
+ a = e[2],
+ s = n[0],
+ u = n[1],
+ h = n[2],
+ c = i - r[0],
+ l = o - r[1],
+ f = a - r[2],
+ d = c * c + l * l + f * f;
+ 0 < d && (c *= d = 1 / Math.sqrt(d), l *= d, f *= d);
+ var p = u * f - h * l,
+ m = h * c - s * f,
+ v = s * l - u * c;
+ return 0 < (d = p * p + m * m + v * v) && (p *= d = 1 / Math.sqrt(d), m *= d, v *= d), t[0] = p, t[1] = m, t[2] = v, t[3] = 0, t[4] = l * v - f * m, t[5] = f * p - c * v, t[6] = c * m - l * p, t[7] = 0, t[8] = c, t[9] = l, t[10] = f, t[11] = 0, t[12] = i, t[13] = o, t[14] = a, t[15] = 1, t
+ }
+
+ function mat4_str(t) {
+ return "mat4(" + t[0] + ", " + t[1] + ", " + t[2] + ", " + t[3] + ", " + t[4] + ", " + t[5] + ", " + t[6] + ", " + t[7] + ", " + t[8] + ", " + t[9] + ", " + t[10] + ", " + t[11] + ", " + t[12] + ", " + t[13] + ", " + t[14] + ", " + t[15] + ")"
+ }
+
+ function mat4_frob(t) {
+ return Math.sqrt(Math.pow(t[0], 2) + Math.pow(t[1], 2) + Math.pow(t[2], 2) + Math.pow(t[3], 2) + Math.pow(t[4], 2) + Math.pow(t[5], 2) + Math.pow(t[6], 2) + Math.pow(t[7], 2) + Math.pow(t[8], 2) + Math.pow(t[9], 2) + Math.pow(t[10], 2) + Math.pow(t[11], 2) + Math.pow(t[12], 2) + Math.pow(t[13], 2) + Math.pow(t[14], 2) + Math.pow(t[15], 2))
+ }
+
+ function mat4_add(t, e, r) {
+ return t[0] = e[0] + r[0], t[1] = e[1] + r[1], t[2] = e[2] + r[2], t[3] = e[3] + r[3], t[4] = e[4] + r[4], t[5] = e[5] + r[5], t[6] = e[6] + r[6], t[7] = e[7] + r[7], t[8] = e[8] + r[8], t[9] = e[9] + r[9], t[10] = e[10] + r[10], t[11] = e[11] + r[11], t[12] = e[12] + r[12], t[13] = e[13] + r[13], t[14] = e[14] + r[14], t[15] = e[15] + r[15], t
+ }
+
+ function mat4_subtract(t, e, r) {
+ return t[0] = e[0] - r[0], t[1] = e[1] - r[1], t[2] = e[2] - r[2], t[3] = e[3] - r[3], t[4] = e[4] - r[4], t[5] = e[5] - r[5], t[6] = e[6] - r[6], t[7] = e[7] - r[7], t[8] = e[8] - r[8], t[9] = e[9] - r[9], t[10] = e[10] - r[10], t[11] = e[11] - r[11], t[12] = e[12] - r[12], t[13] = e[13] - r[13], t[14] = e[14] - r[14], t[15] = e[15] - r[15], t
+ }
+
+ function mat4_multiplyScalar(t, e, r) {
+ return t[0] = e[0] * r, t[1] = e[1] * r, t[2] = e[2] * r, t[3] = e[3] * r, t[4] = e[4] * r, t[5] = e[5] * r, t[6] = e[6] * r, t[7] = e[7] * r, t[8] = e[8] * r, t[9] = e[9] * r, t[10] = e[10] * r, t[11] = e[11] * r, t[12] = e[12] * r, t[13] = e[13] * r, t[14] = e[14] * r, t[15] = e[15] * r, t
+ }
+
+ function mat4_multiplyScalarAndAdd(t, e, r, n) {
+ return t[0] = e[0] + r[0] * n, t[1] = e[1] + r[1] * n, t[2] = e[2] + r[2] * n, t[3] = e[3] + r[3] * n, t[4] = e[4] + r[4] * n, t[5] = e[5] + r[5] * n, t[6] = e[6] + r[6] * n, t[7] = e[7] + r[7] * n, t[8] = e[8] + r[8] * n, t[9] = e[9] + r[9] * n, t[10] = e[10] + r[10] * n, t[11] = e[11] + r[11] * n, t[12] = e[12] + r[12] * n, t[13] = e[13] + r[13] * n, t[14] = e[14] + r[14] * n, t[15] = e[15] + r[15] * n, t
+ }
+
+ function mat4_exactEquals(t, e) {
+ return t[0] === e[0] && t[1] === e[1] && t[2] === e[2] && t[3] === e[3] && t[4] === e[4] && t[5] === e[5] && t[6] === e[6] && t[7] === e[7] && t[8] === e[8] && t[9] === e[9] && t[10] === e[10] && t[11] === e[11] && t[12] === e[12] && t[13] === e[13] && t[14] === e[14] && t[15] === e[15]
+ }
+
+ function mat4_equals(t, e) {
+ var r = t[0],
+ n = t[1],
+ i = t[2],
+ o = t[3],
+ a = t[4],
+ s = t[5],
+ u = t[6],
+ h = t[7],
+ c = t[8],
+ l = t[9],
+ f = t[10],
+ d = t[11],
+ p = t[12],
+ m = t[13],
+ v = t[14],
+ g = t[15],
+ y = e[0],
+ _ = e[1],
+ b = e[2],
+ x = e[3],
+ w = e[4],
+ T = e[5],
+ S = e[6],
+ M = e[7],
+ E = e[8],
+ A = e[9],
+ P = e[10],
+ I = e[11],
+ O = e[12],
+ C = e[13],
+ R = e[14],
+ D = e[15];
+ return Math.abs(r - y) <= F * Math.max(1, Math.abs(r), Math.abs(y)) && Math.abs(n - _) <= F * Math.max(1, Math.abs(n), Math.abs(_)) && Math.abs(i - b) <= F * Math.max(1, Math.abs(i), Math.abs(b)) && Math.abs(o - x) <= F * Math.max(1, Math.abs(o), Math.abs(x)) && Math.abs(a - w) <= F * Math.max(1, Math.abs(a), Math.abs(w)) && Math.abs(s - T) <= F * Math.max(1, Math.abs(s), Math.abs(T)) && Math.abs(u - S) <= F * Math.max(1, Math.abs(u), Math.abs(S)) && Math.abs(h - M) <= F * Math.max(1, Math.abs(h), Math.abs(M)) && Math.abs(c - E) <= F * Math.max(1, Math.abs(c), Math.abs(E)) && Math.abs(l - A) <= F * Math.max(1, Math.abs(l), Math.abs(A)) && Math.abs(f - P) <= F * Math.max(1, Math.abs(f), Math.abs(P)) && Math.abs(d - I) <= F * Math.max(1, Math.abs(d), Math.abs(I)) && Math.abs(p - O) <= F * Math.max(1, Math.abs(p), Math.abs(O)) && Math.abs(m - C) <= F * Math.max(1, Math.abs(m), Math.abs(C)) && Math.abs(v - R) <= F * Math.max(1, Math.abs(v), Math.abs(R)) && Math.abs(g - D) <= F * Math.max(1, Math.abs(g), Math.abs(D))
+ }
+ var w = mat4_multiply,
+ T = mat4_subtract;
+
+ function vec3_create() {
+ var t = new g(3);
+ return g != Float32Array && (t[0] = 0, t[1] = 0, t[2] = 0), t
+ }
+
+ function vec3_clone(t) {
+ var e = new g(3);
+ return e[0] = t[0], e[1] = t[1], e[2] = t[2], e
+ }
+
+ function vec3_length(t) {
+ var e = t[0],
+ r = t[1],
+ n = t[2];
+ return Math.sqrt(e * e + r * r + n * n)
+ }
+
+ function vec3_fromValues(t, e, r) {
+ var n = new g(3);
+ return n[0] = t, n[1] = e, n[2] = r, n
+ }
+
+ function vec3_copy(t, e) {
+ return t[0] = e[0], t[1] = e[1], t[2] = e[2], t
+ }
+
+ function vec3_set(t, e, r, n) {
+ return t[0] = e, t[1] = r, t[2] = n, t
+ }
+
+ function vec3_add(t, e, r) {
+ return t[0] = e[0] + r[0], t[1] = e[1] + r[1], t[2] = e[2] + r[2], t
+ }
+
+ function vec3_subtract(t, e, r) {
+ return t[0] = e[0] - r[0], t[1] = e[1] - r[1], t[2] = e[2] - r[2], t
+ }
+
+ function vec3_multiply(t, e, r) {
+ return t[0] = e[0] * r[0], t[1] = e[1] * r[1], t[2] = e[2] * r[2], t
+ }
+
+ function divide(t, e, r) {
+ return t[0] = e[0] / r[0], t[1] = e[1] / r[1], t[2] = e[2] / r[2], t
+ }
+
+ function ceil(t, e) {
+ return t[0] = Math.ceil(e[0]), t[1] = Math.ceil(e[1]), t[2] = Math.ceil(e[2]), t
+ }
+
+ function floor(t, e) {
+ return t[0] = Math.floor(e[0]), t[1] = Math.floor(e[1]), t[2] = Math.floor(e[2]), t
+ }
+
+ function min(t, e, r) {
+ return t[0] = Math.min(e[0], r[0]), t[1] = Math.min(e[1], r[1]), t[2] = Math.min(e[2], r[2]), t
+ }
+
+ function max(t, e, r) {
+ return t[0] = Math.max(e[0], r[0]), t[1] = Math.max(e[1], r[1]), t[2] = Math.max(e[2], r[2]), t
+ }
+
+ function round(t, e) {
+ return t[0] = Math.round(e[0]), t[1] = Math.round(e[1]), t[2] = Math.round(e[2]), t
+ }
+
+ function vec3_scale(t, e, r) {
+ return t[0] = e[0] * r, t[1] = e[1] * r, t[2] = e[2] * r, t
+ }
+
+ function scaleAndAdd(t, e, r, n) {
+ return t[0] = e[0] + r[0] * n, t[1] = e[1] + r[1] * n, t[2] = e[2] + r[2] * n, t
+ }
+
+ function distance(t, e) {
+ var r = e[0] - t[0],
+ n = e[1] - t[1],
+ i = e[2] - t[2];
+ return Math.sqrt(r * r + n * n + i * i)
+ }
+
+ function squaredDistance(t, e) {
+ var r = e[0] - t[0],
+ n = e[1] - t[1],
+ i = e[2] - t[2];
+ return r * r + n * n + i * i
+ }
+
+ function squaredLength(t) {
+ var e = t[0],
+ r = t[1],
+ n = t[2];
+ return e * e + r * r + n * n
+ }
+
+ function negate(t, e) {
+ return t[0] = -e[0], t[1] = -e[1], t[2] = -e[2], t
+ }
+
+ function inverse(t, e) {
+ return t[0] = 1 / e[0], t[1] = 1 / e[1], t[2] = 1 / e[2], t
+ }
+
+ function normalize(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = r * r + n * n + i * i;
+ return 0 < o && (o = 1 / Math.sqrt(o), t[0] = e[0] * o, t[1] = e[1] * o, t[2] = e[2] * o), t
+ }
+
+ function vec3_dot(t, e) {
+ return t[0] * e[0] + t[1] * e[1] + t[2] * e[2]
+ }
+
+ function cross(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = r[0],
+ s = r[1],
+ u = r[2];
+ return t[0] = i * u - o * s, t[1] = o * a - n * u, t[2] = n * s - i * a, t
+ }
+
+ function lerp(t, e, r, n) {
+ var i = e[0],
+ o = e[1],
+ a = e[2];
+ return t[0] = i + n * (r[0] - i), t[1] = o + n * (r[1] - o), t[2] = a + n * (r[2] - a), t
+ }
+
+ function hermite(t, e, r, n, i, o) {
+ var a = o * o,
+ s = a * (2 * o - 3) + 1,
+ u = a * (o - 2) + o,
+ h = a * (o - 1),
+ c = a * (3 - 2 * o);
+ return t[0] = e[0] * s + r[0] * u + n[0] * h + i[0] * c, t[1] = e[1] * s + r[1] * u + n[1] * h + i[1] * c, t[2] = e[2] * s + r[2] * u + n[2] * h + i[2] * c, t
+ }
+
+ function bezier(t, e, r, n, i, o) {
+ var a = 1 - o,
+ s = a * a,
+ u = o * o,
+ h = s * a,
+ c = 3 * o * s,
+ l = 3 * u * a,
+ f = u * o;
+ return t[0] = e[0] * h + r[0] * c + n[0] * l + i[0] * f, t[1] = e[1] * h + r[1] * c + n[1] * l + i[1] * f, t[2] = e[2] * h + r[2] * c + n[2] * l + i[2] * f, t
+ }
+
+ function random(t, e) {
+ e = e || 1;
+ var r = 2 * d() * Math.PI,
+ n = 2 * d() - 1,
+ i = Math.sqrt(1 - n * n) * e;
+ return t[0] = Math.cos(r) * i, t[1] = Math.sin(r) * i, t[2] = n * e, t
+ }
+
+ function transformMat4(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = r[3] * n + r[7] * i + r[11] * o + r[15];
+ return a = a || 1, t[0] = (r[0] * n + r[4] * i + r[8] * o + r[12]) / a, t[1] = (r[1] * n + r[5] * i + r[9] * o + r[13]) / a, t[2] = (r[2] * n + r[6] * i + r[10] * o + r[14]) / a, t
+ }
+
+ function transformMat3(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2];
+ return t[0] = n * r[0] + i * r[3] + o * r[6], t[1] = n * r[1] + i * r[4] + o * r[7], t[2] = n * r[2] + i * r[5] + o * r[8], t
+ }
+
+ function transformQuat(t, e, r) {
+ var n = r[0],
+ i = r[1],
+ o = r[2],
+ a = r[3],
+ s = e[0],
+ u = e[1],
+ h = e[2],
+ c = i * h - o * u,
+ l = o * s - n * h,
+ f = n * u - i * s,
+ d = i * f - o * l,
+ p = o * c - n * f,
+ m = n * l - i * c,
+ v = 2 * a;
+ return c *= v, l *= v, f *= v, d *= 2, p *= 2, m *= 2, t[0] = s + c + d, t[1] = u + l + p, t[2] = h + f + m, t
+ }
+
+ function vec3_rotateX(t, e, r, n) {
+ var i = [],
+ o = [];
+ return i[0] = e[0] - r[0], i[1] = e[1] - r[1], i[2] = e[2] - r[2], o[0] = i[0], o[1] = i[1] * Math.cos(n) - i[2] * Math.sin(n), o[2] = i[1] * Math.sin(n) + i[2] * Math.cos(n), t[0] = o[0] + r[0], t[1] = o[1] + r[1], t[2] = o[2] + r[2], t
+ }
+
+ function vec3_rotateY(t, e, r, n) {
+ var i = [],
+ o = [];
+ return i[0] = e[0] - r[0], i[1] = e[1] - r[1], i[2] = e[2] - r[2], o[0] = i[2] * Math.sin(n) + i[0] * Math.cos(n), o[1] = i[1], o[2] = i[2] * Math.cos(n) - i[0] * Math.sin(n), t[0] = o[0] + r[0], t[1] = o[1] + r[1], t[2] = o[2] + r[2], t
+ }
+
+ function vec3_rotateZ(t, e, r, n) {
+ var i = [],
+ o = [];
+ return i[0] = e[0] - r[0], i[1] = e[1] - r[1], i[2] = e[2] - r[2], o[0] = i[0] * Math.cos(n) - i[1] * Math.sin(n), o[1] = i[0] * Math.sin(n) + i[1] * Math.cos(n), o[2] = i[2], t[0] = o[0] + r[0], t[1] = o[1] + r[1], t[2] = o[2] + r[2], t
+ }
+
+ function angle(t, e) {
+ var r = vec3_fromValues(t[0], t[1], t[2]),
+ n = vec3_fromValues(e[0], e[1], e[2]);
+ normalize(r, r), normalize(n, n);
+ var i = vec3_dot(r, n);
+ return 1 < i ? 0 : i < -1 ? Math.PI : Math.acos(i)
+ }
+
+ function vec3_str(t) {
+ return "vec3(" + t[0] + ", " + t[1] + ", " + t[2] + ")"
+ }
+
+ function vec3_exactEquals(t, e) {
+ return t[0] === e[0] && t[1] === e[1] && t[2] === e[2]
+ }
+
+ function vec3_equals(t, e) {
+ var r = t[0],
+ n = t[1],
+ i = t[2],
+ o = e[0],
+ a = e[1],
+ s = e[2];
+ return Math.abs(r - o) <= F * Math.max(1, Math.abs(r), Math.abs(o)) && Math.abs(n - a) <= F * Math.max(1, Math.abs(n), Math.abs(a)) && Math.abs(i - s) <= F * Math.max(1, Math.abs(i), Math.abs(s))
+ }
+ var S, M = vec3_subtract,
+ E = vec3_multiply,
+ A = divide,
+ P = distance,
+ I = squaredDistance,
+ O = vec3_length,
+ C = squaredLength,
+ R = (S = vec3_create(), function(t, e, r, n, i, o) {
+ var a = void 0,
+ s = void 0;
+ for (e || (e = 3), r || (r = 0), s = n ? Math.min(n * e + r, t.length) : t.length, a = r; a < s; a += e) S[0] = t[a], S[1] = t[a + 1], S[2] = t[a + 2], i(S, S, o), t[a] = S[0], t[a + 1] = S[1], t[a + 2] = S[2];
+ return t
+ });
+
+ function vec4_create() {
+ var t = new g(4);
+ return g != Float32Array && (t[0] = 0, t[1] = 0, t[2] = 0, t[3] = 0), t
+ }
+
+ function vec4_clone(t) {
+ var e = new g(4);
+ return e[0] = t[0], e[1] = t[1], e[2] = t[2], e[3] = t[3], e
+ }
+
+ function vec4_fromValues(t, e, r, n) {
+ var i = new g(4);
+ return i[0] = t, i[1] = e, i[2] = r, i[3] = n, i
+ }
+
+ function vec4_copy(t, e) {
+ return t[0] = e[0], t[1] = e[1], t[2] = e[2], t[3] = e[3], t
+ }
+
+ function vec4_set(t, e, r, n, i) {
+ return t[0] = e, t[1] = r, t[2] = n, t[3] = i, t
+ }
+
+ function vec4_add(t, e, r) {
+ return t[0] = e[0] + r[0], t[1] = e[1] + r[1], t[2] = e[2] + r[2], t[3] = e[3] + r[3], t
+ }
+
+ function vec4_subtract(t, e, r) {
+ return t[0] = e[0] - r[0], t[1] = e[1] - r[1], t[2] = e[2] - r[2], t[3] = e[3] - r[3], t
+ }
+
+ function vec4_multiply(t, e, r) {
+ return t[0] = e[0] * r[0], t[1] = e[1] * r[1], t[2] = e[2] * r[2], t[3] = e[3] * r[3], t
+ }
+
+ function vec4_divide(t, e, r) {
+ return t[0] = e[0] / r[0], t[1] = e[1] / r[1], t[2] = e[2] / r[2], t[3] = e[3] / r[3], t
+ }
+
+ function vec4_ceil(t, e) {
+ return t[0] = Math.ceil(e[0]), t[1] = Math.ceil(e[1]), t[2] = Math.ceil(e[2]), t[3] = Math.ceil(e[3]), t
+ }
+
+ function vec4_floor(t, e) {
+ return t[0] = Math.floor(e[0]), t[1] = Math.floor(e[1]), t[2] = Math.floor(e[2]), t[3] = Math.floor(e[3]), t
+ }
+
+ function vec4_min(t, e, r) {
+ return t[0] = Math.min(e[0], r[0]), t[1] = Math.min(e[1], r[1]), t[2] = Math.min(e[2], r[2]), t[3] = Math.min(e[3], r[3]), t
+ }
+
+ function vec4_max(t, e, r) {
+ return t[0] = Math.max(e[0], r[0]), t[1] = Math.max(e[1], r[1]), t[2] = Math.max(e[2], r[2]), t[3] = Math.max(e[3], r[3]), t
+ }
+
+ function vec4_round(t, e) {
+ return t[0] = Math.round(e[0]), t[1] = Math.round(e[1]), t[2] = Math.round(e[2]), t[3] = Math.round(e[3]), t
+ }
+
+ function vec4_scale(t, e, r) {
+ return t[0] = e[0] * r, t[1] = e[1] * r, t[2] = e[2] * r, t[3] = e[3] * r, t
+ }
+
+ function vec4_scaleAndAdd(t, e, r, n) {
+ return t[0] = e[0] + r[0] * n, t[1] = e[1] + r[1] * n, t[2] = e[2] + r[2] * n, t[3] = e[3] + r[3] * n, t
+ }
+
+ function vec4_distance(t, e) {
+ var r = e[0] - t[0],
+ n = e[1] - t[1],
+ i = e[2] - t[2],
+ o = e[3] - t[3];
+ return Math.sqrt(r * r + n * n + i * i + o * o)
+ }
+
+ function vec4_squaredDistance(t, e) {
+ var r = e[0] - t[0],
+ n = e[1] - t[1],
+ i = e[2] - t[2],
+ o = e[3] - t[3];
+ return r * r + n * n + i * i + o * o
+ }
+
+ function vec4_length(t) {
+ var e = t[0],
+ r = t[1],
+ n = t[2],
+ i = t[3];
+ return Math.sqrt(e * e + r * r + n * n + i * i)
+ }
+
+ function vec4_squaredLength(t) {
+ var e = t[0],
+ r = t[1],
+ n = t[2],
+ i = t[3];
+ return e * e + r * r + n * n + i * i
+ }
+
+ function vec4_negate(t, e) {
+ return t[0] = -e[0], t[1] = -e[1], t[2] = -e[2], t[3] = -e[3], t
+ }
+
+ function vec4_inverse(t, e) {
+ return t[0] = 1 / e[0], t[1] = 1 / e[1], t[2] = 1 / e[2], t[3] = 1 / e[3], t
+ }
+
+ function vec4_normalize(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[3],
+ a = r * r + n * n + i * i + o * o;
+ return 0 < a && (a = 1 / Math.sqrt(a), t[0] = r * a, t[1] = n * a, t[2] = i * a, t[3] = o * a), t
+ }
+
+ function vec4_dot(t, e) {
+ return t[0] * e[0] + t[1] * e[1] + t[2] * e[2] + t[3] * e[3]
+ }
+
+ function vec4_lerp(t, e, r, n) {
+ var i = e[0],
+ o = e[1],
+ a = e[2],
+ s = e[3];
+ return t[0] = i + n * (r[0] - i), t[1] = o + n * (r[1] - o), t[2] = a + n * (r[2] - a), t[3] = s + n * (r[3] - s), t
+ }
+
+ function vec4_random(t, e) {
+ var r, n, i, o, a, s;
+ for (e = e || 1; 1 <= (a = (r = 2 * d() - 1) * r + (n = 2 * d() - 1) * n););
+ for (; 1 <= (s = (i = 2 * d() - 1) * i + (o = 2 * d() - 1) * o););
+ var u = Math.sqrt((1 - a) / s);
+ return t[0] = e * r, t[1] = e * n, t[2] = e * i * u, t[3] = e * o * u, t
+ }
+
+ function vec4_transformMat4(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3];
+ return t[0] = r[0] * n + r[4] * i + r[8] * o + r[12] * a, t[1] = r[1] * n + r[5] * i + r[9] * o + r[13] * a, t[2] = r[2] * n + r[6] * i + r[10] * o + r[14] * a, t[3] = r[3] * n + r[7] * i + r[11] * o + r[15] * a, t
+ }
+
+ function vec4_transformQuat(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = r[0],
+ s = r[1],
+ u = r[2],
+ h = r[3],
+ c = h * n + s * o - u * i,
+ l = h * i + u * n - a * o,
+ f = h * o + a * i - s * n,
+ d = -a * n - s * i - u * o;
+ return t[0] = c * h + d * -a + l * -u - f * -s, t[1] = l * h + d * -s + f * -a - c * -u, t[2] = f * h + d * -u + c * -s - l * -a, t[3] = e[3], t
+ }
+
+ function vec4_str(t) {
+ return "vec4(" + t[0] + ", " + t[1] + ", " + t[2] + ", " + t[3] + ")"
+ }
+
+ function vec4_exactEquals(t, e) {
+ return t[0] === e[0] && t[1] === e[1] && t[2] === e[2] && t[3] === e[3]
+ }
+
+ function vec4_equals(t, e) {
+ var r = t[0],
+ n = t[1],
+ i = t[2],
+ o = t[3],
+ a = e[0],
+ s = e[1],
+ u = e[2],
+ h = e[3];
+ return Math.abs(r - a) <= F * Math.max(1, Math.abs(r), Math.abs(a)) && Math.abs(n - s) <= F * Math.max(1, Math.abs(n), Math.abs(s)) && Math.abs(i - u) <= F * Math.max(1, Math.abs(i), Math.abs(u)) && Math.abs(o - h) <= F * Math.max(1, Math.abs(o), Math.abs(h))
+ }
+ var D, k = vec4_subtract,
+ L = vec4_multiply,
+ N = vec4_divide,
+ B = vec4_distance,
+ U = vec4_squaredDistance,
+ G = vec4_length,
+ j = vec4_squaredLength,
+ z = (D = vec4_create(), function(t, e, r, n, i, o) {
+ var a = void 0,
+ s = void 0;
+ for (e || (e = 4), r || (r = 0), s = n ? Math.min(n * e + r, t.length) : t.length, a = r; a < s; a += e) D[0] = t[a], D[1] = t[a + 1], D[2] = t[a + 2], D[3] = t[a + 3], i(D, D, o), t[a] = D[0], t[a + 1] = D[1], t[a + 2] = D[2], t[a + 3] = D[3];
+ return t
+ });
+
+ function quat_create() {
+ var t = new g(4);
+ return g != Float32Array && (t[0] = 0, t[1] = 0, t[2] = 0), t[3] = 1, t
+ }
+
+ function quat_identity(t) {
+ return t[0] = 0, t[1] = 0, t[2] = 0, t[3] = 1, t
+ }
+
+ function setAxisAngle(t, e, r) {
+ r *= .5;
+ var n = Math.sin(r);
+ return t[0] = n * e[0], t[1] = n * e[1], t[2] = n * e[2], t[3] = Math.cos(r), t
+ }
+
+ function getAxisAngle(t, e) {
+ var r = 2 * Math.acos(e[3]),
+ n = Math.sin(r / 2);
+ return t[2] = F < n ? (t[0] = e[0] / n, t[1] = e[1] / n, e[2] / n) : (t[0] = 1, t[1] = 0), r
+ }
+
+ function quat_multiply(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = r[0],
+ u = r[1],
+ h = r[2],
+ c = r[3];
+ return t[0] = n * c + a * s + i * h - o * u, t[1] = i * c + a * u + o * s - n * h, t[2] = o * c + a * h + n * u - i * s, t[3] = a * c - n * s - i * u - o * h, t
+ }
+
+ function quat_rotateX(t, e, r) {
+ r *= .5;
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = Math.sin(r),
+ u = Math.cos(r);
+ return t[0] = n * u + a * s, t[1] = i * u + o * s, t[2] = o * u - i * s, t[3] = a * u - n * s, t
+ }
+
+ function quat_rotateY(t, e, r) {
+ r *= .5;
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = Math.sin(r),
+ u = Math.cos(r);
+ return t[0] = n * u - o * s, t[1] = i * u + a * s, t[2] = o * u + n * s, t[3] = a * u - i * s, t
+ }
+
+ function quat_rotateZ(t, e, r) {
+ r *= .5;
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = Math.sin(r),
+ u = Math.cos(r);
+ return t[0] = n * u + i * s, t[1] = i * u - n * s, t[2] = o * u + a * s, t[3] = a * u - o * s, t
+ }
+
+ function calculateW(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2];
+ return t[0] = r, t[1] = n, t[2] = i, t[3] = Math.sqrt(Math.abs(1 - r * r - n * n - i * i)), t
+ }
+
+ function slerp(t, e, r, n) {
+ var i = e[0],
+ o = e[1],
+ a = e[2],
+ s = e[3],
+ u = r[0],
+ h = r[1],
+ c = r[2],
+ l = r[3],
+ f = void 0,
+ d = void 0,
+ p = void 0,
+ m = void 0,
+ v = void 0;
+ return (d = i * u + o * h + a * c + s * l) < 0 && (d = -d, u = -u, h = -h, c = -c, l = -l), v = F < 1 - d ? (f = Math.acos(d), p = Math.sin(f), m = Math.sin((1 - n) * f) / p, Math.sin(n * f) / p) : (m = 1 - n, n), t[0] = m * i + v * u, t[1] = m * o + v * h, t[2] = m * a + v * c, t[3] = m * s + v * l, t
+ }
+
+ function quat_random(t) {
+ var e = d(),
+ r = d(),
+ n = d(),
+ i = Math.sqrt(1 - e),
+ o = Math.sqrt(e);
+ return t[0] = i * Math.sin(2 * Math.PI * r), t[1] = i * Math.cos(2 * Math.PI * r), t[2] = o * Math.sin(2 * Math.PI * n), t[3] = o * Math.cos(2 * Math.PI * n), t
+ }
+
+ function quat_invert(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = e[2],
+ o = e[3],
+ a = r * r + n * n + i * i + o * o,
+ s = a ? 1 / a : 0;
+ return t[0] = -r * s, t[1] = -n * s, t[2] = -i * s, t[3] = o * s, t
+ }
+
+ function conjugate(t, e) {
+ return t[0] = -e[0], t[1] = -e[1], t[2] = -e[2], t[3] = e[3], t
+ }
+
+ function fromMat3(t, e) {
+ var r = e[0] + e[4] + e[8],
+ n = void 0;
+ if (0 < r) n = Math.sqrt(r + 1), t[3] = .5 * n, n = .5 / n, t[0] = (e[5] - e[7]) * n, t[1] = (e[6] - e[2]) * n, t[2] = (e[1] - e[3]) * n;
+ else {
+ var i = 0;
+ e[4] > e[0] && (i = 1), e[8] > e[3 * i + i] && (i = 2);
+ var o = (i + 1) % 3,
+ a = (i + 2) % 3;
+ n = Math.sqrt(e[3 * i + i] - e[3 * o + o] - e[3 * a + a] + 1), t[i] = .5 * n, n = .5 / n, t[3] = (e[3 * o + a] - e[3 * a + o]) * n, t[o] = (e[3 * o + i] + e[3 * i + o]) * n, t[a] = (e[3 * a + i] + e[3 * i + a]) * n
+ }
+ return t
+ }
+
+ function fromEuler(t, e, r, n) {
+ var i = .5 * Math.PI / 180;
+ e *= i, r *= i, n *= i;
+ var o = Math.sin(e),
+ a = Math.cos(e),
+ s = Math.sin(r),
+ u = Math.cos(r),
+ h = Math.sin(n),
+ c = Math.cos(n);
+ return t[0] = o * u * c - a * s * h, t[1] = a * s * c + o * u * h, t[2] = a * u * h - o * s * c, t[3] = a * u * c + o * s * h, t
+ }
+
+ function quat_str(t) {
+ return "quat(" + t[0] + ", " + t[1] + ", " + t[2] + ", " + t[3] + ")"
+ }
+ var X, V, q, H, W, Y, K = vec4_clone,
+ Z = vec4_fromValues,
+ Q = vec4_copy,
+ J = vec4_set,
+ $ = vec4_add,
+ tt = quat_multiply,
+ et = vec4_scale,
+ rt = vec4_dot,
+ nt = vec4_lerp,
+ it = vec4_length,
+ ot = it,
+ at = vec4_squaredLength,
+ st = at,
+ ut = vec4_normalize,
+ ht = vec4_exactEquals,
+ ct = vec4_equals,
+ lt = (X = vec3_create(), V = vec3_fromValues(1, 0, 0), q = vec3_fromValues(0, 1, 0), function(t, e, r) {
+ var n = vec3_dot(e, r);
+ return n < -.999999 ? (cross(X, V, e), O(X) < 1e-6 && cross(X, q, e), normalize(X, X), setAxisAngle(t, X, Math.PI), t) : .999999 < n ? (t[0] = 0, t[1] = 0, t[2] = 0, t[3] = 1, t) : (cross(X, e, r), t[0] = X[0], t[1] = X[1], t[2] = X[2], t[3] = 1 + n, ut(t, t))
+ }),
+ ft = (H = quat_create(), W = quat_create(), function(t, e, r, n, i, o) {
+ return slerp(H, e, i, o), slerp(W, r, n, o), slerp(t, H, W, 2 * o * (1 - o)), t
+ }),
+ dt = (Y = mat3_create(), function(t, e, r, n) {
+ return Y[0] = r[0], Y[3] = r[1], Y[6] = r[2], Y[1] = n[0], Y[4] = n[1], Y[7] = n[2], Y[2] = -e[0], Y[5] = -e[1], Y[8] = -e[2], ut(t, fromMat3(t, Y))
+ });
+
+ function quat2_create() {
+ var t = new g(8);
+ return g != Float32Array && (t[0] = 0, t[1] = 0, t[2] = 0, t[4] = 0, t[5] = 0, t[6] = 0, t[7] = 0), t[3] = 1, t
+ }
+
+ function quat2_clone(t) {
+ var e = new g(8);
+ return e[0] = t[0], e[1] = t[1], e[2] = t[2], e[3] = t[3], e[4] = t[4], e[5] = t[5], e[6] = t[6], e[7] = t[7], e
+ }
+
+ function quat2_fromValues(t, e, r, n, i, o, a, s) {
+ var u = new g(8);
+ return u[0] = t, u[1] = e, u[2] = r, u[3] = n, u[4] = i, u[5] = o, u[6] = a, u[7] = s, u
+ }
+
+ function fromRotationTranslationValues(t, e, r, n, i, o, a) {
+ var s = new g(8);
+ s[0] = t, s[1] = e, s[2] = r, s[3] = n;
+ var u = .5 * i,
+ h = .5 * o,
+ c = .5 * a;
+ return s[4] = u * n + h * r - c * e, s[5] = h * n + c * t - u * r, s[6] = c * n + u * e - h * t, s[7] = -u * t - h * e - c * r, s
+ }
+
+ function quat2_fromRotationTranslation(t, e, r) {
+ var n = .5 * r[0],
+ i = .5 * r[1],
+ o = .5 * r[2],
+ a = e[0],
+ s = e[1],
+ u = e[2],
+ h = e[3];
+ return t[0] = a, t[1] = s, t[2] = u, t[3] = h, t[4] = n * h + i * u - o * s, t[5] = i * h + o * a - n * u, t[6] = o * h + n * s - i * a, t[7] = -n * a - i * s - o * u, t
+ }
+
+ function quat2_fromTranslation(t, e) {
+ return t[0] = 0, t[1] = 0, t[2] = 0, t[3] = 1, t[4] = .5 * e[0], t[5] = .5 * e[1], t[6] = .5 * e[2], t[7] = 0, t
+ }
+
+ function quat2_fromRotation(t, e) {
+ return t[0] = e[0], t[1] = e[1], t[2] = e[2], t[3] = e[3], t[4] = 0, t[5] = 0, t[6] = 0, t[7] = 0, t
+ }
+
+ function quat2_fromMat4(t, e) {
+ var r = quat_create();
+ getRotation(r, e);
+ var n = new g(3);
+ return getTranslation(n, e), quat2_fromRotationTranslation(t, r, n), t
+ }
+
+ function quat2_copy(t, e) {
+ return t[0] = e[0], t[1] = e[1], t[2] = e[2], t[3] = e[3], t[4] = e[4], t[5] = e[5], t[6] = e[6], t[7] = e[7], t
+ }
+
+ function quat2_identity(t) {
+ return t[0] = 0, t[1] = 0, t[2] = 0, t[3] = 1, t[4] = 0, t[5] = 0, t[6] = 0, t[7] = 0, t
+ }
+
+ function quat2_set(t, e, r, n, i, o, a, s, u) {
+ return t[0] = e, t[1] = r, t[2] = n, t[3] = i, t[4] = o, t[5] = a, t[6] = s, t[7] = u, t
+ }
+ var pt = Q;
+
+ function getDual(t, e) {
+ return t[0] = e[4], t[1] = e[5], t[2] = e[6], t[3] = e[7], t
+ }
+ var mt = Q;
+
+ function setDual(t, e) {
+ return t[4] = e[0], t[5] = e[1], t[6] = e[2], t[7] = e[3], t
+ }
+
+ function quat2_getTranslation(t, e) {
+ var r = e[4],
+ n = e[5],
+ i = e[6],
+ o = e[7],
+ a = -e[0],
+ s = -e[1],
+ u = -e[2],
+ h = e[3];
+ return t[0] = 2 * (r * h + o * a + n * u - i * s), t[1] = 2 * (n * h + o * s + i * a - r * u), t[2] = 2 * (i * h + o * u + r * s - n * a), t
+ }
+
+ function quat2_translate(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = .5 * r[0],
+ u = .5 * r[1],
+ h = .5 * r[2],
+ c = e[4],
+ l = e[5],
+ f = e[6],
+ d = e[7];
+ return t[0] = n, t[1] = i, t[2] = o, t[3] = a, t[4] = a * s + i * h - o * u + c, t[5] = a * u + o * s - n * h + l, t[6] = a * h + n * u - i * s + f, t[7] = -n * s - i * u - o * h + d, t
+ }
+
+ function quat2_rotateX(t, e, r) {
+ var n = -e[0],
+ i = -e[1],
+ o = -e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = e[6],
+ c = e[7],
+ l = s * a + c * n + u * o - h * i,
+ f = u * a + c * i + h * n - s * o,
+ d = h * a + c * o + s * i - u * n,
+ p = c * a - s * n - u * i - h * o;
+ return quat_rotateX(t, e, r), n = t[0], i = t[1], o = t[2], a = t[3], t[4] = l * a + p * n + f * o - d * i, t[5] = f * a + p * i + d * n - l * o, t[6] = d * a + p * o + l * i - f * n, t[7] = p * a - l * n - f * i - d * o, t
+ }
+
+ function quat2_rotateY(t, e, r) {
+ var n = -e[0],
+ i = -e[1],
+ o = -e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = e[6],
+ c = e[7],
+ l = s * a + c * n + u * o - h * i,
+ f = u * a + c * i + h * n - s * o,
+ d = h * a + c * o + s * i - u * n,
+ p = c * a - s * n - u * i - h * o;
+ return quat_rotateY(t, e, r), n = t[0], i = t[1], o = t[2], a = t[3], t[4] = l * a + p * n + f * o - d * i, t[5] = f * a + p * i + d * n - l * o, t[6] = d * a + p * o + l * i - f * n, t[7] = p * a - l * n - f * i - d * o, t
+ }
+
+ function quat2_rotateZ(t, e, r) {
+ var n = -e[0],
+ i = -e[1],
+ o = -e[2],
+ a = e[3],
+ s = e[4],
+ u = e[5],
+ h = e[6],
+ c = e[7],
+ l = s * a + c * n + u * o - h * i,
+ f = u * a + c * i + h * n - s * o,
+ d = h * a + c * o + s * i - u * n,
+ p = c * a - s * n - u * i - h * o;
+ return quat_rotateZ(t, e, r), n = t[0], i = t[1], o = t[2], a = t[3], t[4] = l * a + p * n + f * o - d * i, t[5] = f * a + p * i + d * n - l * o, t[6] = d * a + p * o + l * i - f * n, t[7] = p * a - l * n - f * i - d * o, t
+ }
+
+ function rotateByQuatAppend(t, e, r) {
+ var n = r[0],
+ i = r[1],
+ o = r[2],
+ a = r[3],
+ s = e[0],
+ u = e[1],
+ h = e[2],
+ c = e[3];
+ return t[0] = s * a + c * n + u * o - h * i, t[1] = u * a + c * i + h * n - s * o, t[2] = h * a + c * o + s * i - u * n, t[3] = c * a - s * n - u * i - h * o, s = e[4], u = e[5], h = e[6], c = e[7], t[4] = s * a + c * n + u * o - h * i, t[5] = u * a + c * i + h * n - s * o, t[6] = h * a + c * o + s * i - u * n, t[7] = c * a - s * n - u * i - h * o, t
+ }
+
+ function rotateByQuatPrepend(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = r[0],
+ u = r[1],
+ h = r[2],
+ c = r[3];
+ return t[0] = n * c + a * s + i * h - o * u, t[1] = i * c + a * u + o * s - n * h, t[2] = o * c + a * h + n * u - i * s, t[3] = a * c - n * s - i * u - o * h, s = r[4], u = r[5], h = r[6], c = r[7], t[4] = n * c + a * s + i * h - o * u, t[5] = i * c + a * u + o * s - n * h, t[6] = o * c + a * h + n * u - i * s, t[7] = a * c - n * s - i * u - o * h, t
+ }
+
+ function rotateAroundAxis(t, e, r, n) {
+ if (Math.abs(n) < F) return quat2_copy(t, e);
+ var i = Math.sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2]);
+ n *= .5;
+ var o = Math.sin(n),
+ a = o * r[0] / i,
+ s = o * r[1] / i,
+ u = o * r[2] / i,
+ h = Math.cos(n),
+ c = e[0],
+ l = e[1],
+ f = e[2],
+ d = e[3];
+ t[0] = c * h + d * a + l * u - f * s, t[1] = l * h + d * s + f * a - c * u, t[2] = f * h + d * u + c * s - l * a, t[3] = d * h - c * a - l * s - f * u;
+ var p = e[4],
+ m = e[5],
+ v = e[6],
+ g = e[7];
+ return t[4] = p * h + g * a + m * u - v * s, t[5] = m * h + g * s + v * a - p * u, t[6] = v * h + g * u + p * s - m * a, t[7] = g * h - p * a - m * s - v * u, t
+ }
+
+ function quat2_add(t, e, r) {
+ return t[0] = e[0] + r[0], t[1] = e[1] + r[1], t[2] = e[2] + r[2], t[3] = e[3] + r[3], t[4] = e[4] + r[4], t[5] = e[5] + r[5], t[6] = e[6] + r[6], t[7] = e[7] + r[7], t
+ }
+
+ function quat2_multiply(t, e, r) {
+ var n = e[0],
+ i = e[1],
+ o = e[2],
+ a = e[3],
+ s = r[4],
+ u = r[5],
+ h = r[6],
+ c = r[7],
+ l = e[4],
+ f = e[5],
+ d = e[6],
+ p = e[7],
+ m = r[0],
+ v = r[1],
+ g = r[2],
+ y = r[3];
+ return t[0] = n * y + a * m + i * g - o * v, t[1] = i * y + a * v + o * m - n * g, t[2] = o * y + a * g + n * v - i * m, t[3] = a * y - n * m - i * v - o * g, t[4] = n * c + a * s + i * h - o * u + l * y + p * m + f * g - d * v, t[5] = i * c + a * u + o * s - n * h + f * y + p * v + d * m - l * g, t[6] = o * c + a * h + n * u - i * s + d * y + p * g + l * v - f * m, t[7] = a * c - n * s - i * u - o * h + p * y - l * m - f * v - d * g, t
+ }
+ var vt = quat2_multiply;
+
+ function quat2_scale(t, e, r) {
+ return t[0] = e[0] * r, t[1] = e[1] * r, t[2] = e[2] * r, t[3] = e[3] * r, t[4] = e[4] * r, t[5] = e[5] * r, t[6] = e[6] * r, t[7] = e[7] * r, t
+ }
+ var gt = rt;
+
+ function quat2_lerp(t, e, r, n) {
+ var i = 1 - n;
+ return gt(e, r) < 0 && (n = -n), t[0] = e[0] * i + r[0] * n, t[1] = e[1] * i + r[1] * n, t[2] = e[2] * i + r[2] * n, t[3] = e[3] * i + r[3] * n, t[4] = e[4] * i + r[4] * n, t[5] = e[5] * i + r[5] * n, t[6] = e[6] * i + r[6] * n, t[7] = e[7] * i + r[7] * n, t
+ }
+
+ function quat2_invert(t, e) {
+ var r = bt(e);
+ return t[0] = -e[0] / r, t[1] = -e[1] / r, t[2] = -e[2] / r, t[3] = e[3] / r, t[4] = -e[4] / r, t[5] = -e[5] / r, t[6] = -e[6] / r, t[7] = e[7] / r, t
+ }
+
+ function quat2_conjugate(t, e) {
+ return t[0] = -e[0], t[1] = -e[1], t[2] = -e[2], t[3] = e[3], t[4] = -e[4], t[5] = -e[5], t[6] = -e[6], t[7] = e[7], t
+ }
+ var yt = it,
+ _t = yt,
+ bt = at,
+ xt = bt;
+
+ function quat2_normalize(t, e) {
+ var r = bt(e);
+ if (0 < r) {
+ r = Math.sqrt(r);
+ var n = e[0] / r,
+ i = e[1] / r,
+ o = e[2] / r,
+ a = e[3] / r,
+ s = e[4],
+ u = e[5],
+ h = e[6],
+ c = e[7],
+ l = n * s + i * u + o * h + a * c;
+ t[0] = n, t[1] = i, t[2] = o, t[3] = a, t[4] = (s - n * l) / r, t[5] = (u - i * l) / r, t[6] = (h - o * l) / r, t[7] = (c - a * l) / r
+ }
+ return t
+ }
+
+ function quat2_str(t) {
+ return "quat2(" + t[0] + ", " + t[1] + ", " + t[2] + ", " + t[3] + ", " + t[4] + ", " + t[5] + ", " + t[6] + ", " + t[7] + ")"
+ }
+
+ function quat2_exactEquals(t, e) {
+ return t[0] === e[0] && t[1] === e[1] && t[2] === e[2] && t[3] === e[3] && t[4] === e[4] && t[5] === e[5] && t[6] === e[6] && t[7] === e[7]
+ }
+
+ function quat2_equals(t, e) {
+ var r = t[0],
+ n = t[1],
+ i = t[2],
+ o = t[3],
+ a = t[4],
+ s = t[5],
+ u = t[6],
+ h = t[7],
+ c = e[0],
+ l = e[1],
+ f = e[2],
+ d = e[3],
+ p = e[4],
+ m = e[5],
+ v = e[6],
+ g = e[7];
+ return Math.abs(r - c) <= F * Math.max(1, Math.abs(r), Math.abs(c)) && Math.abs(n - l) <= F * Math.max(1, Math.abs(n), Math.abs(l)) && Math.abs(i - f) <= F * Math.max(1, Math.abs(i), Math.abs(f)) && Math.abs(o - d) <= F * Math.max(1, Math.abs(o), Math.abs(d)) && Math.abs(a - p) <= F * Math.max(1, Math.abs(a), Math.abs(p)) && Math.abs(s - m) <= F * Math.max(1, Math.abs(s), Math.abs(m)) && Math.abs(u - v) <= F * Math.max(1, Math.abs(u), Math.abs(v)) && Math.abs(h - g) <= F * Math.max(1, Math.abs(h), Math.abs(g))
+ }
+
+ function vec2_create() {
+ var t = new g(2);
+ return g != Float32Array && (t[0] = 0, t[1] = 0), t
+ }
+
+ function vec2_clone(t) {
+ var e = new g(2);
+ return e[0] = t[0], e[1] = t[1], e
+ }
+
+ function vec2_fromValues(t, e) {
+ var r = new g(2);
+ return r[0] = t, r[1] = e, r
+ }
+
+ function vec2_copy(t, e) {
+ return t[0] = e[0], t[1] = e[1], t
+ }
+
+ function vec2_set(t, e, r) {
+ return t[0] = e, t[1] = r, t
+ }
+
+ function vec2_add(t, e, r) {
+ return t[0] = e[0] + r[0], t[1] = e[1] + r[1], t
+ }
+
+ function vec2_subtract(t, e, r) {
+ return t[0] = e[0] - r[0], t[1] = e[1] - r[1], t
+ }
+
+ function vec2_multiply(t, e, r) {
+ return t[0] = e[0] * r[0], t[1] = e[1] * r[1], t
+ }
+
+ function vec2_divide(t, e, r) {
+ return t[0] = e[0] / r[0], t[1] = e[1] / r[1], t
+ }
+
+ function vec2_ceil(t, e) {
+ return t[0] = Math.ceil(e[0]), t[1] = Math.ceil(e[1]), t
+ }
+
+ function vec2_floor(t, e) {
+ return t[0] = Math.floor(e[0]), t[1] = Math.floor(e[1]), t
+ }
+
+ function vec2_min(t, e, r) {
+ return t[0] = Math.min(e[0], r[0]), t[1] = Math.min(e[1], r[1]), t
+ }
+
+ function vec2_max(t, e, r) {
+ return t[0] = Math.max(e[0], r[0]), t[1] = Math.max(e[1], r[1]), t
+ }
+
+ function vec2_round(t, e) {
+ return t[0] = Math.round(e[0]), t[1] = Math.round(e[1]), t
+ }
+
+ function vec2_scale(t, e, r) {
+ return t[0] = e[0] * r, t[1] = e[1] * r, t
+ }
+
+ function vec2_scaleAndAdd(t, e, r, n) {
+ return t[0] = e[0] + r[0] * n, t[1] = e[1] + r[1] * n, t
+ }
+
+ function vec2_distance(t, e) {
+ var r = e[0] - t[0],
+ n = e[1] - t[1];
+ return Math.sqrt(r * r + n * n)
+ }
+
+ function vec2_squaredDistance(t, e) {
+ var r = e[0] - t[0],
+ n = e[1] - t[1];
+ return r * r + n * n
+ }
+
+ function vec2_length(t) {
+ var e = t[0],
+ r = t[1];
+ return Math.sqrt(e * e + r * r)
+ }
+
+ function vec2_squaredLength(t) {
+ var e = t[0],
+ r = t[1];
+ return e * e + r * r
+ }
+
+ function vec2_negate(t, e) {
+ return t[0] = -e[0], t[1] = -e[1], t
+ }
+
+ function vec2_inverse(t, e) {
+ return t[0] = 1 / e[0], t[1] = 1 / e[1], t
+ }
+
+ function vec2_normalize(t, e) {
+ var r = e[0],
+ n = e[1],
+ i = r * r + n * n;
+ return 0 < i && (i = 1 / Math.sqrt(i), t[0] = e[0] * i, t[1] = e[1] * i), t
+ }
+
+ function vec2_dot(t, e) {
+ return t[0] * e[0] + t[1] * e[1]
+ }
+
+ function vec2_cross(t, e, r) {
+ var n = e[0] * r[1] - e[1] * r[0];
+ return t[0] = t[1] = 0, t[2] = n, t
+ }
+
+ function vec2_lerp(t, e, r, n) {
+ var i = e[0],
+ o = e[1];
+ return t[0] = i + n * (r[0] - i), t[1] = o + n * (r[1] - o), t
+ }
+
+ function vec2_random(t, e) {
+ e = e || 1;
+ var r = 2 * d() * Math.PI;
+ return t[0] = Math.cos(r) * e, t[1] = Math.sin(r) * e, t
+ }
+
+ function transformMat2(t, e, r) {
+ var n = e[0],
+ i = e[1];
+ return t[0] = r[0] * n + r[2] * i, t[1] = r[1] * n + r[3] * i, t
+ }
+
+ function transformMat2d(t, e, r) {
+ var n = e[0],
+ i = e[1];
+ return t[0] = r[0] * n + r[2] * i + r[4], t[1] = r[1] * n + r[3] * i + r[5], t
+ }
+
+ function vec2_transformMat3(t, e, r) {
+ var n = e[0],
+ i = e[1];
+ return t[0] = r[0] * n + r[3] * i + r[6], t[1] = r[1] * n + r[4] * i + r[7], t
+ }
+
+ function vec2_transformMat4(t, e, r) {
+ var n = e[0],
+ i = e[1];
+ return t[0] = r[0] * n + r[4] * i + r[12], t[1] = r[1] * n + r[5] * i + r[13], t
+ }
+
+ function vec2_rotate(t, e, r, n) {
+ var i = e[0] - r[0],
+ o = e[1] - r[1],
+ a = Math.sin(n),
+ s = Math.cos(n);
+ return t[0] = i * s - o * a + r[0], t[1] = i * a + o * s + r[1], t
+ }
+
+ function vec2_angle(t, e) {
+ var r = t[0],
+ n = t[1],
+ i = e[0],
+ o = e[1],
+ a = r * r + n * n;
+ 0 < a && (a = 1 / Math.sqrt(a));
+ var s = i * i + o * o;
+ 0 < s && (s = 1 / Math.sqrt(s));
+ var u = (r * i + n * o) * a * s;
+ return 1 < u ? 0 : u < -1 ? Math.PI : Math.acos(u)
+ }
+
+ function vec2_str(t) {
+ return "vec2(" + t[0] + ", " + t[1] + ")"
+ }
+
+ function vec2_exactEquals(t, e) {
+ return t[0] === e[0] && t[1] === e[1]
+ }
+
+ function vec2_equals(t, e) {
+ var r = t[0],
+ n = t[1],
+ i = e[0],
+ o = e[1];
+ return Math.abs(r - i) <= F * Math.max(1, Math.abs(r), Math.abs(i)) && Math.abs(n - o) <= F * Math.max(1, Math.abs(n), Math.abs(o))
+ }
+ var wt, Tt = vec2_length,
+ St = vec2_subtract,
+ Mt = vec2_multiply,
+ Et = vec2_divide,
+ At = vec2_distance,
+ Pt = vec2_squaredDistance,
+ It = vec2_squaredLength,
+ Ot = (wt = vec2_create(), function(t, e, r, n, i, o) {
+ var a = void 0,
+ s = void 0;
+ for (e || (e = 2), r || (r = 0), s = n ? Math.min(n * e + r, t.length) : t.length, a = r; a < s; a += e) wt[0] = t[a], wt[1] = t[a + 1], i(wt, wt, o), t[a] = wt[0], t[a + 1] = wt[1];
+ return t
+ });
+ r.d(e, "glMatrix", function() {
+ return n
+ }), r.d(e, "mat2", function() {
+ return i
+ }), r.d(e, "mat2d", function() {
+ return o
+ }), r.d(e, "mat3", function() {
+ return a
+ }), r.d(e, "mat4", function() {
+ return s
+ }), r.d(e, "quat", function() {
+ return c
+ }), r.d(e, "quat2", function() {
+ return l
+ }), r.d(e, "vec2", function() {
+ return f
+ }), r.d(e, "vec3", function() {
+ return u
+ }), r.d(e, "vec4", function() {
+ return h
+ })
+ }, function(t, e, r) {
+ "use strict";
+ e.__esModule = !0;
+ var n = function() {
+ function Component(t, e) {
+ if (function(t, e) {
+ if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
+ }(this, Component), !t) throw new Error("component requires an entity");
+ this.entity = t, this.data = e, this.name = "", this.game = null, this.active = !1
+ }
+ return Component.create = function(t, r) {
+ if (Component.mapHash[t]) return Component.mapHash[t];
+
+ function com(t, e) {
+ this.entity = t, this.data = e, r.constructor && r.constructor.call(this)
+ }
+ for (var e in com.prototype = Object.create(Component.prototype), com.id = t, r) com.prototype[e] = r[e];
+ return Component.mapHash[t] = com
+ }, Component
+ }();
+ (e.default = n).mapHash = {}
+ }, function(t, e, r) {
+ var n = r(11);
+ t.exports = function(t) {
+ if (!n(t)) throw TypeError(t + " is not an object!");
+ return t
+ }
+ }, function(t, e, r) {
+ "use strict";
+
+ function _defineProperties(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n)
+ }
+ }
+
+ function mockPromise() {
+ for (var t = arguments.length, e = new Array(t), r = 0; r < t; r++) e[r] = arguments[r];
+ return {
+ then: function(t) {
+ return t.apply(void 0, e)
+ }
+ }
+ }
+ r.d(e, "a", function() {
+ return s
+ });
+ var n = function() {
+ function PokiSDKMockup() {}
+ var t = PokiSDKMockup.prototype;
+ return t.init = function() {
+ return mockPromise()
+ }, t.gameLoadingStart = function() {
+ return mockPromise()
+ }, t.gameLoadingFinished = function() {
+ return mockPromise()
+ }, t.gameplayStart = function() {
+ return mockPromise()
+ }, t.gameplayStop = function() {
+ return mockPromise()
+ }, t.commercialBreak = function() {
+ return mockPromise()
+ }, t.happyTime = function(t) {
+ return mockPromise()
+ }, t.rewardedBreak = function() {
+ return mockPromise(!0)
+ }, PokiSDKMockup
+ }(),
+ i = function() {
+ function PokiSDKHangoutMockup() {}
+ var t = PokiSDKHangoutMockup.prototype;
+ return t.setDebug = function() {
+ return mockPromise()
+ }, t.getLobbyId = function() {
+ return mockPromise()
+ }, t.getLeaderboard = function(t, e, r) {
+ return mockPromise([{
+ name: "Yutani",
+ image: "icon_07_yutani",
+ score: 999999
+ }, {
+ name: "Spike",
+ image: "icon_08_spike",
+ score: 810312
+ }, {
+ name: "Fresh",
+ image: "icon_09_fresh",
+ score: 555555
+ }, {
+ name: "Tricky",
+ image: "icon_11_tricky",
+ score: 345678
+ }, {
+ name: "Lucy",
+ image: "icon_04_lucy",
+ score: 171110
+ }, {
+ name: "Ninja",
+ image: "icon_03_ninja",
+ score: 123456
+ }, {
+ name: "Brody",
+ image: "icon_00_brody",
+ score: 65900
+ }, {
+ name: "Tagbot",
+ image: "icon_01_tagbot",
+ score: 15505
+ }, {
+ name: "Tasha",
+ image: "icon_02_tasha",
+ score: 1e3
+ }, {
+ name: "King",
+ image: "icon_05_king",
+ score: 500
+ }, {
+ name: "ME",
+ image: "icon_friend",
+ score: r
+ }].sort(function(t, e) {
+ return e.score - t.score
+ }))
+ }, t.initHighscoreSession = function() {
+ return mockPromise()
+ }, t.saveHighscore = function() {
+ return mockPromise()
+ }, PokiSDKHangoutMockup
+ }(),
+ o = new n,
+ a = new i,
+ s = function() {
+ function Tabouzigt() {}
+ var t, e, r;
+ return Tabouzigt.sendCustomMessage = function(t, e, r) {
+ window.parent && window.parent.postMessage({
+ type: "pokiMessageEvent",
+ content: {
+ event: "pokiTrackingCustom",
+ data: {
+ eventNoun: t,
+ eventVerb: e,
+ eventData: r
+ }
+ }
+ }, "*")
+ }, t = Tabouzigt, r = [{
+ key: "SDK",
+ get: function() {
+ var t = window.Tabouzigtsdk || o;
+ return t && !t.sendCustomMessage && (t.sendCustomMessage = this.sendCustomMessage), t
+ }
+ }, {
+ key: "hangout",
+ get: function() {
+ var t = window.Tabouzigtsdk || o;
+ return t && t.hangout ? t.hangout : a
+ }
+ }], (e = null) && _defineProperties(t.prototype, e), r && _defineProperties(t, r), Tabouzigt
+ }()
+ }, function(t, e, r) {
+ "use strict";
+ e.__esModule = !0;
+ var n = function() {
+ function defineProperties(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n)
+ }
+ }
+ return function(t, e, r) {
+ return e && defineProperties(t.prototype, e), r && defineProperties(t, r), t
+ }
+ }();
+ var i = function() {
+ function Runner(t) {
+ var e = 1 < arguments.length && void 0 !== arguments[1] ? arguments[1] : 0;
+ ! function(t, e) {
+ if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
+ }(this, Runner), this.items = [], this._name = t, this.running = !1, this.dispatch = Runner.generateRun(t, e), this.run = this.dispatch, this.emit = this.dispatch, this.dummy = {}, this.dummy[t] = function() {}
+ }
+ return Runner.prototype.add = function(t) {
+ t[this._name] && (this.remove(t), this.items.push(t), this.toRemove = [], this.needsTidy = !1)
+ }, Runner.prototype.tidy = function() {
+ for (var t = 0; t < this.toRemove.length; t++) {
+ var e = this.toRemove[t]; - 1 !== e && this.items.splice(e, 1)
+ }
+ }, Runner.prototype.remove = function(t) {
+ var e = this.items.indexOf(t);
+ this.running ? (this.needsTidy = !0, this.toRemove.push(e), this.items[e] = this.dummy) : -1 !== e && this.items.splice(e, 1)
+ }, Runner.prototype.contains = function(t) {
+ return -1 !== this.items.indexOf(t)
+ }, Runner.prototype.removeAll = function() {
+ this.items.length = 0
+ }, Runner.generateRun = function(t, e) {
+ var r = t + "|" + e,
+ n = Runner.hash[r];
+ if (!n) {
+ if (0 < e) {
+ for (var i = "arg0", o = 1; o < e; o++) i += ",arg" + o;
+ n = new Function(i, "this.running = true; \n var items = this.items; \n for(var i=0;i= e.length && e === convertArrayBufferToString(t, 0, e.length)
+ }
+
+ function isFbxFormatASCII(t) {
+ var e, r, n = ["K", "a", "y", "d", "a", "r", "a", "\\", "F", "B", "X", "\\", "B", "i", "n", "a", "r", "y", "\\", "\\"],
+ i = 0;
+ for (var o = 0; o < n.length; ++o) {
+ if ((void 0, r = t[(e = 1) - 1], t = t.slice(i + e), i++, r) === n[o]) return !1
+ }
+ return !0
+ }
+
+ function getFbxVersion(t) {
+ var e = t.match(/FBXVersion: (\d+)/);
+ if (e) return parseInt(e[1]);
+ throw new Error("THREE.FBXLoader: Cannot find the version number for the file given.")
+ }
+
+ function convertFBXTimeToSeconds(t) {
+ return t / 46186158e3
+ }
+ var s = [];
+
+ function getData(t, e, r, n) {
+ var i;
+ switch (n.mappingType) {
+ case "ByPolygonVertex":
+ i = t;
+ break;
+ case "ByPolygon":
+ i = e;
+ break;
+ case "ByVertice":
+ i = r;
+ break;
+ case "AllSame":
+ i = n.indices[0]
+ }
+ "IndexToDirect" === n.referenceType && (i = n.indices[i]);
+ var o = i * n.dataSize,
+ a = o + n.dataSize;
+ return function(t, e, r, n) {
+ for (var i = r, o = 0; i < n; i++, o++) t[o] = e[i];
+ return t
+ }(s, n.buffer, o, a)
+ }
+ var I = new P.k,
+ O = new P.P;
+
+ function generateTransform(t) {
+ var e = new P.v,
+ r = new P.v,
+ n = new P.v,
+ i = new P.v,
+ o = new P.v,
+ a = new P.v,
+ s = new P.v,
+ u = new P.v,
+ h = new P.v,
+ c = new P.v,
+ l = new P.v,
+ f = t.inheritType ? t.inheritType : 0;
+ if (t.translation && e.setPosition(O.fromArray(t.translation)), t.preRotation) {
+ var d = t.preRotation.map(P.t.degToRad);
+ d.push(t.eulerOrder), r.makeRotationFromEuler(I.fromArray(d))
+ }
+ if (t.rotation) {
+ var p = t.rotation.map(P.t.degToRad);
+ p.push(t.eulerOrder), n.makeRotationFromEuler(I.fromArray(p))
+ }
+ if (t.postRotation) {
+ var m = t.postRotation.map(P.t.degToRad);
+ m.push(t.eulerOrder), i.makeRotationFromEuler(I.fromArray(m))
+ }
+ t.scale && o.scale(O.fromArray(t.scale)), t.scalingOffset && s.setPosition(O.fromArray(t.scalingOffset)), t.scalingPivot && a.setPosition(O.fromArray(t.scalingPivot)), t.rotationOffset && u.setPosition(O.fromArray(t.rotationOffset)), t.rotationPivot && h.setPosition(O.fromArray(t.rotationPivot)), t.parentMatrixWorld && (c = t.parentMatrixWorld);
+ var v = r.multiply(n).multiply(i),
+ g = new P.v;
+ c.extractRotation(g);
+ var y, _, b, x, w = new P.v;
+ if (w.copyPosition(c), b = w.getInverse(w).multiply(c), _ = g.getInverse(g).multiply(b), y = o, 0 === f) x = g.multiply(v).multiply(_).multiply(y);
+ else if (1 === f) x = g.multiply(_).multiply(v).multiply(y);
+ else {
+ var T = (new P.v).copy(o),
+ S = _.multiply(T.getInverse(T));
+ x = g.multiply(v).multiply(S).multiply(y)
+ }
+ var M = e.multiply(u).multiply(h).multiply(r).multiply(n).multiply(i).multiply(h.getInverse(h)).multiply(s).multiply(a).multiply(o).multiply(a.getInverse(a)),
+ E = (new P.v).copyPosition(M),
+ A = c.multiply(E);
+ return l.copyPosition(A), M = l.multiply(x)
+ }
+
+ function getEulerOrder(t) {
+ var e = ["ZYX", "YZX", "XZY", "ZXY", "YXZ", "XYZ"];
+ return 6 === (t = t || 0) ? e[0] : e[t]
+ }
+
+ function parseNumberArray(t) {
+ return t.split(",").map(function(t) {
+ return parseFloat(t)
+ })
+ }
+
+ function convertArrayBufferToString(t, e, r) {
+ return void 0 === e && (e = 0), void 0 === r && (r = t.byteLength), P.q.decodeText(new Uint8Array(t, e, r))
+ }
+
+ function append(t, e) {
+ for (var r = 0, n = t.length, i = e.length; r < i; r++, n++) t[n] = e[r]
+ }
+
+ function inject(t, e, r) {
+ return t.slice(0, e).concat(r).concat(t.slice(e))
+ }
+ }, function(t, e, r) {
+ var n = r(35),
+ i = Math.min;
+ t.exports = function(t) {
+ return 0 < t ? i(n(t), 9007199254740991) : 0
+ }
+ }, function(t, e, r) {
+ "use strict";
+
+ function arraySlice(t, e, r) {
+ return isTypedArray(t) ? new t.constructor(t.subarray(e, void 0 !== r ? r : t.length)) : t.slice(e, r)
+ }
+
+ function convertArray(t, e, r) {
+ return !t || !r && t.constructor === e ? t : "number" == typeof e.BYTES_PER_ELEMENT ? new e(t) : Array.prototype.slice.call(t)
+ }
+
+ function isTypedArray(t) {
+ return ArrayBuffer.isView(t) && !(t instanceof DataView)
+ }
+
+ function getKeyframeOrder(r) {
+ for (var t = r.length, e = new Array(t), n = 0; n !== t; ++n) e[n] = n;
+ return e.sort(function(t, e) {
+ return r[t] - r[e]
+ }), e
+ }
+
+ function sortedArray(t, e, r) {
+ for (var n = t.length, i = new t.constructor(n), o = 0, a = 0; a !== n; ++o)
+ for (var s = r[o] * e, u = 0; u !== e; ++u) i[a++] = t[s + u];
+ return i
+ }
+
+ function flattenJSON(t, e, r, n) {
+ for (var i = 1, o = t[0]; void 0 !== o && void 0 === o[n];) o = t[i++];
+ if (void 0 !== o) {
+ var a = o[n];
+ if (void 0 !== a)
+ if (Array.isArray(a))
+ for (; void 0 !== (a = o[n]) && (e.push(o.time), r.push.apply(r, a)), void 0 !== (o = t[i++]););
+ else if (void 0 !== a.toArray)
+ for (; void 0 !== (a = o[n]) && (e.push(o.time), a.toArray(r, r.length)), void 0 !== (o = t[i++]););
+ else
+ for (; void 0 !== (a = o[n]) && (e.push(o.time), r.push(a)), void 0 !== (o = t[i++]););
+ }
+ }
+
+ function subclip(t, e, r, n, i) {
+ i = i || 30;
+ var o = t.clone();
+ o.name = e;
+ for (var a = [], s = 0; s < o.tracks.length; ++s) {
+ for (var u = o.tracks[s], h = u.getValueSize(), c = [], l = [], f = 0; f < u.times.length; ++f) {
+ var d = u.times[f] * i;
+ if (!(d < r || n <= d)) {
+ c.push(u.times[f]);
+ for (var p = 0; p < h; ++p) l.push(u.values[f * h + p])
+ }
+ }
+ 0 !== c.length && (u.times = convertArray(c, u.times.constructor), u.values = convertArray(l, u.values.constructor), a.push(u))
+ }
+ o.tracks = a;
+ var m = 1 / 0;
+ for (s = 0; s < o.tracks.length; ++s) m > o.tracks[s].times[0] && (m = o.tracks[s].times[0]);
+ for (s = 0; s < o.tracks.length; ++s) o.tracks[s].shift(-1 * m);
+ return o.resetDuration(), o
+ }
+ r.d(e, "a", function() {
+ return arraySlice
+ }), r.d(e, "b", function() {
+ return convertArray
+ }), r.d(e, "e", function() {
+ return isTypedArray
+ }), r.d(e, "d", function() {
+ return getKeyframeOrder
+ }), r.d(e, "f", function() {
+ return sortedArray
+ }), r.d(e, "c", function() {
+ return flattenJSON
+ }), r.d(e, "g", function() {
+ return subclip
+ })
+ }, function(t, e, r) {
+ t.exports = !r(10)(function() {
+ return 7 != Object.defineProperty({}, "a", {
+ get: function() {
+ return 7
+ }
+ }).a
+ })
+ }, function(t, e, r) {
+ var n = r(6),
+ i = r(134),
+ o = r(38),
+ a = Object.defineProperty;
+ e.f = r(19) ? Object.defineProperty : function(t, e, r) {
+ if (n(t), e = o(e, !0), n(r), i) try {
+ return a(t, e, r)
+ } catch (t) {}
+ if ("get" in r || "set" in r) throw TypeError("Accessors not supported!");
+ return "value" in r && (t[e] = r.value), t
+ }
+ }, function(t, e, r) {
+ "use strict";
+
+ function _defineProperties(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n)
+ }
+ }
+ var n = function() {
+ function Device() {
+ this.arora = !1, this.chrome = !1, this.epiphany = !1, this.firefox = !1, this.mobileSafari = !1, this.ie = !1, this.ieVersion = 0, this.trident = !1, this.tridentVersion = 0, this.midori = !1, this.opera = !1, this.safari = !1, this.silk = !1, this.webApp = !1, this.cocoonJS = !1, this.android = !1, this.chromeOS = !1, this.iOS = !1, this.linux = !1, this.macOS = !1, this.windows = !1, this.desktop = !1, this.pixelRatio = 0, this.iPhone = !1, this.iPhone4 = !1, this.iPad = !1, this.blob = !1, this.canvas = !1, this.localStorage = !1, this.file = !1, this.fileSystem = !1, this.webGL = !1, this.worker = !1, this.audioData = !1, this.webAudio = !1, this.ogg = !1, this.opus = !1, this.mp3 = !1, this.wav = !1, this.m4a = !1, this.webm = !1;
+ var t = navigator.userAgent;
+ this._checkBrowser(t), this._checkOS(t), this._checkDevice(t), this._checkAudio(), this._checkFeatures(), this._checkIsMobile(), this._checkIsTouch()
+ }
+ var t, e, r, n = Device.prototype;
+ return n._checkBrowser = function(t) {
+ /Arora/.test(t) ? this.arora = !0 : /Opera|OPR|op/.test(t) ? (this.opera = !0, this.chrome = !1) : /Chrome/.test(t) ? this.chrome = !0 : /Epiphany/.test(t) ? this.epiphany = !0 : /Firefox/.test(t) ? this.firefox = !0 : /Mobile Safari/.test(t) ? this.mobileSafari = !0 : /MSIE (\d+\.\d+);/.test(t) || navigator.userAgent.match(/Trident.*rv[ :]*11\./) ? (this.ie = !0, this.ieVersion = parseInt(RegExp.$1, 10)) : /Midori/.test(t) ? this.midori = !0 : /Safari/.test(t) ? this.safari = !0 : /\bSilk\b/.test(t) ? this.silk = !0 : /Trident\/(\d+\.\d+)(.*)rv:(\d+\.\d+)/.test(t) && (this.ie = !0, this.trident = !0, this.tridentVersion = parseInt(RegExp.$1, 10), this.ieVersion = parseInt(RegExp.$3, 10)), navigator.standalone && (this.webApp = !0), navigator.isCocoonJS && (this.cocoonJS = !0)
+ }, n._checkOS = function(t) {
+ if (/Android/.test(t)) this.android = !0;
+ else if (/CrOS/.test(t)) this.chromeOS = !0;
+ else if (/iP[ao]d|iPhone/i.test(t)) {
+ this.iOS = !0;
+ var e = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
+ this.iOS_version = [parseInt(e[1], 10), parseInt(e[2], 10), parseInt(e[3] || 0, 10)]
+ } else /Linux/.test(t) ? this.linux = !0 : /Mac OS/.test(t) ? this.macOS = !0 : /Windows/.test(t) && (this.windows = !0);
+ (this.windows || this.macOS || this.linux || this.chromeOS) && (this.desktop = !0)
+ }, n._checkDevice = function() {
+ this.pixelRatio = window.devicePixelRatio || 1, this.iPhone = -1 !== navigator.userAgent.toLowerCase().indexOf("iphone"), this.iPhone4 = 2 === this.pixelRatio && this.iPhone, this.iPhone4 && (this.iPhone4 = 480 == window.screen.height && 320 == window.screen.width || 480 == window.screen.width && 320 == window.screen.height), this.iPad = -1 !== navigator.userAgent.toLowerCase().indexOf("ipad")
+ }, n._checkFeatures = function() {
+ void 0 !== window.Blob && (this.blob = !0), this.canvas = !!window.CanvasRenderingContext2D;
+ try {
+ this.localStorage = !!localStorage.getItem
+ } catch (t) {
+ this.localStorage = !1
+ }
+ this.file = !!(window.File && window.FileReader && window.FileList && window.Blob), this.fileSystem = !!window.requestFileSystem, this.webGL = function() {
+ try {
+ var t = document.createElement("canvas");
+ return !!window.WebGLRenderingContext && (t.getContext("webgl") || t.getContext("experimental-webgl"))
+ } catch (t) {
+ return !1
+ }
+ }(), (this.android || this.ie) && (this.webGL = !1), this.worker = !!window.Worker, ("ontouchstart" in document.documentElement || window.navigator.msPointerEnabled) && (this.touch = !0)
+ }, n._checkAudio = function() {
+ this.audioData = !!window.Audio, this.webaudio = !(!window.AudioContext && !window.webkitAudioContext);
+ var t = document.createElement("audio");
+ try {
+ !1 == !!t.canPlayType && (t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, "") && (this.ogg = !0), t.canPlayType("audio/mpeg;").replace(/^no$/, "") && (this.mp3 = !0), t.canPlayType('audio/wav; codecs="1"').replace(/^no$/, "") && (this.wav = !0), (t.canPlayType("audio/x-m4a;") || t.canPlayType("audio/aac;").replace(/^no$/, "")) && (this.m4a = !0))
+ } catch (t) {}
+ }, n._checkIsMobile = function() {
+ var t, e = !1;
+ t = navigator.userAgent || navigator.vendor || window.opera, (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(t) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(t.substr(0, 4))) && (e = !0), this.isMobile = e, this.mobile = e
+ }, n._checkIsTouch = function() {
+ this.isTouch = "ontouchstart" in window || 0 < navigator.MaxTouchPoints || 0 < navigator.msMaxTouchPoints
+ }, n.is_touch_device = function() {}, n.getInfo = function() {
+ var t = "DEVICE OUTPUT\n\n";
+ return t += "---\n", t += "Browser Info :: \n", t += "Arora : " + this.arora + "\n", t += "Chrome : " + this.chrome + "\n", t += "Epiphany : " + this.epiphany + "\n", t += "Firefox : " + this.firefox + "\n", t += "Mobile Safari : " + this.mobileSafari + "\n", t += "IE : " + this.ie, this.ie ? t += " (Version " + this.ieVersion + ")\n" : t += "\n", t += "Midori : " + this.midori + "\n", t += "Opera : " + this.opera + "\n", t += "Safari : " + this.safari + "\n", t += "Web App : " + this.webApp + "\n", t += "CocoonJS : " + this.cocoonJS + "\n", t += "Android : " + this.android + "\n", t += "---\n", t += "Operating System :: \n", t += "Chrome OS : " + this.chromeOS + "\n", t += "iOS : " + this.iOS + "\n", t += "Linux : " + this.linux + "\n", t += "Mac OS : " + this.macOS + "\n", t += "Windows : " + this.windows + "\n", t += "Desktop : " + this.desktop + "\n", t += "---\n", t += "Device Type : \n", t += "Pixel Ratio : " + this.pixelRatio + "\n", t += "iPhone : " + this.iPhone + "\n", t += "iPhone 4 : " + this.iPhone4 + "\n", t += "iPad : " + this.iPad + "\n", t += "---\n", t += "Features :: \n", t += "Blob : " + this.blob + "\n", t += "Canvas : " + this.canvas + "\n", t += "LocalStorage : " + this.localStorage + "\n", t += "File : " + this.file + "\n", t += "File System : " + this.fileSystem + "\n", t += "WebGL : " + this.webGL + "\n", t += "Workers : " + this.worker + "\n", t += "---\n", t += "Audio :: \n", t += "AudioData : " + this.audioData + "\n", t += "WebAudio : " + this.webAudio + "\n", t += "Supports .ogg : " + this.ogg + "\n", t += "Supports Opus : " + this.opus + "\n", t += "Supports .mp3 : " + this.mp3 + "\n", t += "Supports .wav : " + this.wav + "\n", t += "Supports .m4a : " + this.m4a + "\n", t += "Supports .webm : " + this.webm
+ }, t = Device, (e = [{
+ key: "ie9",
+ get: function() {
+ return this.ie && 9 === this.ieVersion
+ }
+ }, {
+ key: "useSM2",
+ get: function() {
+ return this.ie || this.opera
+ }
+ }]) && _defineProperties(t.prototype, e), r && _defineProperties(t, r), Device
+ }();
+ n.instance = new n, e.a = n
+ }, function(t, e, r) {
+ var n = r(39);
+ t.exports = function(t) {
+ return Object(n(t))
+ }
+ }, function(i, f, t) {
+ (function(r) {
+ var n;
+ ! function() {
+ "use strict";
+ var t = function() {
+ this.init()
+ };
+ t.prototype = {
+ init: function() {
+ var t = this || b;
+ return t._counter = 1e3, t._html5AudioPool = [], t.html5PoolSize = 10, t._codecs = {}, t._howls = [], t._muted = !1, t._volume = 1, t._canPlayEvent = "canplaythrough", t._navigator = "undefined" != typeof window && window.navigator ? window.navigator : null, t.masterGain = null, t.noAudio = !1, t.usingWebAudio = !0, t.autoSuspend = !0, t.ctx = null, t.autoUnlock = !0, t._setup(), t
+ },
+ volume: function(t) {
+ var e = this || b;
+ if (t = parseFloat(t), e.ctx || l(), void 0 !== t && 0 <= t && t <= 1) {
+ if (e._volume = t, e._muted) return e;
+ e.usingWebAudio && e.masterGain.gain.setValueAtTime(t, b.ctx.currentTime);
+ for (var r = 0; r < e._howls.length; r++)
+ if (!e._howls[r]._webAudio)
+ for (var n = e._howls[r]._getSoundIds(), i = 0; i < n.length; i++) {
+ var o = e._howls[r]._soundById(n[i]);
+ o && o._node && (o._node.volume = o._volume * t)
+ }
+ return e
+ }
+ return e._volume
+ },
+ mute: function(t) {
+ var e = this || b;
+ e.ctx || l(), e._muted = t, e.usingWebAudio && e.masterGain.gain.setValueAtTime(t ? 0 : e._volume, b.ctx.currentTime);
+ for (var r = 0; r < e._howls.length; r++)
+ if (!e._howls[r]._webAudio)
+ for (var n = e._howls[r]._getSoundIds(), i = 0; i < n.length; i++) {
+ var o = e._howls[r]._soundById(n[i]);
+ o && o._node && (o._node.muted = !!t || o._muted)
+ }
+ return e
+ },
+ unload: function() {
+ for (var t = this || b, e = t._howls.length - 1; 0 <= e; e--) t._howls[e].unload();
+ return t.usingWebAudio && t.ctx && void 0 !== t.ctx.close && (t.ctx.close(), t.ctx = null, l()), t
+ },
+ codecs: function(t) {
+ return (this || b)._codecs[t.replace(/^x-/, "")]
+ },
+ _setup: function() {
+ var e = this || b;
+ if (e.state = e.ctx && e.ctx.state || "suspended", e._autoSuspend(), !e.usingWebAudio)
+ if ("undefined" != typeof Audio) try {
+ void 0 === (new Audio).oncanplaythrough && (e._canPlayEvent = "canplay")
+ } catch (t) {
+ e.noAudio = !0
+ } else e.noAudio = !0;
+ try {
+ (new Audio).muted && (e.noAudio = !0)
+ } catch (t) {}
+ return e.noAudio || e._setupCodecs(), e
+ },
+ _setupCodecs: function() {
+ var e = this || b,
+ t = null;
+ try {
+ t = "undefined" != typeof Audio ? new Audio : null
+ } catch (t) {
+ return e
+ }
+ if (!t || "function" != typeof t.canPlayType) return e;
+ var r = t.canPlayType("audio/mpeg;").replace(/^no$/, ""),
+ n = e._navigator && e._navigator.userAgent.match(/OPR\/([0-6].)/g),
+ i = n && parseInt(n[0].split("/")[1], 10) < 33;
+ return e._codecs = {
+ mp3: !(i || !r && !t.canPlayType("audio/mp3;").replace(/^no$/, "")),
+ mpeg: !!r,
+ opus: !!t.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ""),
+ ogg: !!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""),
+ oga: !!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""),
+ wav: !!t.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ""),
+ aac: !!t.canPlayType("audio/aac;").replace(/^no$/, ""),
+ caf: !!t.canPlayType("audio/x-caf;").replace(/^no$/, ""),
+ m4a: !!(t.canPlayType("audio/x-m4a;") || t.canPlayType("audio/m4a;") || t.canPlayType("audio/aac;")).replace(/^no$/, ""),
+ mp4: !!(t.canPlayType("audio/x-mp4;") || t.canPlayType("audio/mp4;") || t.canPlayType("audio/aac;")).replace(/^no$/, ""),
+ weba: !!t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ""),
+ webm: !!t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ""),
+ dolby: !!t.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/, ""),
+ flac: !!(t.canPlayType("audio/x-flac;") || t.canPlayType("audio/flac;")).replace(/^no$/, "")
+ }, e
+ },
+ _unlockAudio: function() {
+ var s = this || b,
+ t = /iPhone|iPad|iPod|Android|BlackBerry|BB10|Silk|Mobi|Chrome|Safari/i.test(s._navigator && s._navigator.userAgent);
+ if (!s._audioUnlocked && s.ctx && t) {
+ s._audioUnlocked = !1, s.autoUnlock = !1, s._mobileUnloaded || 44100 === s.ctx.sampleRate || (s._mobileUnloaded = !0, s.unload()), s._scratchBuffer = s.ctx.createBuffer(1, 1, 22050);
+ var u = function(t) {
+ for (var e = 0; e < s.html5PoolSize; e++) {
+ var r = new Audio;
+ r._unlocked = !0, s._releaseHtml5Audio(r)
+ }
+ for (e = 0; e < s._howls.length; e++)
+ if (!s._howls[e]._webAudio)
+ for (var n = s._howls[e]._getSoundIds(), i = 0; i < n.length; i++) {
+ var o = s._howls[e]._soundById(n[i]);
+ o && o._node && !o._node._unlocked && (o._node._unlocked = !0, o._node.load())
+ }
+ s._autoResume();
+ var a = s.ctx.createBufferSource();
+ a.buffer = s._scratchBuffer, a.connect(s.ctx.destination), void 0 === a.start ? a.noteOn(0) : a.start(0), "function" == typeof s.ctx.resume && s.ctx.resume(), a.onended = function() {
+ a.disconnect(0), s._audioUnlocked = !0, document.removeEventListener("touchstart", u, !0), document.removeEventListener("touchend", u, !0), document.removeEventListener("click", u, !0);
+ for (var t = 0; t < s._howls.length; t++) s._howls[t]._emit("unlock")
+ }
+ };
+ return document.addEventListener("touchstart", u, !0), document.addEventListener("touchend", u, !0), document.addEventListener("click", u, !0), s
+ }
+ },
+ _obtainHtml5Audio: function() {
+ var t = this || b;
+ if (t._html5AudioPool.length) return t._html5AudioPool.pop();
+ var e = (new Audio).play();
+ return e && "undefined" != typeof Promise && (e instanceof Promise || "function" == typeof e.then) && e.catch(function() {}), new Audio
+ },
+ _releaseHtml5Audio: function(t) {
+ var e = this || b;
+ return t._unlocked && e._html5AudioPool.push(t), e
+ },
+ _autoSuspend: function() {
+ var t = this;
+ if (t.autoSuspend && t.ctx && void 0 !== t.ctx.suspend && b.usingWebAudio) {
+ for (var e = 0; e < t._howls.length; e++)
+ if (t._howls[e]._webAudio)
+ for (var r = 0; r < t._howls[e]._sounds.length; r++)
+ if (!t._howls[e]._sounds[r]._paused) return t;
+ return t._suspendTimer && clearTimeout(t._suspendTimer), t._suspendTimer = setTimeout(function() {
+ t.autoSuspend && (t._suspendTimer = null, t.state = "suspending", t.ctx.suspend().then(function() {
+ t.state = "suspended", t._resumeAfterSuspend && (delete t._resumeAfterSuspend, t._autoResume())
+ }))
+ }, 3e4), t
+ }
+ },
+ _autoResume: function() {
+ var e = this;
+ if (e.ctx && void 0 !== e.ctx.resume && b.usingWebAudio) return "running" === e.state && e._suspendTimer ? (clearTimeout(e._suspendTimer), e._suspendTimer = null) : "suspended" === e.state ? (e.ctx.resume().then(function() {
+ e.state = "running";
+ for (var t = 0; t < e._howls.length; t++) e._howls[t]._emit("resume")
+ }), e._suspendTimer && (clearTimeout(e._suspendTimer), e._suspendTimer = null)) : "suspending" === e.state && (e._resumeAfterSuspend = !0), e
+ }
+ };
+ var b = new t,
+ e = function(t) {
+ t.src && 0 !== t.src.length && this.init(t)
+ };
+ e.prototype = {
+ init: function(t) {
+ var e = this;
+ return b.ctx || l(), e._autoplay = t.autoplay || !1, e._format = "string" != typeof t.format ? t.format : [t.format], e._html5 = t.html5 || !1, e._muted = t.mute || !1, e._loop = t.loop || !1, e._pool = t.pool || 5, e._preload = "boolean" != typeof t.preload || t.preload, e._rate = t.rate || 1, e._sprite = t.sprite || {}, e._src = "string" != typeof t.src ? t.src : [t.src], e._volume = void 0 !== t.volume ? t.volume : 1, e._xhrWithCredentials = t.xhrWithCredentials || !1, e._duration = 0, e._state = "unloaded", e._sounds = [], e._endTimers = {}, e._queue = [], e._playLock = !1, e._onend = t.onend ? [{
+ fn: t.onend
+ }] : [], e._onfade = t.onfade ? [{
+ fn: t.onfade
+ }] : [], e._onload = t.onload ? [{
+ fn: t.onload
+ }] : [], e._onloaderror = t.onloaderror ? [{
+ fn: t.onloaderror
+ }] : [], e._onplayerror = t.onplayerror ? [{
+ fn: t.onplayerror
+ }] : [], e._onpause = t.onpause ? [{
+ fn: t.onpause
+ }] : [], e._onplay = t.onplay ? [{
+ fn: t.onplay
+ }] : [], e._onstop = t.onstop ? [{
+ fn: t.onstop
+ }] : [], e._onmute = t.onmute ? [{
+ fn: t.onmute
+ }] : [], e._onvolume = t.onvolume ? [{
+ fn: t.onvolume
+ }] : [], e._onrate = t.onrate ? [{
+ fn: t.onrate
+ }] : [], e._onseek = t.onseek ? [{
+ fn: t.onseek
+ }] : [], e._onunlock = t.onunlock ? [{
+ fn: t.onunlock
+ }] : [], e._onresume = [], e._webAudio = b.usingWebAudio && !e._html5, void 0 !== b.ctx && b.ctx && b.autoUnlock && b._unlockAudio(), b._howls.push(e), e._autoplay && e._queue.push({
+ event: "play",
+ action: function() {
+ e.play()
+ }
+ }), e._preload && e.load(), e
+ },
+ load: function() {
+ var t = this,
+ e = null;
+ if (b.noAudio) t._emit("loaderror", null, "No audio support.");
+ else {
+ "string" == typeof t._src && (t._src = [t._src]);
+ for (var r = 0; r < t._src.length; r++) {
+ var n, i;
+ if (t._format && t._format[r]) n = t._format[r];
+ else {
+ if ("string" != typeof(i = t._src[r])) {
+ t._emit("loaderror", null, "Non-string found in selected audio sources - ignoring.");
+ continue
+ }(n = /^data:audio\/([^;,]+);/i.exec(i)) || (n = /\.([^.]+)$/.exec(i.split("?", 1)[0])), n && (n = n[1].toLowerCase())
+ }
+ if (n && b.codecs(n)) {
+ e = t._src[r];
+ break
+ }
+ }
+ if (e) return t._src = e, t._state = "loading", "https:" === window.location.protocol && "http:" === e.slice(0, 5) && (t._html5 = !0, t._webAudio = !1), new o(t), t._webAudio && s(t), t;
+ t._emit("loaderror", null, "No codec support for selected audio sources.")
+ }
+ },
+ play: function(e, r) {
+ var n = this,
+ t = null;
+ if ("number" == typeof e) t = e, e = null;
+ else {
+ if ("string" == typeof e && "loaded" === n._state && !n._sprite[e]) return null;
+ if (void 0 === e && (e = "__default", !n._playLock)) {
+ for (var i = 0, o = 0; o < n._sounds.length; o++) n._sounds[o]._paused && !n._sounds[o]._ended && (i++, t = n._sounds[o]._id);
+ 1 === i ? e = null : t = null
+ }
+ }
+ var a = t ? n._soundById(t) : n._inactiveSound();
+ if (!a) return null;
+ if (t && !e && (e = a._sprite || "__default"), "loaded" !== n._state) {
+ a._sprite = e, a._ended = !1;
+ var s = a._id;
+ return n._queue.push({
+ event: "play",
+ action: function() {
+ n.play(s)
+ }
+ }), s
+ }
+ if (t && !a._paused) return r || n._loadQueue("play"), a._id;
+ n._webAudio && b._autoResume();
+ var u = Math.max(0, 0 < a._seek ? a._seek : n._sprite[e][0] / 1e3),
+ h = Math.max(0, (n._sprite[e][0] + n._sprite[e][1]) / 1e3 - u),
+ c = 1e3 * h / Math.abs(a._rate),
+ l = n._sprite[e][0] / 1e3,
+ f = (n._sprite[e][0] + n._sprite[e][1]) / 1e3,
+ d = !(!a._loop && !n._sprite[e][2]);
+ a._sprite = e, a._ended = !1;
+ var p = function() {
+ a._paused = !1, a._seek = u, a._start = l, a._stop = f, a._loop = d
+ };
+ if (!(f <= u)) {
+ var m = a._node;
+ if (n._webAudio) {
+ var v = function() {
+ n._playLock = !1, p(), n._refreshBuffer(a);
+ var t = a._muted || n._muted ? 0 : a._volume;
+ m.gain.setValueAtTime(t, b.ctx.currentTime), a._playStart = b.ctx.currentTime, void 0 === m.bufferSource.start ? a._loop ? m.bufferSource.noteGrainOn(0, u, 86400) : m.bufferSource.noteGrainOn(0, u, h) : a._loop ? m.bufferSource.start(0, u, 86400) : m.bufferSource.start(0, u, h), c !== 1 / 0 && (n._endTimers[a._id] = setTimeout(n._ended.bind(n, a), c)), r || setTimeout(function() {
+ n._emit("play", a._id), n._loadQueue()
+ }, 0)
+ };
+ "running" === b.state ? v() : (n._playLock = !0, n.once("resume", v), n._clearTimer(a._id))
+ } else {
+ var g = function() {
+ m.currentTime = u, m.muted = a._muted || n._muted || b._muted || m.muted, m.volume = a._volume * b.volume(), m.playbackRate = a._rate;
+ try {
+ var t = m.play();
+ if (t && "undefined" != typeof Promise && (t instanceof Promise || "function" == typeof t.then) ? (n._playLock = !0, p(), t.then(function() {
+ n._playLock = !1, m._unlocked = !0, r || (n._emit("play", a._id), n._loadQueue())
+ }).catch(function() {
+ n._playLock = !1, n._emit("playerror", a._id, "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction."), a._ended = !0, a._paused = !0
+ })) : r || (n._playLock = !1, p(), n._emit("play", a._id), n._loadQueue()), m.playbackRate = a._rate, m.paused) return void n._emit("playerror", a._id, "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction.");
+ "__default" !== e || a._loop ? n._endTimers[a._id] = setTimeout(n._ended.bind(n, a), c) : (n._endTimers[a._id] = function() {
+ n._ended(a), m.removeEventListener("ended", n._endTimers[a._id], !1)
+ }, m.addEventListener("ended", n._endTimers[a._id], !1))
+ } catch (t) {
+ n._emit("playerror", a._id, t)
+ }
+ },
+ y = window && window.ejecta || !m.readyState && b._navigator.isCocoonJS;
+ if (3 <= m.readyState || y) g();
+ else {
+ n._playLock = !0;
+ var _ = function() {
+ g(), m.removeEventListener(b._canPlayEvent, _, !1)
+ };
+ m.addEventListener(b._canPlayEvent, _, !1), n._clearTimer(a._id)
+ }
+ }
+ return a._id
+ }
+ n._ended(a)
+ },
+ pause: function(t) {
+ var e = this;
+ if ("loaded" !== e._state || e._playLock) return e._queue.push({
+ event: "pause",
+ action: function() {
+ e.pause(t)
+ }
+ }), e;
+ for (var r = e._getSoundIds(t), n = 0; n < r.length; n++) {
+ e._clearTimer(r[n]);
+ var i = e._soundById(r[n]);
+ if (i && !i._paused && (i._seek = e.seek(r[n]), i._rateSeek = 0, i._paused = !0, e._stopFade(r[n]), i._node))
+ if (e._webAudio) {
+ if (!i._node.bufferSource) continue;
+ void 0 === i._node.bufferSource.stop ? i._node.bufferSource.noteOff(0) : i._node.bufferSource.stop(0), e._cleanBuffer(i._node)
+ } else isNaN(i._node.duration) && i._node.duration !== 1 / 0 || i._node.pause();
+ arguments[1] || e._emit("pause", i ? i._id : null)
+ }
+ return e
+ },
+ stop: function(t, e) {
+ var r = this;
+ if ("loaded" !== r._state || r._playLock) return r._queue.push({
+ event: "stop",
+ action: function() {
+ r.stop(t)
+ }
+ }), r;
+ for (var n = r._getSoundIds(t), i = 0; i < n.length; i++) {
+ r._clearTimer(n[i]);
+ var o = r._soundById(n[i]);
+ o && (o._seek = o._start || 0, o._rateSeek = 0, o._paused = !0, o._ended = !0, r._stopFade(n[i]), o._node && (r._webAudio ? o._node.bufferSource && (void 0 === o._node.bufferSource.stop ? o._node.bufferSource.noteOff(0) : o._node.bufferSource.stop(0), r._cleanBuffer(o._node)) : isNaN(o._node.duration) && o._node.duration !== 1 / 0 || (o._node.currentTime = o._start || 0, o._node.pause())), e || r._emit("stop", o._id))
+ }
+ return r
+ },
+ mute: function(t, e) {
+ var r = this;
+ if ("loaded" !== r._state || r._playLock) return r._queue.push({
+ event: "mute",
+ action: function() {
+ r.mute(t, e)
+ }
+ }), r;
+ if (void 0 === e) {
+ if ("boolean" != typeof t) return r._muted;
+ r._muted = t
+ }
+ for (var n = r._getSoundIds(e), i = 0; i < n.length; i++) {
+ var o = r._soundById(n[i]);
+ o && (o._muted = t, o._interval && r._stopFade(o._id), r._webAudio && o._node ? o._node.gain.setValueAtTime(t ? 0 : o._volume, b.ctx.currentTime) : o._node && (o._node.muted = !!b._muted || t), r._emit("mute", o._id))
+ }
+ return r
+ },
+ volume: function() {
+ var t, e, r, n = this,
+ i = arguments;
+ if (0 === i.length) return n._volume;
+ if (1 === i.length || 2 === i.length && void 0 === i[1] ? 0 <= n._getSoundIds().indexOf(i[0]) ? e = parseInt(i[0], 10) : t = parseFloat(i[0]) : 2 <= i.length && (t = parseFloat(i[0]), e = parseInt(i[1], 10)), !(void 0 !== t && 0 <= t && t <= 1)) return (r = e ? n._soundById(e) : n._sounds[0]) ? r._volume : 0;
+ if ("loaded" !== n._state || n._playLock) return n._queue.push({
+ event: "volume",
+ action: function() {
+ n.volume.apply(n, i)
+ }
+ }), n;
+ void 0 === e && (n._volume = t), e = n._getSoundIds(e);
+ for (var o = 0; o < e.length; o++)(r = n._soundById(e[o])) && (r._volume = t, i[2] || n._stopFade(e[o]), n._webAudio && r._node && !r._muted ? r._node.gain.setValueAtTime(t, b.ctx.currentTime) : r._node && !r._muted && (r._node.volume = t * b.volume()), n._emit("volume", r._id));
+ return n
+ },
+ fade: function(t, e, r, n) {
+ var i = this;
+ if ("loaded" !== i._state || i._playLock) return i._queue.push({
+ event: "fade",
+ action: function() {
+ i.fade(t, e, r, n)
+ }
+ }), i;
+ t = parseFloat(t), e = parseFloat(e), r = parseFloat(r), i.volume(t, n);
+ for (var o = i._getSoundIds(n), a = 0; a < o.length; a++) {
+ var s = i._soundById(o[a]);
+ if (s) {
+ if (n || i._stopFade(o[a]), i._webAudio && !s._muted) {
+ var u = b.ctx.currentTime,
+ h = u + r / 1e3;
+ s._volume = t, s._node.gain.setValueAtTime(t, u), s._node.gain.linearRampToValueAtTime(e, h)
+ }
+ i._startFadeInterval(s, t, e, r, o[a], void 0 === n)
+ }
+ }
+ return i
+ },
+ _startFadeInterval: function(e, r, n, i, t, o) {
+ var a = this,
+ s = r,
+ u = n - r,
+ h = Math.abs(u / .01),
+ c = Math.max(4, 0 < h ? i / h : i),
+ l = Date.now();
+ e._fadeTo = n, e._interval = setInterval(function() {
+ var t = (Date.now() - l) / i;
+ l = Date.now(), s += u * t, s = Math.max(0, s), s = Math.min(1, s), s = Math.round(100 * s) / 100, a._webAudio ? e._volume = s : a.volume(s, e._id, !0), o && (a._volume = s), (n < r && s <= n || r < n && n <= s) && (clearInterval(e._interval), e._interval = null, e._fadeTo = null, a.volume(n, e._id), a._emit("fade", e._id))
+ }, c)
+ },
+ _stopFade: function(t) {
+ var e = this._soundById(t);
+ return e && e._interval && (this._webAudio && e._node.gain.cancelScheduledValues(b.ctx.currentTime), clearInterval(e._interval), e._interval = null, this.volume(e._fadeTo, t), e._fadeTo = null, this._emit("fade", t)), this
+ },
+ loop: function() {
+ var t, e, r, n = arguments;
+ if (0 === n.length) return this._loop;
+ if (1 === n.length) {
+ if ("boolean" != typeof n[0]) return !!(r = this._soundById(parseInt(n[0], 10))) && r._loop;
+ t = n[0], this._loop = t
+ } else 2 === n.length && (t = n[0], e = parseInt(n[1], 10));
+ for (var i = this._getSoundIds(e), o = 0; o < i.length; o++)(r = this._soundById(i[o])) && (r._loop = t, this._webAudio && r._node && r._node.bufferSource && (r._node.bufferSource.loop = t) && (r._node.bufferSource.loopStart = r._start || 0, r._node.bufferSource.loopEnd = r._stop));
+ return this
+ },
+ rate: function() {
+ var t, e, r, n = this,
+ i = arguments;
+ if (0 === i.length) e = n._sounds[0]._id;
+ else if (1 === i.length) {
+ 0 <= n._getSoundIds().indexOf(i[0]) ? e = parseInt(i[0], 10) : t = parseFloat(i[0])
+ } else 2 === i.length && (t = parseFloat(i[0]), e = parseInt(i[1], 10));
+ if ("number" != typeof t) return (r = n._soundById(e)) ? r._rate : n._rate;
+ if ("loaded" !== n._state || n._playLock) return n._queue.push({
+ event: "rate",
+ action: function() {
+ n.rate.apply(n, i)
+ }
+ }), n;
+ void 0 === e && (n._rate = t), e = n._getSoundIds(e);
+ for (var o = 0; o < e.length; o++)
+ if (r = n._soundById(e[o])) {
+ n.playing(e[o]) && (r._rateSeek = n.seek(e[o]), r._playStart = n._webAudio ? b.ctx.currentTime : r._playStart), r._rate = t, n._webAudio && r._node && r._node.bufferSource ? r._node.bufferSource.playbackRate.setValueAtTime(t, b.ctx.currentTime) : r._node && (r._node.playbackRate = t);
+ var a = n.seek(e[o]),
+ s = 1e3 * ((n._sprite[r._sprite][0] + n._sprite[r._sprite][1]) / 1e3 - a) / Math.abs(r._rate);
+ !n._endTimers[e[o]] && r._paused || (n._clearTimer(e[o]), n._endTimers[e[o]] = setTimeout(n._ended.bind(n, r), s)), n._emit("rate", r._id)
+ }
+ return n
+ },
+ seek: function() {
+ var t, e, r = this,
+ n = arguments;
+ if (0 === n.length) e = r._sounds[0]._id;
+ else if (1 === n.length) {
+ 0 <= r._getSoundIds().indexOf(n[0]) ? e = parseInt(n[0], 10) : r._sounds.length && (e = r._sounds[0]._id, t = parseFloat(n[0]))
+ } else 2 === n.length && (t = parseFloat(n[0]), e = parseInt(n[1], 10));
+ if (void 0 === e) return r;
+ if ("loaded" !== r._state || r._playLock) return r._queue.push({
+ event: "seek",
+ action: function() {
+ r.seek.apply(r, n)
+ }
+ }), r;
+ var i = r._soundById(e);
+ if (i) {
+ if (!("number" == typeof t && 0 <= t)) {
+ if (r._webAudio) {
+ var o = r.playing(e) ? b.ctx.currentTime - i._playStart : 0,
+ a = i._rateSeek ? i._rateSeek - i._seek : 0;
+ return i._seek + (a + o * Math.abs(i._rate))
+ }
+ return i._node.currentTime
+ }
+ var s = r.playing(e);
+ s && r.pause(e, !0), i._seek = t, i._ended = !1, r._clearTimer(e), r._webAudio || !i._node || isNaN(i._node.duration) || (i._node.currentTime = t);
+ var u = function() {
+ r._emit("seek", e), s && r.play(e, !0)
+ };
+ if (s && !r._webAudio) {
+ var h = function() {
+ r._playLock ? setTimeout(h, 0) : u()
+ };
+ setTimeout(h, 0)
+ } else u()
+ }
+ return r
+ },
+ playing: function(t) {
+ if ("number" == typeof t) {
+ var e = this._soundById(t);
+ return !!e && !e._paused
+ }
+ for (var r = 0; r < this._sounds.length; r++)
+ if (!this._sounds[r]._paused) return !0;
+ return !1
+ },
+ duration: function(t) {
+ var e = this._duration,
+ r = this._soundById(t);
+ return r && (e = this._sprite[r._sprite][1] / 1e3), e
+ },
+ state: function() {
+ return this._state
+ },
+ unload: function() {
+ for (var t = this, e = t._sounds, r = 0; r < e.length; r++) {
+ if (e[r]._paused || t.stop(e[r]._id), !t._webAudio) /MSIE |Trident\//.test(b._navigator && b._navigator.userAgent) || (e[r]._node.src = "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA"), e[r]._node.removeEventListener("error", e[r]._errorFn, !1), e[r]._node.removeEventListener(b._canPlayEvent, e[r]._loadFn, !1), b._releaseHtml5Audio(e[r]._node);
+ delete e[r]._node, t._clearTimer(e[r]._id)
+ }
+ var n = b._howls.indexOf(t);
+ 0 <= n && b._howls.splice(n, 1);
+ var i = !0;
+ for (r = 0; r < b._howls.length; r++)
+ if (b._howls[r]._src === t._src || 0 <= t._src.indexOf(b._howls[r]._src)) {
+ i = !1;
+ break
+ }
+ return a && i && delete a[t._src], b.noAudio = !1, t._state = "unloaded", t._sounds = [], t = null
+ },
+ on: function(t, e, r, n) {
+ var i = this["_on" + t];
+ return "function" == typeof e && i.push(n ? {
+ id: r,
+ fn: e,
+ once: n
+ } : {
+ id: r,
+ fn: e
+ }), this
+ },
+ off: function(t, e, r) {
+ var n = this["_on" + t],
+ i = 0;
+ if ("number" == typeof e && (r = e, e = null), e || r)
+ for (i = 0; i < n.length; i++) {
+ var o = r === n[i].id;
+ if (e === n[i].fn && o || !e && o) {
+ n.splice(i, 1);
+ break
+ }
+ } else if (t) this["_on" + t] = [];
+ else {
+ var a = Object.keys(this);
+ for (i = 0; i < a.length; i++) 0 === a[i].indexOf("_on") && Array.isArray(this[a[i]]) && (this[a[i]] = [])
+ }
+ return this
+ },
+ once: function(t, e, r) {
+ return this.on(t, e, r, 1), this
+ },
+ _emit: function(t, e, r) {
+ for (var n = this["_on" + t], i = n.length - 1; 0 <= i; i--) n[i].id && n[i].id !== e && "load" !== t || (setTimeout(function(t) {
+ t.call(this, e, r)
+ }.bind(this, n[i].fn), 0), n[i].once && this.off(t, n[i].fn, n[i].id));
+ return this._loadQueue(t), this
+ },
+ _loadQueue: function(t) {
+ if (0 < this._queue.length) {
+ var e = this._queue[0];
+ e.event === t && (this._queue.shift(), this._loadQueue()), t || e.action()
+ }
+ return this
+ },
+ _ended: function(t) {
+ var e = this,
+ r = t._sprite;
+ if (!e._webAudio && t._node && !t._node.paused && !t._node.ended && t._node.currentTime < t._stop) return setTimeout(e._ended.bind(e, t), 100), e;
+ var n = !(!t._loop && !e._sprite[r][2]);
+ if (e._emit("end", t._id), !e._webAudio && n && e.stop(t._id, !0).play(t._id), e._webAudio && n) {
+ e._emit("play", t._id), t._seek = t._start || 0, t._rateSeek = 0, t._playStart = b.ctx.currentTime;
+ var i = 1e3 * (t._stop - t._start) / Math.abs(t._rate);
+ e._endTimers[t._id] = setTimeout(e._ended.bind(e, t), i)
+ }
+ return e._webAudio && !n && (t._paused = !0, t._ended = !0, t._seek = t._start || 0, t._rateSeek = 0, e._clearTimer(t._id), e._cleanBuffer(t._node), b._autoSuspend()), e._webAudio || n || e.stop(t._id, !0), e
+ },
+ _clearTimer: function(t) {
+ if (this._endTimers[t]) {
+ if ("function" != typeof this._endTimers[t]) clearTimeout(this._endTimers[t]);
+ else {
+ var e = this._soundById(t);
+ e && e._node && e._node.removeEventListener("ended", this._endTimers[t], !1)
+ }
+ delete this._endTimers[t]
+ }
+ return this
+ },
+ _soundById: function(t) {
+ for (var e = 0; e < this._sounds.length; e++)
+ if (t === this._sounds[e]._id) return this._sounds[e];
+ return null
+ },
+ _inactiveSound: function() {
+ this._drain();
+ for (var t = 0; t < this._sounds.length; t++)
+ if (this._sounds[t]._ended) return this._sounds[t].reset();
+ return new o(this)
+ },
+ _drain: function() {
+ var t = this,
+ e = t._pool,
+ r = 0,
+ n = 0;
+ if (!(t._sounds.length < e)) {
+ for (n = 0; n < t._sounds.length; n++) t._sounds[n]._ended && r++;
+ for (n = t._sounds.length - 1; 0 <= n; n--) {
+ if (r <= e) return;
+ t._sounds[n]._ended && (t._webAudio && t._sounds[n]._node && t._sounds[n]._node.disconnect(0), t._sounds.splice(n, 1), r--)
+ }
+ }
+ },
+ _getSoundIds: function(t) {
+ if (void 0 !== t) return [t];
+ for (var e = [], r = 0; r < this._sounds.length; r++) e.push(this._sounds[r]._id);
+ return e
+ },
+ _refreshBuffer: function(t) {
+ return t._node.bufferSource = b.ctx.createBufferSource(), t._node.bufferSource.buffer = a[this._src], t._panner ? t._node.bufferSource.connect(t._panner) : t._node.bufferSource.connect(t._node), t._node.bufferSource.loop = t._loop, t._loop && (t._node.bufferSource.loopStart = t._start || 0, t._node.bufferSource.loopEnd = t._stop || 0), t._node.bufferSource.playbackRate.setValueAtTime(t._rate, b.ctx.currentTime), this
+ },
+ _cleanBuffer: function(t) {
+ var e = b._navigator && 0 <= b._navigator.vendor.indexOf("Apple");
+ if (b._scratchBuffer && t.bufferSource && (t.bufferSource.onended = null, t.bufferSource.disconnect(0), e)) try {
+ t.bufferSource.buffer = b._scratchBuffer
+ } catch (t) {}
+ return t.bufferSource = null, this
+ }
+ };
+ var o = function(t) {
+ this._parent = t, this.init()
+ };
+ o.prototype = {
+ init: function() {
+ var t = this,
+ e = t._parent;
+ return t._muted = e._muted, t._loop = e._loop, t._volume = e._volume, t._rate = e._rate, t._seek = 0, t._paused = !0, t._ended = !0, t._sprite = "__default", t._id = ++b._counter, e._sounds.push(t), t.create(), t
+ },
+ create: function() {
+ var t = this,
+ e = t._parent,
+ r = b._muted || t._muted || t._parent._muted ? 0 : t._volume;
+ return e._webAudio ? (t._node = void 0 === b.ctx.createGain ? b.ctx.createGainNode() : b.ctx.createGain(), t._node.gain.setValueAtTime(r, b.ctx.currentTime), t._node.paused = !0, t._node.connect(b.masterGain)) : (t._node = b._obtainHtml5Audio(), t._errorFn = t._errorListener.bind(t), t._node.addEventListener("error", t._errorFn, !1), t._loadFn = t._loadListener.bind(t), t._node.addEventListener(b._canPlayEvent, t._loadFn, !1), t._node.src = e._src, t._node.preload = "auto", t._node.volume = r * b.volume(), t._node.load()), t
+ },
+ reset: function() {
+ var t = this,
+ e = t._parent;
+ return t._muted = e._muted, t._loop = e._loop, t._volume = e._volume, t._rate = e._rate, t._seek = 0, t._rateSeek = 0, t._paused = !0, t._ended = !0, t._sprite = "__default", t._id = ++b._counter, t
+ },
+ _errorListener: function() {
+ this._parent._emit("loaderror", this._id, this._node.error ? this._node.error.code : 0), this._node.removeEventListener("error", this._errorFn, !1)
+ },
+ _loadListener: function() {
+ var t = this._parent;
+ t._duration = Math.ceil(10 * this._node.duration) / 10, 0 === Object.keys(t._sprite).length && (t._sprite = {
+ __default: [0, 1e3 * t._duration]
+ }), "loaded" !== t._state && (t._state = "loaded", t._emit("load"), t._loadQueue()), this._node.removeEventListener(b._canPlayEvent, this._loadFn, !1)
+ }
+ };
+ var a = {},
+ s = function(e) {
+ var t = e._src;
+ if (a[t]) return e._duration = a[t].duration, void c(e);
+ if (/^data:[^;]+;base64,/.test(t)) {
+ for (var r = atob(t.split(",")[1]), n = new Uint8Array(r.length), i = 0; i < r.length; ++i) n[i] = r.charCodeAt(i);
+ h(n.buffer, e)
+ } else {
+ var o = new XMLHttpRequest;
+ o.open("GET", t, !0), o.withCredentials = e._xhrWithCredentials, o.responseType = "arraybuffer", o.onload = function() {
+ var t = (o.status + "")[0];
+ "0" === t || "2" === t || "3" === t ? h(o.response, e) : e._emit("loaderror", null, "Failed loading audio file with status: " + o.status + ".")
+ }, o.onerror = function() {
+ e._webAudio && (e._html5 = !0, e._webAudio = !1, e._sounds = [], delete a[t], e.load())
+ }, u(o)
+ }
+ },
+ u = function(e) {
+ try {
+ e.send()
+ } catch (t) {
+ e.onerror()
+ }
+ },
+ h = function(t, e) {
+ var r = function() {
+ e._emit("loaderror", null, "Decoding audio data failed.")
+ },
+ n = function(t) {
+ t && 0 < e._sounds.length ? (a[e._src] = t, c(e, t)) : r()
+ };
+ "undefined" != typeof Promise && 1 === b.ctx.decodeAudioData.length ? b.ctx.decodeAudioData(t).then(n).catch(r) : b.ctx.decodeAudioData(t, n, r)
+ },
+ c = function(t, e) {
+ e && !t._duration && (t._duration = e.duration), 0 === Object.keys(t._sprite).length && (t._sprite = {
+ __default: [0, 1e3 * t._duration]
+ }), "loaded" !== t._state && (t._state = "loaded", t._emit("load"), t._loadQueue())
+ },
+ l = function() {
+ if (b.usingWebAudio) {
+ try {
+ "undefined" != typeof AudioContext ? b.ctx = new AudioContext : "undefined" != typeof webkitAudioContext ? b.ctx = new webkitAudioContext : b.usingWebAudio = !1
+ } catch (t) {
+ b.usingWebAudio = !1
+ }
+ b.ctx || (b.usingWebAudio = !1);
+ var t = /iP(hone|od|ad)/.test(b._navigator && b._navigator.platform),
+ e = b._navigator && b._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/),
+ r = e ? parseInt(e[1], 10) : null;
+ if (t && r && r < 9) {
+ var n = /safari/.test(b._navigator && b._navigator.userAgent.toLowerCase());
+ (b._navigator && b._navigator.standalone && !n || b._navigator && !b._navigator.standalone && !n) && (b.usingWebAudio = !1)
+ }
+ b.usingWebAudio && (b.masterGain = void 0 === b.ctx.createGain ? b.ctx.createGainNode() : b.ctx.createGain(), b.masterGain.gain.setValueAtTime(b._muted ? 0 : 1, b.ctx.currentTime), b.masterGain.connect(b.ctx.destination)), b._setup()
+ }
+ };
+ void 0 === (n = function() {
+ return {
+ Howler: b,
+ Howl: e
+ }
+ }.apply(f, [])) || (i.exports = n), f.Howler = b, f.Howl = e, "undefined" != typeof window ? (window.HowlerGlobal = t, window.Howler = b, window.Howl = e, window.Sound = o) : void 0 !== r && (r.HowlerGlobal = t, r.Howler = b, r.Howl = e, r.Sound = o)
+ }(),
+ function() {
+ "use strict";
+ var e, r, n;
+ HowlerGlobal.prototype._pos = [0, 0, 0], HowlerGlobal.prototype._orientation = [0, 0, -1, 0, 1, 0], HowlerGlobal.prototype.stereo = function(t) {
+ if (!this.ctx || !this.ctx.listener) return this;
+ for (var e = this._howls.length - 1; 0 <= e; e--) this._howls[e].stereo(t);
+ return this
+ }, HowlerGlobal.prototype.pos = function(t, e, r) {
+ var n = this;
+ return n.ctx && n.ctx.listener ? (e = "number" != typeof e ? n._pos[1] : e, r = "number" != typeof r ? n._pos[2] : r, "number" != typeof t ? n._pos : (n._pos = [t, e, r], void 0 !== n.ctx.listener.positionX ? (n.ctx.listener.positionX.setTargetAtTime(n._pos[0], Howler.ctx.currentTime, .1), n.ctx.listener.positionY.setTargetAtTime(n._pos[1], Howler.ctx.currentTime, .1), n.ctx.listener.positionZ.setTargetAtTime(n._pos[2], Howler.ctx.currentTime, .1)) : n.ctx.listener.setPosition(n._pos[0], n._pos[1], n._pos[2]), n)) : n
+ }, HowlerGlobal.prototype.orientation = function(t, e, r, n, i, o) {
+ var a = this;
+ if (!a.ctx || !a.ctx.listener) return a;
+ var s = a._orientation;
+ return e = "number" != typeof e ? s[1] : e, r = "number" != typeof r ? s[2] : r, n = "number" != typeof n ? s[3] : n, i = "number" != typeof i ? s[4] : i, o = "number" != typeof o ? s[5] : o, "number" != typeof t ? s : (a._orientation = [t, e, r, n, i, o], void 0 !== a.ctx.listener.forwardX ? (a.ctx.listener.forwardX.setTargetAtTime(t, Howler.ctx.currentTime, .1), a.ctx.listener.forwardY.setTargetAtTime(e, Howler.ctx.currentTime, .1), a.ctx.listener.forwardZ.setTargetAtTime(r, Howler.ctx.currentTime, .1), a.ctx.listener.upX.setTargetAtTime(t, Howler.ctx.currentTime, .1), a.ctx.listener.upY.setTargetAtTime(e, Howler.ctx.currentTime, .1), a.ctx.listener.upZ.setTargetAtTime(r, Howler.ctx.currentTime, .1)) : a.ctx.listener.setOrientation(t, e, r, n, i, o), a)
+ }, Howl.prototype.init = (e = Howl.prototype.init, function(t) {
+ return this._orientation = t.orientation || [1, 0, 0], this._stereo = t.stereo || null, this._pos = t.pos || null, this._pannerAttr = {
+ coneInnerAngle: void 0 !== t.coneInnerAngle ? t.coneInnerAngle : 360,
+ coneOuterAngle: void 0 !== t.coneOuterAngle ? t.coneOuterAngle : 360,
+ coneOuterGain: void 0 !== t.coneOuterGain ? t.coneOuterGain : 0,
+ distanceModel: void 0 !== t.distanceModel ? t.distanceModel : "inverse",
+ maxDistance: void 0 !== t.maxDistance ? t.maxDistance : 1e4,
+ panningModel: void 0 !== t.panningModel ? t.panningModel : "HRTF",
+ refDistance: void 0 !== t.refDistance ? t.refDistance : 1,
+ rolloffFactor: void 0 !== t.rolloffFactor ? t.rolloffFactor : 1
+ }, this._onstereo = t.onstereo ? [{
+ fn: t.onstereo
+ }] : [], this._onpos = t.onpos ? [{
+ fn: t.onpos
+ }] : [], this._onorientation = t.onorientation ? [{
+ fn: t.onorientation
+ }] : [], e.call(this, t)
+ }), Howl.prototype.stereo = function(t, e) {
+ var r = this;
+ if (!r._webAudio) return r;
+ if ("loaded" !== r._state) return r._queue.push({
+ event: "stereo",
+ action: function() {
+ r.stereo(t, e)
+ }
+ }), r;
+ var n = void 0 === Howler.ctx.createStereoPanner ? "spatial" : "stereo";
+ if (void 0 === e) {
+ if ("number" != typeof t) return r._stereo;
+ r._stereo = t, r._pos = [t, 0, 0]
+ }
+ for (var i = r._getSoundIds(e), o = 0; o < i.length; o++) {
+ var a = r._soundById(i[o]);
+ if (a) {
+ if ("number" != typeof t) return a._stereo;
+ a._stereo = t, a._pos = [t, 0, 0], a._node && (a._pannerAttr.panningModel = "equalpower", a._panner && a._panner.pan || h(a, n), "spatial" === n ? void 0 !== a._panner.positionX ? (a._panner.positionX.setValueAtTime(t, Howler.ctx.currentTime), a._panner.positionY.setValueAtTime(0, Howler.ctx.currentTime), a._panner.positionZ.setValueAtTime(0, Howler.ctx.currentTime)) : a._panner.setPosition(t, 0, 0) : a._panner.pan.setValueAtTime(t, Howler.ctx.currentTime)), r._emit("stereo", a._id)
+ }
+ }
+ return r
+ }, Howl.prototype.pos = function(t, e, r, n) {
+ var i = this;
+ if (!i._webAudio) return i;
+ if ("loaded" !== i._state) return i._queue.push({
+ event: "pos",
+ action: function() {
+ i.pos(t, e, r, n)
+ }
+ }), i;
+ if (e = "number" != typeof e ? 0 : e, r = "number" != typeof r ? -.5 : r, void 0 === n) {
+ if ("number" != typeof t) return i._pos;
+ i._pos = [t, e, r]
+ }
+ for (var o = i._getSoundIds(n), a = 0; a < o.length; a++) {
+ var s = i._soundById(o[a]);
+ if (s) {
+ if ("number" != typeof t) return s._pos;
+ s._pos = [t, e, r], s._node && (s._panner && !s._panner.pan || h(s, "spatial"), void 0 !== s._panner.positionX ? (s._panner.positionX.setValueAtTime(t, Howler.ctx.currentTime), s._panner.positionY.setValueAtTime(e, Howler.ctx.currentTime), s._panner.positionZ.setValueAtTime(r, Howler.ctx.currentTime)) : s._panner.setPosition(t, e, r)), i._emit("pos", s._id)
+ }
+ }
+ return i
+ }, Howl.prototype.orientation = function(t, e, r, n) {
+ var i = this;
+ if (!i._webAudio) return i;
+ if ("loaded" !== i._state) return i._queue.push({
+ event: "orientation",
+ action: function() {
+ i.orientation(t, e, r, n)
+ }
+ }), i;
+ if (e = "number" != typeof e ? i._orientation[1] : e, r = "number" != typeof r ? i._orientation[2] : r, void 0 === n) {
+ if ("number" != typeof t) return i._orientation;
+ i._orientation = [t, e, r]
+ }
+ for (var o = i._getSoundIds(n), a = 0; a < o.length; a++) {
+ var s = i._soundById(o[a]);
+ if (s) {
+ if ("number" != typeof t) return s._orientation;
+ s._orientation = [t, e, r], s._node && (s._panner || (s._pos || (s._pos = i._pos || [0, 0, -.5]), h(s, "spatial")), void 0 !== s._panner.orientationX ? (s._panner.orientationX.setValueAtTime(t, Howler.ctx.currentTime), s._panner.orientationY.setValueAtTime(e, Howler.ctx.currentTime), s._panner.orientationZ.setValueAtTime(r, Howler.ctx.currentTime)) : s._panner.setOrientation(t, e, r)), i._emit("orientation", s._id)
+ }
+ }
+ return i
+ }, Howl.prototype.pannerAttr = function() {
+ var t, e, r, n = this,
+ i = arguments;
+ if (!n._webAudio) return n;
+ if (0 === i.length) return n._pannerAttr;
+ if (1 === i.length) {
+ if ("object" != typeof i[0]) return (r = n._soundById(parseInt(i[0], 10))) ? r._pannerAttr : n._pannerAttr;
+ t = i[0], void 0 === e && (t.pannerAttr || (t.pannerAttr = {
+ coneInnerAngle: t.coneInnerAngle,
+ coneOuterAngle: t.coneOuterAngle,
+ coneOuterGain: t.coneOuterGain,
+ distanceModel: t.distanceModel,
+ maxDistance: t.maxDistance,
+ refDistance: t.refDistance,
+ rolloffFactor: t.rolloffFactor,
+ panningModel: t.panningModel
+ }), n._pannerAttr = {
+ coneInnerAngle: void 0 !== t.pannerAttr.coneInnerAngle ? t.pannerAttr.coneInnerAngle : n._coneInnerAngle,
+ coneOuterAngle: void 0 !== t.pannerAttr.coneOuterAngle ? t.pannerAttr.coneOuterAngle : n._coneOuterAngle,
+ coneOuterGain: void 0 !== t.pannerAttr.coneOuterGain ? t.pannerAttr.coneOuterGain : n._coneOuterGain,
+ distanceModel: void 0 !== t.pannerAttr.distanceModel ? t.pannerAttr.distanceModel : n._distanceModel,
+ maxDistance: void 0 !== t.pannerAttr.maxDistance ? t.pannerAttr.maxDistance : n._maxDistance,
+ refDistance: void 0 !== t.pannerAttr.refDistance ? t.pannerAttr.refDistance : n._refDistance,
+ rolloffFactor: void 0 !== t.pannerAttr.rolloffFactor ? t.pannerAttr.rolloffFactor : n._rolloffFactor,
+ panningModel: void 0 !== t.pannerAttr.panningModel ? t.pannerAttr.panningModel : n._panningModel
+ })
+ } else 2 === i.length && (t = i[0], e = parseInt(i[1], 10));
+ for (var o = n._getSoundIds(e), a = 0; a < o.length; a++)
+ if (r = n._soundById(o[a])) {
+ var s = r._pannerAttr;
+ s = {
+ coneInnerAngle: void 0 !== t.coneInnerAngle ? t.coneInnerAngle : s.coneInnerAngle,
+ coneOuterAngle: void 0 !== t.coneOuterAngle ? t.coneOuterAngle : s.coneOuterAngle,
+ coneOuterGain: void 0 !== t.coneOuterGain ? t.coneOuterGain : s.coneOuterGain,
+ distanceModel: void 0 !== t.distanceModel ? t.distanceModel : s.distanceModel,
+ maxDistance: void 0 !== t.maxDistance ? t.maxDistance : s.maxDistance,
+ refDistance: void 0 !== t.refDistance ? t.refDistance : s.refDistance,
+ rolloffFactor: void 0 !== t.rolloffFactor ? t.rolloffFactor : s.rolloffFactor,
+ panningModel: void 0 !== t.panningModel ? t.panningModel : s.panningModel
+ };
+ var u = r._panner;
+ u ? (u.coneInnerAngle = s.coneInnerAngle, u.coneOuterAngle = s.coneOuterAngle, u.coneOuterGain = s.coneOuterGain, u.distanceModel = s.distanceModel, u.maxDistance = s.maxDistance, u.refDistance = s.refDistance, u.rolloffFactor = s.rolloffFactor, u.panningModel = s.panningModel) : (r._pos || (r._pos = n._pos || [0, 0, -.5]), h(r, "spatial"))
+ }
+ return n
+ }, Sound.prototype.init = (r = Sound.prototype.init, function() {
+ var t = this,
+ e = t._parent;
+ t._orientation = e._orientation, t._stereo = e._stereo, t._pos = e._pos, t._pannerAttr = e._pannerAttr, r.call(this), t._stereo ? e.stereo(t._stereo) : t._pos && e.pos(t._pos[0], t._pos[1], t._pos[2], t._id)
+ }), Sound.prototype.reset = (n = Sound.prototype.reset, function() {
+ var t = this,
+ e = t._parent;
+ return t._orientation = e._orientation, t._stereo = e._stereo, t._pos = e._pos, t._pannerAttr = e._pannerAttr, t._stereo ? e.stereo(t._stereo) : t._pos ? e.pos(t._pos[0], t._pos[1], t._pos[2], t._id) : t._panner && (t._panner.disconnect(0), t._panner = void 0, e._refreshBuffer(t)), n.call(this)
+ });
+ var h = function(t, e) {
+ "spatial" === (e = e || "spatial") ? (t._panner = Howler.ctx.createPanner(), t._panner.coneInnerAngle = t._pannerAttr.coneInnerAngle, t._panner.coneOuterAngle = t._pannerAttr.coneOuterAngle, t._panner.coneOuterGain = t._pannerAttr.coneOuterGain, t._panner.distanceModel = t._pannerAttr.distanceModel, t._panner.maxDistance = t._pannerAttr.maxDistance, t._panner.refDistance = t._pannerAttr.refDistance, t._panner.rolloffFactor = t._pannerAttr.rolloffFactor, t._panner.panningModel = t._pannerAttr.panningModel, void 0 !== t._panner.positionX ? (t._panner.positionX.setValueAtTime(t._pos[0], Howler.ctx.currentTime), t._panner.positionY.setValueAtTime(t._pos[1], Howler.ctx.currentTime), t._panner.positionZ.setValueAtTime(t._pos[2], Howler.ctx.currentTime)) : t._panner.setPosition(t._pos[0], t._pos[1], t._pos[2]), void 0 !== t._panner.orientationX ? (t._panner.orientationX.setValueAtTime(t._orientation[0], Howler.ctx.currentTime), t._panner.orientationY.setValueAtTime(t._orientation[1], Howler.ctx.currentTime), t._panner.orientationZ.setValueAtTime(t._orientation[2], Howler.ctx.currentTime)) : t._panner.setOrientation(t._orientation[0], t._orientation[1], t._orientation[2])) : (t._panner = Howler.ctx.createStereoPanner(), t._panner.pan.setValueAtTime(t._stereo, Howler.ctx.currentTime)), t._panner.connect(t._node), t._paused || t._parent.pause(t._id, !0).play(t._id, !0)
+ }
+ }()
+ }).call(this, t(42))
+ }, function(t, e) {
+ t.exports = function(t) {
+ if ("function" != typeof t) throw TypeError(t + " is not a function!");
+ return t
+ }
+ }, function(t, e, r) {
+ var n = r(20),
+ i = r(51);
+ t.exports = r(19) ? function(t, e, r) {
+ return n.f(t, e, i(1, r))
+ } : function(t, e, r) {
+ return t[e] = r, t
+ }
+ }, function(t, e, r) {
+ var o = r(9),
+ a = r(25),
+ s = r(28),
+ u = r(52)("src"),
+ n = "toString",
+ i = Function[n],
+ h = ("" + i).split(n);
+ r(32).inspectSource = function(t) {
+ return i.call(t)
+ }, (t.exports = function(t, e, r, n) {
+ var i = "function" == typeof r;
+ i && (s(r, "name") || a(r, "name", e)), t[e] !== r && (i && (s(r, u) || a(r, u, t[e] ? "" + t[e] : h.join(String(e)))), t === o ? t[e] = r : n ? t[e] ? t[e] = r : a(t, e, r) : (delete t[e], a(t, e, r)))
+ })(Function.prototype, n, function() {
+ return "function" == typeof this && this[u] || i.call(this)
+ })
+ }, function(t, e, r) {
+ var n = r(1),
+ i = r(10),
+ a = r(39),
+ s = /"/g,
+ o = function(t, e, r, n) {
+ var i = String(a(t)),
+ o = "<" + e;
+ return "" !== r && (o += " " + r + '="' + String(n).replace(s, """) + '"'), o + ">" + i + "" + e + ">"
+ };
+ t.exports = function(e, t) {
+ var r = {};
+ r[e] = t(o), n(n.P + n.F * i(function() {
+ var t = "" [e]('"');
+ return t !== t.toLowerCase() || 3 < t.split('"').length
+ }), "String", r)
+ }
+ }, function(t, e) {
+ var r = {}.hasOwnProperty;
+ t.exports = function(t, e) {
+ return r.call(t, e)
+ }
+ }, function(t, e, r) {
+ var n = r(69),
+ i = r(39);
+ t.exports = function(t) {
+ return n(i(t))
+ }
+ }, function(t, e, r) {
+ var n = r(70),
+ i = r(51),
+ o = r(29),
+ a = r(38),
+ s = r(28),
+ u = r(134),
+ h = Object.getOwnPropertyDescriptor;
+ e.f = r(19) ? h : function(t, e) {
+ if (t = o(t), e = a(e, !0), u) try {
+ return h(t, e)
+ } catch (t) {}
+ if (s(t, e)) return i(!n.f.call(t, e), t[e])
+ }
+ }, function(t, e, r) {
+ var n = r(28),
+ i = r(22),
+ o = r(100)("IE_PROTO"),
+ a = Object.prototype;
+ t.exports = Object.getPrototypeOf || function(t) {
+ return t = i(t), n(t, o) ? t[o] : "function" == typeof t.constructor && t instanceof t.constructor ? t.constructor.prototype : t instanceof Object ? a : null
+ }
+ }, function(t, e) {
+ var r = t.exports = {
+ version: "2.6.3"
+ };
+ "number" == typeof __e && (__e = r)
+ }, function(t, e, r) {
+ var o = r(24);
+ t.exports = function(n, i, t) {
+ if (o(n), void 0 === i) return n;
+ switch (t) {
+ case 1:
+ return function(t) {
+ return n.call(i, t)
+ };
+ case 2:
+ return function(t, e) {
+ return n.call(i, t, e)
+ };
+ case 3:
+ return function(t, e, r) {
+ return n.call(i, t, e, r)
+ }
+ }
+ return function() {
+ return n.apply(i, arguments)
+ }
+ }
+ }, function(t, e) {
+ var r = {}.toString;
+ t.exports = function(t) {
+ return r.call(t).slice(8, -1)
+ }
+ }, function(t, e) {
+ var r = Math.ceil,
+ n = Math.floor;
+ t.exports = function(t) {
+ return isNaN(t = +t) ? 0 : (0 < t ? n : r)(t)
+ }
+ }, function(t, e, r) {
+ "use strict";
+ var n = r(10);
+ t.exports = function(t, e) {
+ return !!t && n(function() {
+ e ? t.call(null, function() {}, 1) : t.call(null)
+ })
+ }
+ }, function(t, e, r) {
+ "use strict";
+ e.__esModule = !0;
+ var n = function() {
+ function defineProperties(t, e) {
+ for (var r = 0; r < e.length; r++) {
+ var n = e[r];
+ n.enumerable = n.enumerable || !1, n.configurable = !0, "value" in n && (n.writable = !0), Object.defineProperty(t, n.key, n)
+ }
+ }
+ return function(t, e, r) {
+ return e && defineProperties(t.prototype, e), r && defineProperties(t, r), t
+ }
+ }(),
+ u = function(t) {
+ {
+ if (t && t.__esModule) return t;
+ var e = {};
+ if (null != t)
+ for (var r in t) Object.prototype.hasOwnProperty.call(t, r) && (e[r] = t[r]);
+ return e.default = t, e
+ }
+ }(r(0)),
+ h = r(4);
+
+ function filterEmptyLine(t) {
+ return "" !== t
+ }
+ var c = {
+ uniformData: {
+ id: -1
+ }
+ },
+ l = 0,
+ i = {},
+ f = {},
+ o = function(s) {
+ function BaseMaterial() {
+ var t = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : {},
+ e = arguments[1],
+ r = arguments[2],
+ n = arguments[3],
+ i = 4 < arguments.length && void 0 !== arguments[4] ? arguments[4] : "base";
+ ! function(t, e) {
+ if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
+ }(this, BaseMaterial);
+ var o = {
+ uShininess: t.shininess || 32,
+ uOpacity: void 0 === t.opacity ? 1 : t.opacity,
+ uSpecular: new Float32Array([0, 0, 0]),
+ uColor: new Float32Array([1, 1, 1]),
+ normal: h.mat3.create()
+ },
+ a = function(t, e) {
+ if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return !e || "object" != typeof e && "function" != typeof e ? t : e
+ }(this, s.call(this, c, o));
+ return a.type = i, a.name = t.name || a.type + "-shader", a.options = {}, a.needsUpdate = !0, a.id = l++, a.skinning = !!t.skinning, a.skinning && (o.bones = new Float32Array(960)), a.specularColor = t.specular || 0, a.color = t.color || 16777215, a.instancing = !!t.instancing, a.emissive = !1, a.instancing && (a.name += "-instanced"), t.uniforms && Object.assign(o, t.uniforms), t.map && (o.uMap = t.map, o.uMapFrame = new u.Rectangle(0, 0, 1, 1)), t.enviromentMap && (o.uEnviromentMap = t.enviromentMap), t.shininessMap && (o.uShininessMap = t.shininessMap), t.occlusionMap && (o.uOcclusionMap = t.occlusionMap), a.emissive = !!(t.emissive || t.emissiveColor || t.emissiveMap), a.emissive && (void 0 !== t.emissive && (o.uEmissive = t.emissive), t.emissiveColor && (o.uEmissiveColor = new Float32Array([1, 1, 1]), a.emissiveColor = t.emissiveColor), t.emissiveMap && (o.uEmissiveMap = t.emissiveMap)), a.vertexSource = e, a.fragmentSource = r, a.fragmentInjection = t.fragment || {}, a.vertexInjection = t.vertex || {}, a.sig = a.getSignature(t), a.program = c, a.rebuildId = 0, a.defines = n || [], a
+ }
+ return function(t, e) {
+ if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e);
+ t.prototype = Object.create(e && e.prototype, {
+ constructor: {
+ value: t,
+ enumerable: !1,
+ writable: !0,
+ configurable: !0
+ }
+ }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e)
+ }(BaseMaterial, s), BaseMaterial.prototype.injectLights = function(t, e) {
+ var r = f[e.sig];
+ if (!r) {
+ var n = [],
+ i = [];
+ e.lights.forEach(function(t) {
+ var e = t.light._lightId;
+ 0 === t.light.type ? (n.push("uniform vec3 uLightColor" + e + ";"), n.push("uniform vec3 uLightDirection" + e + ";"), i.push("\n\n attenuation = 1.;\n\n attenuation *= diffuseLighting(worldNormal,uLightDirection" + e + ");\n\n lighting += attenuation * uLightColor" + e + ";\n \n attenuation *= specularLighting(worldNormal, eyeToSurfaceDir,uLightDirection" + e + ");\n\n specular += attenuation * uSpecular * uLightColor" + e + ";\n \n ")) : 1 === t.light.type ? (n.push("uniform vec3 uLightColor" + e + ";"), n.push("uniform vec3 uLightDirection" + e + ";"), n.push("uniform vec3 uLightPosition" + e + ";"), n.push("uniform float uLightDistance" + e + ";"), i.push("\n \n lightDirection = vPosition - uLightPosition" + e + ";\n \n lightDirectionNormal = normalize(lightDirection);\n \n distancFromLight = length(lightDirection);\n \n attenuation = pow( saturate(-distancFromLight / uLightDistance" + e + " + 1.0) , 1. );\n \n if(attenuation > 0.0001)\n {\n attenuation *= diffuseLighting(worldNormal,lightDirectionNormal);\n\n lighting += attenuation * uLightColor" + e + ";\n \n attenuation *= specularLighting(worldNormal,eyeToSurfaceDir,lightDirectionNormal);\n\n specular += attenuation * uSpecular * uLightColor" + e + ";\n \n }")) : 2 === t.light.type && (n.push("uniform vec3 uLightColor" + e + ";"), n.push("uniform vec3 uLightDirection" + e + ";"), n.push("uniform vec3 uLightPosition" + e + ";"), n.push("uniform float uLightDistance" + e + ";"), i.push("\n \n lightDirection = uLightPosition" + e + " - vPosition;\n float dist = length(lightDirection);\n \n L = normalize(lightDirection);\n\n float attenuation = pow( saturate(-dist / uLightDistance" + e + " + 1.0) , 1. );\n \n float dotFromDirection = dot(L, -uLightDirection" + e + ");\n \n float limit = cos(30. * (3.14/180.) );\n\n if(dotFromDirection >= 0.000001)\n {\n if(attenuation > 0.001)\n {\n lighting += diffuseLighting(N,L,uLightColor" + e + ") * attenuation;\n lighting += specularLighting(N,L,V) * attenuation;\n lighting *= reflection;\n \n }\n }"))
+ }), f[e.sig] = r = {
+ uniforms: n.join("\n"),
+ code: i.join("\n")
+ }
+ }
+ var o = t.fragment,
+ a = t.vertex;
+ o = (o = o.replace(/#HOOK_LIGHT_UNIFROMS/g, r.uniforms)).replace(/#HOOK_LIGHT/g, r.code), a = (a = a.replace(/#HOOK_LIGHT_UNIFROMS/g, r.uniforms)).replace(/#HOOK_LIGHT/g, r.code), t.fragment = o, t.vertex = a
+ }, BaseMaterial.prototype.injectDefines = function(t, e) {
+ var r = this.uniforms,
+ n = [r.uColor ? "#define COLOR" : "", this.skinning ? "#define SKINNING" : "", r.uMap ? "#define MAP" : "", r.uOcclusionMap ? "#define OCCLUSION_MAP" : "", r.uShininess ? "#define SHININESS_FLOAT" : "", r.uShininessMap ? "#define SHININESS_MAP" : "", this.emissive ? "#define EMISSIVE" : "", void 0 !== r.uEmissive ? "#define EMISSIVE_FLOAT" : "", r.uEmissiveColor ? "#define EMISSIVE_COLOR" : "", r.uEmissiveMap ? "#define EMISSIVE_MAP" : "", r.uEnviromentMap ? "#define ENV_REFLECT" : "", this.instancing ? "#define INSTANCING" : "", e ? "#define FOG" : ""].concat(this.defines).filter(filterEmptyLine).join("\n");
+ t.vertex = n + "\n" + t.vertex, t.fragment = n + "\n" + t.fragment
+ }, BaseMaterial.prototype.injectHooks = function(t) {
+ var e = this.vertexInjection,
+ r = t.vertex;
+ r = (r = (r = r.replace(/#HOOK_VERTEX_START/g, e.start || "")).replace(/#HOOK_VERTEX_MAIN/g, e.main || "")).replace(/#HOOK_VERTEX_END/g, e.end || "");
+ var n = this.fragmentInjection,
+ i = t.fragment;
+ i = (i = (i = i.replace(/#HOOK_FRAGMENT_START/g, n.start || "")).replace(/#HOOK_FRAGMENT_MAIN/g, n.main || "")).replace(/#HOOK_FRAGMENT_END/g, n.end || ""), t.fragment = i, t.vertex = r
+ }, BaseMaterial.prototype.build = function(t, e) {
+ if (i[this.sig + t.sig]) this.program = i[this.sig + t.sig];
+ else {
+ var r = {
+ vertex: this.vertexSource,
+ fragment: this.fragmentSource
+ };
+ this.injectDefines(r, e), this.injectHooks(r), this.injectLights(r, t), this.program = u.Program.from(r.vertex, r.fragment, this.name), i[this.sig + t.sig] = this.program
+ }
+ }, BaseMaterial.prototype.getSignature = function(t) {
+ var e = [this.type];
+ for (var r in t) e.push(r);
+ return e.sort(), t.vertex && e.push(t.vertex.start || "", t.vertex.main || "", t.vertex.end || ""), t.fragment && e.push(t.fragment.start || "", t.fragment.main || "", t.fragment.end || ""), e.join("-")
+ }, n(BaseMaterial, [{
+ key: "opacity",
+ set: function(t) {
+ this.uniforms.uOpacity = t
+ },
+ get: function() {
+ return this.uniforms.uOpacity
+ }
+ }, {
+ key: "map",
+ set: function(t) {
+ this.uniforms.uMap = t
+ },
+ get: function() {
+ return this.uniforms.uMap
+ }
+ }, {
+ key: "occlusionMap",
+ set: function(t) {
+ this.uniforms.uOcclusionMap = t
+ },
+ get: function() {
+ return this.uniforms.uOcclusionMap
+ }
+ }, {
+ key: "shininessMap",
+ set: function(t) {
+ this.uniforms.uShininessMap = t
+ },
+ get: function() {
+ return this.uniforms.uShininessMap
+ }
+ }, {
+ key: "shininess",
+ set: function(t) {
+ this.uniforms.uShininess = t
+ },
+ get: function() {
+ return this.uniforms.uShininess
+ }
+ }, {
+ key: "emissive",
+ set: function(t) {
+ this.uniforms.uEmissive = t
+ },
+ get: function() {
+ return this.uniforms.uEmissive
+ }
+ }, {
+ key: "emissiveMap",
+ set: function(t) {
+ this.uniforms.uEmissiveMap = t
+ },
+ get: function() {
+ return this.uniforms.uEmissiveMap
+ }
+ }, {
+ key: "enviromentMap",
+ set: function(t) {
+ this.uniforms.uEnviromentMap = t
+ },
+ get: function() {
+ return this.uniforms.uEnviromentMap
+ }
+ }, {
+ key: "emissiveColor",
+ set: function(t) {
+ this._hexEmissiveColor = t, u.utils.hex2rgb(t, this.uniforms.uEmissiveColor)
+ },
+ get: function() {
+ return this._hexEmissiveColor
+ }
+ }, {
+ key: "color",
+ set: function(t) {
+ this._hexColor = t, u.utils.hex2rgb(t, this.uniforms.uColor)
+ },
+ get: function() {
+ return this._hexColor
+ }
+ }, {
+ key: "specularColor",
+ set: function(t) {
+ this._hexSpecularColor = t, u.utils.hex2rgb(t, this.uniforms.uSpecular)
+ },
+ get: function() {
+ return this._hexSpecularColor
+ }
+ }]), BaseMaterial
+ }(u.Shader);
+ e.default = o
+ }, function(t, e, r) {
+ var i = r(11);
+ t.exports = function(t, e) {
+ if (!i(t)) return t;
+ var r, n;
+ if (e && "function" == typeof(r = t.toString) && !i(n = r.call(t))) return n;
+ if ("function" == typeof(r = t.valueOf) && !i(n = r.call(t))) return n;
+ if (!e && "function" == typeof(r = t.toString) && !i(n = r.call(t))) return n;
+ throw TypeError("Can't convert object to primitive value")
+ }
+ }, function(t, e) {
+ t.exports = function(t) {
+ if (null == t) throw TypeError("Can't call method on " + t);
+ return t
+ }
+ }, function(t, e, r) {
+ var i = r(1),
+ o = r(32),
+ a = r(10);
+ t.exports = function(t, e) {
+ var r = (o.Object || {})[t] || Object[t],
+ n = {};
+ n[t] = e(r), i(i.S + i.F * a(function() {
+ r(1)
+ }), "Object", n)
+ }
+ }, function(t, e, r) {
+ var _ = r(33),
+ b = r(69),
+ x = r(22),
+ w = r(17),
+ n = r(116);
+ t.exports = function(l, t) {
+ var f = 1 == l,
+ d = 2 == l,
+ p = 3 == l,
+ m = 4 == l,
+ v = 6 == l,
+ g = 5 == l || v,
+ y = t || n;
+ return function(t, e, r) {
+ for (var n, i, o = x(t), a = b(o), s = _(e, r, 3), u = w(a.length), h = 0, c = f ? y(t, u) : d ? y(t, 0) : void 0; h < u; h++)
+ if ((g || h in a) && (i = s(n = a[h], h, o), l))
+ if (f) c[h] = i;
+ else if (i) switch (l) {
+ case 3:
+ return !0;
+ case 5:
+ return n;
+ case 6:
+ return h;
+ case 2:
+ c.push(n)
+ } else if (m) return !1;
+ return v ? -1 : p || m ? m : c
+ }
+ }
+ }, function(t, e) {
+ var r;
+ r = function() {
+ return this
+ }();
+ try {
+ r = r || new Function("return this")()
+ } catch (t) {
+ "object" == typeof window && (r = window)
+ }
+ t.exports = r
+ }, function(t, e, r) {
+ "use strict";
+ if (r(19)) {
+ var g = r(49),
+ y = r(9),
+ _ = r(10),
+ b = r(1),
+ x = r(85),
+ n = r(124),
+ f = r(33),
+ w = r(58),
+ i = r(51),
+ T = r(25),
+ o = r(60),
+ a = r(35),
+ S = r(17),
+ M = r(162),
+ s = r(54),
+ u = r(38),
+ h = r(28),
+ E = r(62),
+ A = r(11),
+ d = r(22),
+ p = r(113),
+ P = r(55),
+ I = r(31),
+ O = r(56).f,
+ m = r(115),
+ c = r(52),
+ l = r(15),
+ v = r(41),
+ C = r(75),
+ R = r(72),
+ D = r(118),
+ F = r(64),
+ k = r(80),
+ L = r(57),
+ N = r(117),
+ B = r(151),
+ U = r(20),
+ G = r(30),
+ j = U.f,
+ z = G.f,
+ X = y.RangeError,
+ V = y.TypeError,
+ q = y.Uint8Array,
+ H = "ArrayBuffer",
+ W = "Shared" + H,
+ Y = "BYTES_PER_ELEMENT",
+ K = "prototype",
+ Z = Array[K],
+ Q = n.ArrayBuffer,
+ J = n.DataView,
+ $ = v(0),
+ tt = v(2),
+ et = v(3),
+ rt = v(4),
+ nt = v(5),
+ it = v(6),
+ ot = C(!0),
+ at = C(!1),
+ st = D.values,
+ ut = D.keys,
+ ht = D.entries,
+ ct = Z.lastIndexOf,
+ lt = Z.reduce,
+ ft = Z.reduceRight,
+ dt = Z.join,
+ pt = Z.sort,
+ mt = Z.slice,
+ vt = Z.toString,
+ gt = Z.toLocaleString,
+ yt = l("iterator"),
+ _t = l("toStringTag"),
+ bt = c("typed_constructor"),
+ xt = c("def_constructor"),
+ wt = x.CONSTR,
+ Tt = x.TYPED,
+ St = x.VIEW,
+ Mt = "Wrong length!",
+ Et = v(1, function(t, e) {
+ return Ct(R(t, t[xt]), e)
+ }),
+ At = _(function() {
+ return 1 === new q(new Uint16Array([1]).buffer)[0]
+ }),
+ Pt = !!q && !!q[K].set && _(function() {
+ new q(1).set({})
+ }),
+ It = function(t, e) {
+ var r = a(t);
+ if (r < 0 || r % e) throw X("Wrong offset!");
+ return r
+ },
+ Ot = function(t) {
+ if (A(t) && Tt in t) return t;
+ throw V(t + " is not a typed array!")
+ },
+ Ct = function(t, e) {
+ if (!(A(t) && bt in t)) throw V("It is not a typed array constructor!");
+ return new t(e)
+ },
+ Rt = function(t, e) {
+ return Dt(R(t, t[xt]), e)
+ },
+ Dt = function(t, e) {
+ for (var r = 0, n = e.length, i = Ct(t, n); r < n;) i[r] = e[r++];
+ return i
+ },
+ Ft = function(t, e, r) {
+ j(t, e, {
+ get: function() {
+ return this._d[r]
+ }
+ })
+ },
+ kt = function(t) {
+ var e, r, n, i, o, a, s = d(t),
+ u = arguments.length,
+ h = 1 < u ? arguments[1] : void 0,
+ c = void 0 !== h,
+ l = m(s);
+ if (null != l && !p(l)) {
+ for (a = l.call(s), n = [], e = 0; !(o = a.next()).done; e++) n.push(o.value);
+ s = n
+ }
+ for (c && 2 < u && (h = f(h, arguments[2], 2)), e = 0, r = S(s.length), i = Ct(this, r); e < r; e++) i[e] = c ? h(s[e], e) : s[e];
+ return i
+ },
+ Lt = function() {
+ for (var t = 0, e = arguments.length, r = Ct(this, e); t < e;) r[t] = arguments[t++];
+ return r
+ },
+ Nt = !!q && _(function() {
+ gt.call(new q(1))
+ }),
+ Bt = function() {
+ return gt.apply(Nt ? mt.call(Ot(this)) : Ot(this), arguments)
+ },
+ Ut = {
+ copyWithin: function(t, e) {
+ return B.call(Ot(this), t, e, 2 < arguments.length ? arguments[2] : void 0)
+ },
+ every: function(t) {
+ return rt(Ot(this), t, 1 < arguments.length ? arguments[1] : void 0)
+ },
+ fill: function(t) {
+ return N.apply(Ot(this), arguments)
+ },
+ filter: function(t) {
+ return Rt(this, tt(Ot(this), t, 1 < arguments.length ? arguments[1] : void 0))
+ },
+ find: function(t) {
+ return nt(Ot(this), t, 1 < arguments.length ? arguments[1] : void 0)
+ },
+ findIndex: function(t) {
+ return it(Ot(this), t, 1 < arguments.length ? arguments[1] : void 0)
+ },
+ forEach: function(t) {
+ $(Ot(this), t, 1 < arguments.length ? arguments[1] : void 0)
+ },
+ indexOf: function(t) {
+ return at(Ot(this), t, 1 < arguments.length ? arguments[1] : void 0)
+ },
+ includes: function(t) {
+ return ot(Ot(this), t, 1 < arguments.length ? arguments[1] : void 0)
+ },
+ join: function(t) {
+ return dt.apply(Ot(this), arguments)
+ },
+ lastIndexOf: function(t) {
+ return ct.apply(Ot(this), arguments)
+ },
+ map: function(t) {
+ return Et(Ot(this), t, 1 < arguments.length ? arguments[1] : void 0)
+ },
+ reduce: function(t) {
+ return lt.apply(Ot(this), arguments)
+ },
+ reduceRight: function(t) {
+ return ft.apply(Ot(this), arguments)
+ },
+ reverse: function() {
+ for (var t, e = Ot(this).length, r = Math.floor(e / 2), n = 0; n < r;) t = this[n], this[n++] = this[--e], this[e] = t;
+ return this
+ },
+ some: function(t) {
+ return et(Ot(this), t, 1 < arguments.length ? arguments[1] : void 0)
+ },
+ sort: function(t) {
+ return pt.call(Ot(this), t)
+ },
+ subarray: function(t, e) {
+ var r = Ot(this),
+ n = r.length,
+ i = s(t, n);
+ return new(R(r, r[xt]))(r.buffer, r.byteOffset + i * r.BYTES_PER_ELEMENT, S((void 0 === e ? n : s(e, n)) - i))
+ }
+ },
+ Gt = function(t, e) {
+ return Rt(this, mt.call(Ot(this), t, e))
+ },
+ jt = function(t) {
+ Ot(this);
+ var e = It(arguments[1], 1),
+ r = this.length,
+ n = d(t),
+ i = S(n.length),
+ o = 0;
+ if (r < i + e) throw X(Mt);
+ for (; o < i;) this[e + o] = n[o++]
+ },
+ zt = {
+ entries: function() {
+ return ht.call(Ot(this))
+ },
+ keys: function() {
+ return ut.call(Ot(this))
+ },
+ values: function() {
+ return st.call(Ot(this))
+ }
+ },
+ Xt = function(t, e) {
+ return A(t) && t[Tt] && "symbol" != typeof e && e in t && String(+e) == String(e)
+ },
+ Vt = function(t, e) {
+ return Xt(t, e = u(e, !0)) ? i(2, t[e]) : z(t, e)
+ },
+ qt = function(t, e, r) {
+ return !(Xt(t, e = u(e, !0)) && A(r) && h(r, "value")) || h(r, "get") || h(r, "set") || r.configurable || h(r, "writable") && !r.writable || h(r, "enumerable") && !r.enumerable ? j(t, e, r) : (t[e] = r.value, t)
+ };
+ wt || (G.f = Vt, U.f = qt), b(b.S + b.F * !wt, "Object", {
+ getOwnPropertyDescriptor: Vt,
+ defineProperty: qt
+ }), _(function() {
+ vt.call({})
+ }) && (vt = gt = function() {
+ return dt.call(this)
+ });
+ var Ht = o({}, Ut);
+ o(Ht, zt), T(Ht, yt, zt.values), o(Ht, {
+ slice: Gt,
+ set: jt,
+ constructor: function() {},
+ toString: vt,
+ toLocaleString: Bt
+ }), Ft(Ht, "buffer", "b"), Ft(Ht, "byteOffset", "o"), Ft(Ht, "byteLength", "l"), Ft(Ht, "length", "e"), j(Ht, _t, {
+ get: function() {
+ return this[Tt]
+ }
+ }), t.exports = function(t, l, e, o) {
+ var f = t + ((o = !!o) ? "Clamped" : "") + "Array",
+ r = "get" + t,
+ a = "set" + t,
+ d = y[f],
+ s = d || {},
+ n = d && I(d),
+ i = !d || !x.ABV,
+ u = {},
+ h = d && d[K],
+ p = function(t, i) {
+ j(t, i, {
+ get: function() {
+ return t = i, (e = this._d).v[r](t * l + e.o, At);
+ var t, e
+ },
+ set: function(t) {
+ return e = i, r = t, n = this._d, o && (r = (r = Math.round(r)) < 0 ? 0 : 255 < r ? 255 : 255 & r), void n.v[a](e * l + n.o, r, At);
+ var e, r, n
+ },
+ enumerable: !0
+ })
+ };
+ i ? (d = e(function(t, e, r, n) {
+ w(t, d, f, "_d");
+ var i, o, a, s, u = 0,
+ h = 0;
+ if (A(e)) {
+ if (!(e instanceof Q || (s = E(e)) == H || s == W)) return Tt in e ? Dt(d, e) : kt.call(d, e);
+ i = e, h = It(r, l);
+ var c = e.byteLength;
+ if (void 0 === n) {
+ if (c % l) throw X(Mt);
+ if ((o = c - h) < 0) throw X(Mt)
+ } else if (c < (o = S(n) * l) + h) throw X(Mt);
+ a = o / l
+ } else a = M(e), i = new Q(o = a * l);
+ for (T(t, "_d", {
+ b: i,
+ o: h,
+ l: o,
+ e: a,
+ v: new J(i)
+ }); u < a;) p(t, u++)
+ }), h = d[K] = P(Ht), T(h, "constructor", d)) : _(function() {
+ d(1)
+ }) && _(function() {
+ new d(-1)
+ }) && k(function(t) {
+ new d, new d(null), new d(1.5), new d(t)
+ }, !0) || (d = e(function(t, e, r, n) {
+ var i;
+ return w(t, d, f), A(e) ? e instanceof Q || (i = E(e)) == H || i == W ? void 0 !== n ? new s(e, It(r, l), n) : void 0 !== r ? new s(e, It(r, l)) : new s(e) : Tt in e ? Dt(d, e) : kt.call(d, e) : new s(M(e))
+ }), $(n !== Function.prototype ? O(s).concat(O(n)) : O(s), function(t) {
+ t in d || T(d, t, s[t])
+ }), d[K] = h, g || (h.constructor = d));
+ var c = h[yt],
+ m = !!c && ("values" == c.name || null == c.name),
+ v = zt.values;
+ T(d, bt, !0), T(h, Tt, f), T(h, St, !0), T(h, xt, d), (o ? new d(1)[_t] == f : _t in h) || j(h, _t, {
+ get: function() {
+ return f
+ }
+ }), u[f] = d, b(b.G + b.W + b.F * (d != s), u), b(b.S, f, {
+ BYTES_PER_ELEMENT: l
+ }), b(b.S + b.F * _(function() {
+ s.of.call(d, 1)
+ }), f, {
+ from: kt,
+ of: Lt
+ }), Y in h || T(h, Y, l), b(b.P, f, Ut), L(f), b(b.P + b.F * Pt, f, {
+ set: jt
+ }), b(b.P + b.F * !m, f, zt), g || h.toString == vt || (h.toString = vt), b(b.P + b.F * _(function() {
+ new d(1).slice()
+ }), f, {
+ slice: Gt
+ }), b(b.P + b.F * (_(function() {
+ return [1, 2].toLocaleString() != new d([1, 2]).toLocaleString()
+ }) || !_(function() {
+ h.toLocaleString.call([1, 2])
+ })), f, {
+ toLocaleString: Bt
+ }), F[f] = m ? c : v, g || m || T(h, yt, v)
+ }
+ } else t.exports = function() {}
+ }, function(t, e, r) {
+ var o = r(157),
+ n = r(1),
+ i = r(74)("metadata"),
+ a = i.store || (i.store = new(r(160))),
+ s = function(t, e, r) {
+ var n = a.get(t);
+ if (!n) {
+ if (!r) return;
+ a.set(t, n = new o)
+ }
+ var i = n.get(e);
+ if (!i) {
+ if (!r) return;
+ n.set(e, i = new o)
+ }
+ return i
+ };
+ t.exports = {
+ store: a,
+ map: s,
+ has: function(t, e, r) {
+ var n = s(e, r, !1);
+ return void 0 !== n && n.has(t)
+ },
+ get: function(t, e, r) {
+ var n = s(e, r, !1);
+ return void 0 === n ? void 0 : n.get(t)
+ },
+ set: function(t, e, r, n) {
+ s(r, n, !0).set(t, e)
+ },
+ keys: function(t, e) {
+ var r = s(t, e, !1),
+ n = [];
+ return r && r.forEach(function(t, e) {
+ n.push(e)
+ }), n
+ },
+ key: function(t) {
+ return void 0 === t || "symbol" == typeof t ? t : String(t)
+ },
+ exp: function(t) {
+ n(n.S, "Reflect", t)
+ }
+ }
+ }, function(t, e, r) {
+ "use strict";
+ e.__esModule = !0;
+ ! function(t) {
+ {
+ if (t && t.__esModule) return;
+ var e = {};
+ if (null != t)
+ for (var r in t) Object.prototype.hasOwnProperty.call(t, r) && (e[r] = t[r]);
+ e.default = t
+ }
+ }(r(0));
+ var n = _interopRequireDefault(r(37)),
+ i = _interopRequireDefault(r(428)),
+ o = _interopRequireDefault(r(429));
+
+ function _interopRequireDefault(t) {
+ return t && t.__esModule ? t : {
+ default: t
+ }
+ }
+ var a = function(e) {
+ function PhongMaterial() {
+ var t = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : {};
+ return function(t, e) {
+ if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
+ }(this, PhongMaterial),
+ function(t, e) {
+ if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return !e || "object" != typeof e && "function" != typeof e ? t : e
+ }(this, e.call(this, t, i.default, o.default, [], "phong"))
+ }
+ return function(t, e) {
+ if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e);
+ t.prototype = Object.create(e && e.prototype, {
+ constructor: {
+ value: t,
+ enumerable: !1,
+ writable: !0,
+ configurable: !0
+ }
+ }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e)
+ }(PhongMaterial, e), PhongMaterial
+ }(n.default);
+ e.default = a
+ }, function(e, r, t) {
+ var n, b, x;
+ ! function(t) {
+ var o = /iPhone/i,
+ a = /iPod/i,
+ s = /iPad/i,
+ u = /\bAndroid(?:.+)Mobile\b/i,
+ h = /Android/i,
+ c = /\bAndroid(?:.+)SD4930UR\b/i,
+ l = /\bAndroid(?:.+)(?:KF[A-Z]{2,4})\b/i,
+ f = /Windows Phone/i,
+ d = /\bWindows(?:.+)ARM\b/i,
+ p = /BlackBerry/i,
+ v = /BB10/i,
+ g = /Opera Mini/i,
+ y = /\b(CriOS|Chrome)(?:.+)Mobile/i,
+ _ = /\Mobile(?:.+)Firefox\b/i;
+
+ function m(t, e) {
+ return t.test(e)
+ }
+
+ function i(t) {
+ var e = t || ("undefined" != typeof navigator ? navigator.userAgent : ""),
+ r = e.split("[FBAN");
+ void 0 !== r[1] && (e = r[0]), void 0 !== (r = e.split("Twitter"))[1] && (e = r[0]);
+ var n = {
+ apple: {
+ phone: m(o, e) && !m(f, e),
+ ipod: m(a, e),
+ tablet: !m(o, e) && m(s, e) && !m(f, e),
+ device: (m(o, e) || m(a, e) || m(s, e)) && !m(f, e)
+ },
+ amazon: {
+ phone: m(c, e),
+ tablet: !m(c, e) && m(l, e),
+ device: m(c, e) || m(l, e)
+ },
+ android: {
+ phone: !m(f, e) && m(c, e) || !m(f, e) && m(u, e),
+ tablet: !m(f, e) && !m(c, e) && !m(u, e) && (m(l, e) || m(h, e)),
+ device: !m(f, e) && (m(c, e) || m(l, e) || m(u, e) || m(h, e))
+ },
+ windows: {
+ phone: m(f, e),
+ tablet: m(d, e),
+ device: m(f, e) || m(d, e)
+ },
+ other: {
+ blackberry: m(p, e),
+ blackberry10: m(v, e),
+ opera: m(g, e),
+ firefox: m(_, e),
+ chrome: m(y, e),
+ device: m(p, e) || m(v, e) || m(g, e) || m(_, e) || m(y, e)
+ }
+ };
+ return n.any = n.apple.device || n.android.device || n.windows.device || n.other.device, n.phone = n.apple.phone || n.android.phone || n.windows.phone, n.tablet = n.apple.tablet || n.android.tablet || n.windows.tablet, n
+ }
+ e.exports && "undefined" == typeof window ? e.exports = i : e.exports && "undefined" != typeof window ? e.exports = i() : (b = [], n = t.isMobile = i(), void 0 === (x = "function" == typeof n ? n.apply(r, b) : n) || (e.exports = x))
+ }(this)
+ }, function(t, e, r) {
+ "use strict";
+ var n = r(12),
+ i = r.n(n),
+ o = r(68),
+ c = r(23),
+ a = function() {
+ function SoundManagerHowler() {
+ this.disabled = !1, (window.smm = this).preload = !0, this.currentSound = null, this.sounds = {}, this.groups = {}, this.globalVolume = 1, this.isMuted = !1, this._visibilityActive = !0, this.preload = !0, window.onfocus = this._onFocus.bind(this), this.onMuteToggle = new i.a, o.a.onHide.add(function() {
+ this.onVisibilityHide()
+ }.bind(this)), o.a.onShow.add(function() {
+ this.onVisibilityShow()
+ }.bind(this))
+ }
+ var t = SoundManagerHowler.prototype;
+ return t.enableVisibility = function() {
+ this._visibilityActive = !0
+ }, t.disableVisibility = function() {
+ this._visibilityActive = !1
+ }, t.onVisibilityHide = function() {
+ this._visibilityActive && (c.Howler.mute(!0), c.Howler.volume(0))
+ }, t.onVisibilityShow = function() {
+ this._visibilityActive && this._onFocus()
+ }, t._onFocus = function() {
+ this.isMuted ? this.mute() : this.unmute()
+ }, t.addSound = function(t, e, r) {
+ if (!this.disabled) {
+ for (var n, i = "", o = 1, a = null, s = 0; s < e.length; s++) "/" === e[s] && (a = s);
+ for (null !== a && (i = e.slice(a + 1, e.length)), e = i; this.exists(i);) i = e + "-" + o, o++;
+ r = r || {};
+ var u = t.split(".").pop();
+ n = "ogg" === u || "mp3" === u || "wav" === u ? [t] : [t + ".ogg", t + ".mp3"];
+ var h = new c.Howl({
+ src: n,
+ preload: this.preload,
+ autoplay: r.autoplay || !1,
+ loop: r.loop || !1,
+ volume: r.volume
+ });
+ r.autoplay && (this.preload || h.load(), h.play()), h.realVolume = r.volume || 1, this.sounds[i] = h
+ }
+ }, t.addSounds = function(t, e) {
+ for (var r = 0; r < t.length; r++) {
+ var n = t[r];
+ this.addSound(e + n, n)
+ }
+ }, t.addGroup = function(t, e) {
+ if (!this.disabled && !this.groups[e]) {
+ var r = {
+ index: 0,
+ type: 0,
+ sounds: t
+ };
+ this.groups[e] = r
+ }
+ }, t.getSoundByAlias = function(t) {
+ return this.sounds[t]
+ }, t.getSound = function(t) {
+ return this.currentSound
+ }, t.exists = function(t) {
+ return this.sounds[t]
+ }, t.play = function(t, e) {
+ if (void 0 === e && (e = {}), !this.disabled && this.sounds[t]) return e.volume && (this.sounds[t].volume = e.volume * this.globalVolume), e.time && (this.sounds[t].currentTime = e.time), this.preload || this.sounds[t].load(), this.sounds[t].play(), this.currentSound = this.sounds[t], this.currentSound;
+ this.sounds[t]
+ }, t.fadeTo = function(t, e, r) {
+ if (void 0 === r && (r = 2.5), void 0 !== e) {
+ var n = this.sounds[t];
+ n && TweenLite.to(n, r, {
+ _volume: e,
+ onUpdate: this.actuallyChangeVolume.bind(this),
+ onComplete: this.stopAndReset.bind(this),
+ onCompleteParams: [t],
+ onUpdateParams: ["{self}", t]
+ })
+ }
+ }, t.actuallyChangeVolume = function(t, e) {
+ this.setVolume(e, t.target._volume)
+ }, t.setVolume = function(t, e) {
+ if (!this.disabled) {
+ var r = this.sounds[t];
+ r.realVolume = e, r.volume(e * this.globalVolume)
+ }
+ }, t.stopAndReset = function(t) {
+ this.stop(t), this.setVolume(t, 1), this.stop(t)
+ }, t.isPlaying = function(t) {
+ if (!this.disabled) return !this.sounds[t]._audioNode[0].paused
+ }, t.playGroup = function(t) {
+ if (!this.disabled && this.groups[t]) {
+ var e = this.groups[t],
+ r = Math.random() * e.sounds.length | 0;
+ this.preload || this.sounds[e.sounds[r]].load(), this.sounds[e.sounds[r]].play(), this.currentSound = this.sounds[e.sounds[r]]
+ }
+ }, t.setVolume = function(t, e) {
+ if (!this.disabled) {
+ var r = this.sounds[t];
+ r.realVolume = e, r.volume = e * this.globalVolume
+ }
+ }, t.stop = function(t) {
+ !this.disabled && this.sounds[t] && this.sounds[t].stop()
+ }, t.pause = function(t) {
+ !this.disabled && this.sounds[t] && this.sounds[t].pause()
+ }, t.stopAll = function() {
+ if (!this.disabled)
+ for (var t in this.sounds) this.sounds[t].stop()
+ }, t.setPlaybackSpeed = function(t, e) {
+ if (!this.disabled) {
+ var r = this.sounds[t];
+ r._playbackSpeed = e;
+ var n = "music" == t ? 0 : 1;
+ r._webAudio && c.Howler._howls[n]._audioNode[0] && (c.Howler._howls[n]._audioNode[0].bufferSource.playbackRate.value = e)
+ }
+ }, t.getPlaybackSpeed = function(t) {
+ if (!this.disabled) return this.sounds[t]._playbackSpeed || 1
+ }, t.setGlobalVolume = function(t) {
+ for (var e in this.globalVolume = t, this.sounds) {
+ var r = this.sounds[e];
+ r.volume = r.realVolume * t
+ }
+ }, t.mute = function() {
+ for (var t in this.isMuted = !0, c.Howler.mute(!0), c.Howler.volume(0), this.sounds) this.sounds[t].mute(!0);
+ this.onMuteToggle.dispatch(!0)
+ }, t.unmute = function() {
+ for (var t in this.isMuted = !1, c.Howler.mute(!1), c.Howler.volume(1), this.sounds) this.sounds[t].mute(!1);
+ this.onMuteToggle.dispatch(!1)
+ }, t.check = function() {
+ this.lastSeen = Date.now();
+ ! function loop() {
+ lastSeen = Date.now(), setTimeout(loop, 50)
+ }(), document.getElementById("music").addEventListener("timeupdate", function() {
+ 100 < Date.now() - exports.lastSeen && this.pause()
+ }, !1)
+ }, SoundManagerHowler
+ }();
+ e.a = new a
+ }, function(t, e, r) {
+ var n = r(52)("meta"),
+ i = r(11),
+ o = r(28),
+ a = r(20).f,
+ s = 0,
+ u = Object.isExtensible || function() {
+ return !0
+ },
+ h = !r(10)(function() {
+ return u(Object.preventExtensions({}))
+ }),
+ c = function(t) {
+ a(t, n, {
+ value: {
+ i: "O" + ++s,
+ w: {}
+ }
+ })
+ },
+ l = t.exports = {
+ KEY: n,
+ NEED: !1,
+ fastKey: function(t, e) {
+ if (!i(t)) return "symbol" == typeof t ? t : ("string" == typeof t ? "S" : "P") + t;
+ if (!o(t, n)) {
+ if (!u(t)) return "F";
+ if (!e) return "E";
+ c(t)
+ }
+ return t[n].i
+ },
+ getWeak: function(t, e) {
+ if (!o(t, n)) {
+ if (!u(t)) return !0;
+ if (!e) return !1;
+ c(t)
+ }
+ return t[n].w
+ },
+ onFreeze: function(t) {
+ return h && l.NEED && u(t) && !o(t, n) && c(t), t
+ }
+ }
+ }, function(t, e) {
+ t.exports = !1
+ }, function(t, e, r) {
+ var n = r(15)("unscopables"),
+ i = Array.prototype;
+ null == i[n] && r(25)(i, n, {}), t.exports = function(t) {
+ i[n][t] = !0
+ }
+ }, function(t, e) {
+ t.exports = function(t, e) {
+ return {
+ enumerable: !(1 & t),
+ configurable: !(2 & t),
+ writable: !(4 & t),
+ value: e
+ }
+ }
+ }, function(t, e) {
+ var r = 0,
+ n = Math.random();
+ t.exports = function(t) {
+ return "Symbol(".concat(void 0 === t ? "" : t, ")_", (++r + n).toString(36))
+ }
+ }, function(t, e, r) {
+ var n = r(136),
+ i = r(101);
+ t.exports = Object.keys || function(t) {
+ return n(t, i)
+ }
+ }, function(t, e, r) {
+ var n = r(35),
+ i = Math.max,
+ o = Math.min;
+ t.exports = function(t, e) {
+ return (t = n(t)) < 0 ? i(t + e, 0) : o(t, e)
+ }
+ }, function(t, e, n) {
+ var i = n(6),
+ o = n(137),
+ a = n(101),
+ s = n(100)("IE_PROTO"),
+ u = function() {},
+ h = "prototype",
+ c = function() {
+ var t, e = n(98)("iframe"),
+ r = a.length;
+ for (e.style.display = "none", n(102).appendChild(e), e.src = "javascript:", (t = e.contentWindow.document).open(), t.write("
-
-
-
-
+
+
- Selenite
+ Support | Selenite
-
+
-
-
+
+
-
-
-
-
-
Thank you for clicking!
-
I'm just a single developer who works on this website for free in my free time. I currently don't make anything from this website, and so any donation would be very appreciated. Click on one of the links below to help support me!
-
Patreon
-
+
+
+
diff --git a/impossiblegame/image.jpg b/theimpossiblegame/image.jpg
similarity index 100%
rename from impossiblegame/image.jpg
rename to theimpossiblegame/image.jpg
diff --git a/impossiblegame/index.html b/theimpossiblegame/index.html
similarity index 100%
rename from impossiblegame/index.html
rename to theimpossiblegame/index.html
diff --git a/impossiblegame/theimpossiblegame.swf b/theimpossiblegame/theimpossiblegame.swf
similarity index 100%
rename from impossiblegame/theimpossiblegame.swf
rename to theimpossiblegame/theimpossiblegame.swf
diff --git a/themes.css b/themes.css
new file mode 100644
index 00000000..9b9e28d6
--- /dev/null
+++ b/themes.css
@@ -0,0 +1,42 @@
+body {
+ --inputbg: #000000;
+ --inputborder: #000000;
+ --uibg: #000000;
+ --textcolor: #000;
+ --bg: #000000;
+}
+body[theme=main] {
+ --inputbg: #3c096c;
+ --inputborder: #5a189a;
+ --uibg: #240046;
+ --textcolor: #fff;
+ --bg: #10002b;
+}
+body[theme=light] {
+ --inputbg: #bbbbbb;
+ --inputborder: #e6e6e6;
+ --uibg: #b3b3b3;
+ --textcolor: #1a1a1a;
+ --bg: #c5c5c5;
+}
+body[theme=dark] {
+ --inputbg: #333333;
+ --inputborder: #444444;
+ --uibg: #242424;
+ --textcolor: #fff;
+ --bg: #0c0c0c;
+}
+body[theme=egamepass] {
+ --inputbg: #4f6ed1;
+ --inputborder: #5586e0;
+ --uibg: #185494;
+ --textcolor: #a7d3ff;
+ --bg: #16416f;
+}
+body[theme=cools1te] {
+ --inputbg: #a134dc;
+ --inputborder: #b153e3;
+ --uibg: #ab28cf;
+ --textcolor: #d3a4fa;
+ --bg: #8e14af;
+}
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/action_bg.png b/thirtydollarwebsite/assets/action_bg.png
new file mode 100644
index 00000000..9735ee80
Binary files /dev/null and b/thirtydollarwebsite/assets/action_bg.png differ
diff --git a/thirtydollarwebsite/assets/action_combine.png b/thirtydollarwebsite/assets/action_combine.png
new file mode 100644
index 00000000..4ecf64d5
Binary files /dev/null and b/thirtydollarwebsite/assets/action_combine.png differ
diff --git a/thirtydollarwebsite/assets/action_cut.png b/thirtydollarwebsite/assets/action_cut.png
new file mode 100644
index 00000000..0a9df78c
Binary files /dev/null and b/thirtydollarwebsite/assets/action_cut.png differ
diff --git a/thirtydollarwebsite/assets/action_divider.png b/thirtydollarwebsite/assets/action_divider.png
new file mode 100644
index 00000000..29627ac9
Binary files /dev/null and b/thirtydollarwebsite/assets/action_divider.png differ
diff --git a/thirtydollarwebsite/assets/action_flash.png b/thirtydollarwebsite/assets/action_flash.png
new file mode 100644
index 00000000..d6c99510
Binary files /dev/null and b/thirtydollarwebsite/assets/action_flash.png differ
diff --git a/thirtydollarwebsite/assets/action_jump.png b/thirtydollarwebsite/assets/action_jump.png
new file mode 100644
index 00000000..bb198491
Binary files /dev/null and b/thirtydollarwebsite/assets/action_jump.png differ
diff --git a/thirtydollarwebsite/assets/action_loop.png b/thirtydollarwebsite/assets/action_loop.png
new file mode 100644
index 00000000..4e745b0b
Binary files /dev/null and b/thirtydollarwebsite/assets/action_loop.png differ
diff --git a/thirtydollarwebsite/assets/action_loopmany.png b/thirtydollarwebsite/assets/action_loopmany.png
new file mode 100644
index 00000000..8305ebdc
Binary files /dev/null and b/thirtydollarwebsite/assets/action_loopmany.png differ
diff --git a/thirtydollarwebsite/assets/action_looptarget.png b/thirtydollarwebsite/assets/action_looptarget.png
new file mode 100644
index 00000000..ac64797b
Binary files /dev/null and b/thirtydollarwebsite/assets/action_looptarget.png differ
diff --git a/thirtydollarwebsite/assets/action_pulse.png b/thirtydollarwebsite/assets/action_pulse.png
new file mode 100644
index 00000000..f49f8146
Binary files /dev/null and b/thirtydollarwebsite/assets/action_pulse.png differ
diff --git a/thirtydollarwebsite/assets/action_speed.png b/thirtydollarwebsite/assets/action_speed.png
new file mode 100644
index 00000000..364b8ee4
Binary files /dev/null and b/thirtydollarwebsite/assets/action_speed.png differ
diff --git a/thirtydollarwebsite/assets/action_startpos.png b/thirtydollarwebsite/assets/action_startpos.png
new file mode 100644
index 00000000..532c7f20
Binary files /dev/null and b/thirtydollarwebsite/assets/action_startpos.png differ
diff --git a/thirtydollarwebsite/assets/action_stop.png b/thirtydollarwebsite/assets/action_stop.png
new file mode 100644
index 00000000..8505fad1
Binary files /dev/null and b/thirtydollarwebsite/assets/action_stop.png differ
diff --git a/thirtydollarwebsite/assets/action_target.png b/thirtydollarwebsite/assets/action_target.png
new file mode 100644
index 00000000..5cf6523c
Binary files /dev/null and b/thirtydollarwebsite/assets/action_target.png differ
diff --git a/thirtydollarwebsite/assets/action_transpose.png b/thirtydollarwebsite/assets/action_transpose.png
new file mode 100644
index 00000000..dc373248
Binary files /dev/null and b/thirtydollarwebsite/assets/action_transpose.png differ
diff --git a/thirtydollarwebsite/assets/action_volume.png b/thirtydollarwebsite/assets/action_volume.png
new file mode 100644
index 00000000..d59bb53f
Binary files /dev/null and b/thirtydollarwebsite/assets/action_volume.png differ
diff --git a/thirtydollarwebsite/assets/check_off.svg b/thirtydollarwebsite/assets/check_off.svg
new file mode 100644
index 00000000..72504499
--- /dev/null
+++ b/thirtydollarwebsite/assets/check_off.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/dont_you_lecture_me.wav b/thirtydollarwebsite/assets/dont_you_lecture_me.wav
new file mode 100644
index 00000000..a5baaba8
Binary files /dev/null and b/thirtydollarwebsite/assets/dont_you_lecture_me.wav differ
diff --git a/thirtydollarwebsite/assets/download.svg b/thirtydollarwebsite/assets/download.svg
new file mode 100644
index 00000000..91b227c4
--- /dev/null
+++ b/thirtydollarwebsite/assets/download.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/load.svg b/thirtydollarwebsite/assets/load.svg
new file mode 100644
index 00000000..e57e30c1
--- /dev/null
+++ b/thirtydollarwebsite/assets/load.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/play.png b/thirtydollarwebsite/assets/play.png
new file mode 100644
index 00000000..fc026965
Binary files /dev/null and b/thirtydollarwebsite/assets/play.png differ
diff --git a/thirtydollarwebsite/assets/reset.png b/thirtydollarwebsite/assets/reset.png
new file mode 100644
index 00000000..8dff0172
Binary files /dev/null and b/thirtydollarwebsite/assets/reset.png differ
diff --git a/thirtydollarwebsite/assets/save.svg b/thirtydollarwebsite/assets/save.svg
new file mode 100644
index 00000000..a5d27eb7
--- /dev/null
+++ b/thirtydollarwebsite/assets/save.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/section_deselect.png b/thirtydollarwebsite/assets/section_deselect.png
new file mode 100644
index 00000000..c6c12913
Binary files /dev/null and b/thirtydollarwebsite/assets/section_deselect.png differ
diff --git a/thirtydollarwebsite/assets/section_hide.png b/thirtydollarwebsite/assets/section_hide.png
new file mode 100644
index 00000000..8642097d
Binary files /dev/null and b/thirtydollarwebsite/assets/section_hide.png differ
diff --git a/thirtydollarwebsite/assets/section_next.png b/thirtydollarwebsite/assets/section_next.png
new file mode 100644
index 00000000..36606bc9
Binary files /dev/null and b/thirtydollarwebsite/assets/section_next.png differ
diff --git a/thirtydollarwebsite/assets/section_previous.png b/thirtydollarwebsite/assets/section_previous.png
new file mode 100644
index 00000000..cac00d7f
Binary files /dev/null and b/thirtydollarwebsite/assets/section_previous.png differ
diff --git a/thirtydollarwebsite/assets/section_show.png b/thirtydollarwebsite/assets/section_show.png
new file mode 100644
index 00000000..45ab5768
Binary files /dev/null and b/thirtydollarwebsite/assets/section_show.png differ
diff --git a/thirtydollarwebsite/assets/social_tiktok.svg b/thirtydollarwebsite/assets/social_tiktok.svg
new file mode 100644
index 00000000..3da85e64
--- /dev/null
+++ b/thirtydollarwebsite/assets/social_tiktok.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/social_twitter.svg b/thirtydollarwebsite/assets/social_twitter.svg
new file mode 100644
index 00000000..d16b6a7d
--- /dev/null
+++ b/thirtydollarwebsite/assets/social_twitter.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
diff --git a/thirtydollarwebsite/assets/social_youtube.svg b/thirtydollarwebsite/assets/social_youtube.svg
new file mode 100644
index 00000000..552c295f
--- /dev/null
+++ b/thirtydollarwebsite/assets/social_youtube.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/stop.png b/thirtydollarwebsite/assets/stop.png
new file mode 100644
index 00000000..192a0fab
Binary files /dev/null and b/thirtydollarwebsite/assets/stop.png differ
diff --git a/thirtydollarwebsite/assets/tab_actions.svg b/thirtydollarwebsite/assets/tab_actions.svg
new file mode 100644
index 00000000..a49fdf92
--- /dev/null
+++ b/thirtydollarwebsite/assets/tab_actions.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/tab_all.svg b/thirtydollarwebsite/assets/tab_all.svg
new file mode 100644
index 00000000..00c4a0c2
--- /dev/null
+++ b/thirtydollarwebsite/assets/tab_all.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/tab_notes.svg b/thirtydollarwebsite/assets/tab_notes.svg
new file mode 100644
index 00000000..d224ce01
--- /dev/null
+++ b/thirtydollarwebsite/assets/tab_notes.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/tab_percussion.svg b/thirtydollarwebsite/assets/tab_percussion.svg
new file mode 100644
index 00000000..748d8a7b
--- /dev/null
+++ b/thirtydollarwebsite/assets/tab_percussion.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/tab_recent.svg b/thirtydollarwebsite/assets/tab_recent.svg
new file mode 100644
index 00000000..5638d69d
--- /dev/null
+++ b/thirtydollarwebsite/assets/tab_recent.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/assets/white_people_be_like.wav b/thirtydollarwebsite/assets/white_people_be_like.wav
new file mode 100644
index 00000000..7e0dbc78
Binary files /dev/null and b/thirtydollarwebsite/assets/white_people_be_like.wav differ
diff --git a/thirtydollarwebsite/assets/you_deadass_built_like_a.wav b/thirtydollarwebsite/assets/you_deadass_built_like_a.wav
new file mode 100644
index 00000000..f948b264
Binary files /dev/null and b/thirtydollarwebsite/assets/you_deadass_built_like_a.wav differ
diff --git a/thirtydollarwebsite/assets/🗿.png b/thirtydollarwebsite/assets/🗿.png
new file mode 100644
index 00000000..910c14dc
Binary files /dev/null and b/thirtydollarwebsite/assets/🗿.png differ
diff --git a/thirtydollarwebsite/icons/21.png b/thirtydollarwebsite/icons/21.png
new file mode 100644
index 00000000..d6769a30
Binary files /dev/null and b/thirtydollarwebsite/icons/21.png differ
diff --git a/thirtydollarwebsite/icons/BABA.png b/thirtydollarwebsite/icons/BABA.png
new file mode 100644
index 00000000..5426f05b
Binary files /dev/null and b/thirtydollarwebsite/icons/BABA.png differ
diff --git a/thirtydollarwebsite/icons/DEFEAT.png b/thirtydollarwebsite/icons/DEFEAT.png
new file mode 100644
index 00000000..75acd28e
Binary files /dev/null and b/thirtydollarwebsite/icons/DEFEAT.png differ
diff --git a/thirtydollarwebsite/icons/SLAM.png b/thirtydollarwebsite/icons/SLAM.png
new file mode 100644
index 00000000..436dcb06
Binary files /dev/null and b/thirtydollarwebsite/icons/SLAM.png differ
diff --git a/thirtydollarwebsite/icons/YOU.png b/thirtydollarwebsite/icons/YOU.png
new file mode 100644
index 00000000..c8356fb0
Binary files /dev/null and b/thirtydollarwebsite/icons/YOU.png differ
diff --git a/thirtydollarwebsite/icons/adofai_fire.png b/thirtydollarwebsite/icons/adofai_fire.png
new file mode 100644
index 00000000..89705878
Binary files /dev/null and b/thirtydollarwebsite/icons/adofai_fire.png differ
diff --git a/thirtydollarwebsite/icons/adofai_ice.png b/thirtydollarwebsite/icons/adofai_ice.png
new file mode 100644
index 00000000..592cab02
Binary files /dev/null and b/thirtydollarwebsite/icons/adofai_ice.png differ
diff --git a/thirtydollarwebsite/icons/adofaicymbal.png b/thirtydollarwebsite/icons/adofaicymbal.png
new file mode 100644
index 00000000..bc449a22
Binary files /dev/null and b/thirtydollarwebsite/icons/adofaicymbal.png differ
diff --git a/thirtydollarwebsite/icons/adofaikick.png b/thirtydollarwebsite/icons/adofaikick.png
new file mode 100644
index 00000000..889653c0
Binary files /dev/null and b/thirtydollarwebsite/icons/adofaikick.png differ
diff --git a/thirtydollarwebsite/icons/airhorn.png b/thirtydollarwebsite/icons/airhorn.png
new file mode 100644
index 00000000..7ddca353
Binary files /dev/null and b/thirtydollarwebsite/icons/airhorn.png differ
diff --git a/thirtydollarwebsite/icons/americano.png b/thirtydollarwebsite/icons/americano.png
new file mode 100644
index 00000000..a618f733
Binary files /dev/null and b/thirtydollarwebsite/icons/americano.png differ
diff --git a/thirtydollarwebsite/icons/amogus.png b/thirtydollarwebsite/icons/amogus.png
new file mode 100644
index 00000000..808e5b94
Binary files /dev/null and b/thirtydollarwebsite/icons/amogus.png differ
diff --git a/thirtydollarwebsite/icons/amogus_emergency.png b/thirtydollarwebsite/icons/amogus_emergency.png
new file mode 100644
index 00000000..9d5a0cf1
Binary files /dev/null and b/thirtydollarwebsite/icons/amogus_emergency.png differ
diff --git a/thirtydollarwebsite/icons/amogus_kill.png b/thirtydollarwebsite/icons/amogus_kill.png
new file mode 100644
index 00000000..e68a6c3d
Binary files /dev/null and b/thirtydollarwebsite/icons/amogus_kill.png differ
diff --git a/thirtydollarwebsite/icons/amongdrip.png b/thirtydollarwebsite/icons/amongdrip.png
new file mode 100644
index 00000000..cf20047d
Binary files /dev/null and b/thirtydollarwebsite/icons/amongdrip.png differ
diff --git a/thirtydollarwebsite/icons/amongus.png b/thirtydollarwebsite/icons/amongus.png
new file mode 100644
index 00000000..eba95be1
Binary files /dev/null and b/thirtydollarwebsite/icons/amongus.png differ
diff --git a/thirtydollarwebsite/icons/boing.png b/thirtydollarwebsite/icons/boing.png
new file mode 100644
index 00000000..e0c4ae2d
Binary files /dev/null and b/thirtydollarwebsite/icons/boing.png differ
diff --git a/thirtydollarwebsite/icons/bong.png b/thirtydollarwebsite/icons/bong.png
new file mode 100644
index 00000000..f84f6c9d
Binary files /dev/null and b/thirtydollarwebsite/icons/bong.png differ
diff --git a/thirtydollarwebsite/icons/boom.png b/thirtydollarwebsite/icons/boom.png
new file mode 100644
index 00000000..910c14dc
Binary files /dev/null and b/thirtydollarwebsite/icons/boom.png differ
diff --git a/thirtydollarwebsite/icons/boowomp.png b/thirtydollarwebsite/icons/boowomp.png
new file mode 100644
index 00000000..dcc6a85f
Binary files /dev/null and b/thirtydollarwebsite/icons/boowomp.png differ
diff --git a/thirtydollarwebsite/icons/bruh.png b/thirtydollarwebsite/icons/bruh.png
new file mode 100644
index 00000000..3eead237
Binary files /dev/null and b/thirtydollarwebsite/icons/bruh.png differ
diff --git a/thirtydollarwebsite/icons/builttoscale.png b/thirtydollarwebsite/icons/builttoscale.png
new file mode 100644
index 00000000..a7e5d565
Binary files /dev/null and b/thirtydollarwebsite/icons/builttoscale.png differ
diff --git a/thirtydollarwebsite/icons/bup.png b/thirtydollarwebsite/icons/bup.png
new file mode 100644
index 00000000..368cb36a
Binary files /dev/null and b/thirtydollarwebsite/icons/bup.png differ
diff --git a/thirtydollarwebsite/icons/buttonpop.png b/thirtydollarwebsite/icons/buttonpop.png
new file mode 100644
index 00000000..a9930f2b
Binary files /dev/null and b/thirtydollarwebsite/icons/buttonpop.png differ
diff --git a/thirtydollarwebsite/icons/buzzer.png b/thirtydollarwebsite/icons/buzzer.png
new file mode 100644
index 00000000..47f2b8da
Binary files /dev/null and b/thirtydollarwebsite/icons/buzzer.png differ
diff --git a/thirtydollarwebsite/icons/bwomp.png b/thirtydollarwebsite/icons/bwomp.png
new file mode 100644
index 00000000..57b39e97
Binary files /dev/null and b/thirtydollarwebsite/icons/bwomp.png differ
diff --git a/thirtydollarwebsite/icons/celeste_dash.png b/thirtydollarwebsite/icons/celeste_dash.png
new file mode 100644
index 00000000..85786e7a
Binary files /dev/null and b/thirtydollarwebsite/icons/celeste_dash.png differ
diff --git a/thirtydollarwebsite/icons/celeste_death.png b/thirtydollarwebsite/icons/celeste_death.png
new file mode 100644
index 00000000..7c583c12
Binary files /dev/null and b/thirtydollarwebsite/icons/celeste_death.png differ
diff --git a/thirtydollarwebsite/icons/celeste_diamond.png b/thirtydollarwebsite/icons/celeste_diamond.png
new file mode 100644
index 00000000..7d71fa6e
Binary files /dev/null and b/thirtydollarwebsite/icons/celeste_diamond.png differ
diff --git a/thirtydollarwebsite/icons/celeste_spring.png b/thirtydollarwebsite/icons/celeste_spring.png
new file mode 100644
index 00000000..5e02de77
Binary files /dev/null and b/thirtydollarwebsite/icons/celeste_spring.png differ
diff --git a/thirtydollarwebsite/icons/choruskid.png b/thirtydollarwebsite/icons/choruskid.png
new file mode 100644
index 00000000..d0efbc3b
Binary files /dev/null and b/thirtydollarwebsite/icons/choruskid.png differ
diff --git a/thirtydollarwebsite/icons/cowbell.png b/thirtydollarwebsite/icons/cowbell.png
new file mode 100644
index 00000000..c4265ea4
Binary files /dev/null and b/thirtydollarwebsite/icons/cowbell.png differ
diff --git a/thirtydollarwebsite/icons/dimrainsynth.png b/thirtydollarwebsite/icons/dimrainsynth.png
new file mode 100644
index 00000000..38966032
Binary files /dev/null and b/thirtydollarwebsite/icons/dimrainsynth.png differ
diff --git a/thirtydollarwebsite/icons/dodgeball.png b/thirtydollarwebsite/icons/dodgeball.png
new file mode 100644
index 00000000..95ba87ef
Binary files /dev/null and b/thirtydollarwebsite/icons/dodgeball.png differ
diff --git a/thirtydollarwebsite/icons/e.png b/thirtydollarwebsite/icons/e.png
new file mode 100644
index 00000000..92be0fdf
Binary files /dev/null and b/thirtydollarwebsite/icons/e.png differ
diff --git a/thirtydollarwebsite/icons/eight.png b/thirtydollarwebsite/icons/eight.png
new file mode 100644
index 00000000..eaed8862
Binary files /dev/null and b/thirtydollarwebsite/icons/eight.png differ
diff --git a/thirtydollarwebsite/icons/empty.png b/thirtydollarwebsite/icons/empty.png
new file mode 100644
index 00000000..855346ad
Binary files /dev/null and b/thirtydollarwebsite/icons/empty.png differ
diff --git a/thirtydollarwebsite/icons/explosion.png b/thirtydollarwebsite/icons/explosion.png
new file mode 100644
index 00000000..e8682d25
Binary files /dev/null and b/thirtydollarwebsite/icons/explosion.png differ
diff --git a/thirtydollarwebsite/icons/familyguy.png b/thirtydollarwebsite/icons/familyguy.png
new file mode 100644
index 00000000..1b8c2153
Binary files /dev/null and b/thirtydollarwebsite/icons/familyguy.png differ
diff --git a/thirtydollarwebsite/icons/flipnote.png b/thirtydollarwebsite/icons/flipnote.png
new file mode 100644
index 00000000..d016796b
Binary files /dev/null and b/thirtydollarwebsite/icons/flipnote.png differ
diff --git a/thirtydollarwebsite/icons/fnf_death.png b/thirtydollarwebsite/icons/fnf_death.png
new file mode 100644
index 00000000..b96565e0
Binary files /dev/null and b/thirtydollarwebsite/icons/fnf_death.png differ
diff --git a/thirtydollarwebsite/icons/fnf_down.png b/thirtydollarwebsite/icons/fnf_down.png
new file mode 100644
index 00000000..cfe07bee
Binary files /dev/null and b/thirtydollarwebsite/icons/fnf_down.png differ
diff --git a/thirtydollarwebsite/icons/fnf_left.png b/thirtydollarwebsite/icons/fnf_left.png
new file mode 100644
index 00000000..0e9c57ba
Binary files /dev/null and b/thirtydollarwebsite/icons/fnf_left.png differ
diff --git a/thirtydollarwebsite/icons/fnf_right.png b/thirtydollarwebsite/icons/fnf_right.png
new file mode 100644
index 00000000..11725547
Binary files /dev/null and b/thirtydollarwebsite/icons/fnf_right.png differ
diff --git a/thirtydollarwebsite/icons/fnf_up.png b/thirtydollarwebsite/icons/fnf_up.png
new file mode 100644
index 00000000..208f0c17
Binary files /dev/null and b/thirtydollarwebsite/icons/fnf_up.png differ
diff --git a/thirtydollarwebsite/icons/gaster.png b/thirtydollarwebsite/icons/gaster.png
new file mode 100644
index 00000000..b2863474
Binary files /dev/null and b/thirtydollarwebsite/icons/gaster.png differ
diff --git a/thirtydollarwebsite/icons/gd_coin.png b/thirtydollarwebsite/icons/gd_coin.png
new file mode 100644
index 00000000..c6ab23fe
Binary files /dev/null and b/thirtydollarwebsite/icons/gd_coin.png differ
diff --git a/thirtydollarwebsite/icons/gd_diamonds.png b/thirtydollarwebsite/icons/gd_diamonds.png
new file mode 100644
index 00000000..10b8a598
Binary files /dev/null and b/thirtydollarwebsite/icons/gd_diamonds.png differ
diff --git a/thirtydollarwebsite/icons/gd_orbs.png b/thirtydollarwebsite/icons/gd_orbs.png
new file mode 100644
index 00000000..44f6e835
Binary files /dev/null and b/thirtydollarwebsite/icons/gd_orbs.png differ
diff --git a/thirtydollarwebsite/icons/gd_quit.png b/thirtydollarwebsite/icons/gd_quit.png
new file mode 100644
index 00000000..47726ebf
Binary files /dev/null and b/thirtydollarwebsite/icons/gd_quit.png differ
diff --git a/thirtydollarwebsite/icons/gdcrash.png b/thirtydollarwebsite/icons/gdcrash.png
new file mode 100644
index 00000000..e173d4b7
Binary files /dev/null and b/thirtydollarwebsite/icons/gdcrash.png differ
diff --git a/thirtydollarwebsite/icons/gdcrash_orbs.png b/thirtydollarwebsite/icons/gdcrash_orbs.png
new file mode 100644
index 00000000..9045afed
Binary files /dev/null and b/thirtydollarwebsite/icons/gdcrash_orbs.png differ
diff --git a/thirtydollarwebsite/icons/gnome.png b/thirtydollarwebsite/icons/gnome.png
new file mode 100644
index 00000000..2b491f1d
Binary files /dev/null and b/thirtydollarwebsite/icons/gnome.png differ
diff --git a/thirtydollarwebsite/icons/granddad.png b/thirtydollarwebsite/icons/granddad.png
new file mode 100644
index 00000000..1c19f80f
Binary files /dev/null and b/thirtydollarwebsite/icons/granddad.png differ
diff --git a/thirtydollarwebsite/icons/gun.png b/thirtydollarwebsite/icons/gun.png
new file mode 100644
index 00000000..30091071
Binary files /dev/null and b/thirtydollarwebsite/icons/gun.png differ
diff --git a/thirtydollarwebsite/icons/hammer.png b/thirtydollarwebsite/icons/hammer.png
new file mode 100644
index 00000000..5e26d734
Binary files /dev/null and b/thirtydollarwebsite/icons/hammer.png differ
diff --git a/thirtydollarwebsite/icons/hehehehaw.png b/thirtydollarwebsite/icons/hehehehaw.png
new file mode 100644
index 00000000..30bf42c5
Binary files /dev/null and b/thirtydollarwebsite/icons/hehehehaw.png differ
diff --git a/thirtydollarwebsite/icons/hitmarker.png b/thirtydollarwebsite/icons/hitmarker.png
new file mode 100644
index 00000000..d7764e4d
Binary files /dev/null and b/thirtydollarwebsite/icons/hitmarker.png differ
diff --git a/thirtydollarwebsite/icons/hoenn.png b/thirtydollarwebsite/icons/hoenn.png
new file mode 100644
index 00000000..5f2d8ed1
Binary files /dev/null and b/thirtydollarwebsite/icons/hoenn.png differ
diff --git a/thirtydollarwebsite/icons/isaac_dead.png b/thirtydollarwebsite/icons/isaac_dead.png
new file mode 100644
index 00000000..531a96d9
Binary files /dev/null and b/thirtydollarwebsite/icons/isaac_dead.png differ
diff --git a/thirtydollarwebsite/icons/isaac_hurt.png b/thirtydollarwebsite/icons/isaac_hurt.png
new file mode 100644
index 00000000..4e89a39c
Binary files /dev/null and b/thirtydollarwebsite/icons/isaac_hurt.png differ
diff --git a/thirtydollarwebsite/icons/isaac_mantle.png b/thirtydollarwebsite/icons/isaac_mantle.png
new file mode 100644
index 00000000..fa6b9040
Binary files /dev/null and b/thirtydollarwebsite/icons/isaac_mantle.png differ
diff --git a/thirtydollarwebsite/icons/karateman_bulb.png b/thirtydollarwebsite/icons/karateman_bulb.png
new file mode 100644
index 00000000..e63876bf
Binary files /dev/null and b/thirtydollarwebsite/icons/karateman_bulb.png differ
diff --git a/thirtydollarwebsite/icons/karateman_hit.png b/thirtydollarwebsite/icons/karateman_hit.png
new file mode 100644
index 00000000..37aea1a9
Binary files /dev/null and b/thirtydollarwebsite/icons/karateman_hit.png differ
diff --git a/thirtydollarwebsite/icons/karateman_offbeat.png b/thirtydollarwebsite/icons/karateman_offbeat.png
new file mode 100644
index 00000000..c449278d
Binary files /dev/null and b/thirtydollarwebsite/icons/karateman_offbeat.png differ
diff --git a/thirtydollarwebsite/icons/karateman_throw.png b/thirtydollarwebsite/icons/karateman_throw.png
new file mode 100644
index 00000000..ec538786
Binary files /dev/null and b/thirtydollarwebsite/icons/karateman_throw.png differ
diff --git a/thirtydollarwebsite/icons/lancersplat.png b/thirtydollarwebsite/icons/lancersplat.png
new file mode 100644
index 00000000..ed796cb7
Binary files /dev/null and b/thirtydollarwebsite/icons/lancersplat.png differ
diff --git a/thirtydollarwebsite/icons/mariopaint_baby.png b/thirtydollarwebsite/icons/mariopaint_baby.png
new file mode 100644
index 00000000..d9161d47
Binary files /dev/null and b/thirtydollarwebsite/icons/mariopaint_baby.png differ
diff --git a/thirtydollarwebsite/icons/mariopaint_car.png b/thirtydollarwebsite/icons/mariopaint_car.png
new file mode 100644
index 00000000..68c564e4
Binary files /dev/null and b/thirtydollarwebsite/icons/mariopaint_car.png differ
diff --git a/thirtydollarwebsite/icons/mariopaint_cat.png b/thirtydollarwebsite/icons/mariopaint_cat.png
new file mode 100644
index 00000000..61a5eb3a
Binary files /dev/null and b/thirtydollarwebsite/icons/mariopaint_cat.png differ
diff --git a/thirtydollarwebsite/icons/mariopaint_dog.png b/thirtydollarwebsite/icons/mariopaint_dog.png
new file mode 100644
index 00000000..3322b916
Binary files /dev/null and b/thirtydollarwebsite/icons/mariopaint_dog.png differ
diff --git a/thirtydollarwebsite/icons/mariopaint_flower.png b/thirtydollarwebsite/icons/mariopaint_flower.png
new file mode 100644
index 00000000..f39d1db1
Binary files /dev/null and b/thirtydollarwebsite/icons/mariopaint_flower.png differ
diff --git a/thirtydollarwebsite/icons/mariopaint_gameboy.png b/thirtydollarwebsite/icons/mariopaint_gameboy.png
new file mode 100644
index 00000000..14977d8a
Binary files /dev/null and b/thirtydollarwebsite/icons/mariopaint_gameboy.png differ
diff --git a/thirtydollarwebsite/icons/mariopaint_luigi.png b/thirtydollarwebsite/icons/mariopaint_luigi.png
new file mode 100644
index 00000000..aa80d8db
Binary files /dev/null and b/thirtydollarwebsite/icons/mariopaint_luigi.png differ
diff --git a/thirtydollarwebsite/icons/mariopaint_mario.png b/thirtydollarwebsite/icons/mariopaint_mario.png
new file mode 100644
index 00000000..246abdb7
Binary files /dev/null and b/thirtydollarwebsite/icons/mariopaint_mario.png differ
diff --git a/thirtydollarwebsite/icons/mariopaint_plane.png b/thirtydollarwebsite/icons/mariopaint_plane.png
new file mode 100644
index 00000000..7ebce5cc
Binary files /dev/null and b/thirtydollarwebsite/icons/mariopaint_plane.png differ
diff --git a/thirtydollarwebsite/icons/mariopaint_star.png b/thirtydollarwebsite/icons/mariopaint_star.png
new file mode 100644
index 00000000..68d0e612
Binary files /dev/null and b/thirtydollarwebsite/icons/mariopaint_star.png differ
diff --git a/thirtydollarwebsite/icons/mariopaint_swan.png b/thirtydollarwebsite/icons/mariopaint_swan.png
new file mode 100644
index 00000000..a382a742
Binary files /dev/null and b/thirtydollarwebsite/icons/mariopaint_swan.png differ
diff --git a/thirtydollarwebsite/icons/megalovania.png b/thirtydollarwebsite/icons/megalovania.png
new file mode 100644
index 00000000..30d3b017
Binary files /dev/null and b/thirtydollarwebsite/icons/megalovania.png differ
diff --git a/thirtydollarwebsite/icons/metalpipe.png b/thirtydollarwebsite/icons/metalpipe.png
new file mode 100644
index 00000000..d39d0c00
Binary files /dev/null and b/thirtydollarwebsite/icons/metalpipe.png differ
diff --git a/thirtydollarwebsite/icons/midspin.png b/thirtydollarwebsite/icons/midspin.png
new file mode 100644
index 00000000..b3afdaca
Binary files /dev/null and b/thirtydollarwebsite/icons/midspin.png differ
diff --git a/thirtydollarwebsite/icons/minecraft_anvil.png b/thirtydollarwebsite/icons/minecraft_anvil.png
new file mode 100644
index 00000000..656b4ef9
Binary files /dev/null and b/thirtydollarwebsite/icons/minecraft_anvil.png differ
diff --git a/thirtydollarwebsite/icons/minecraft_bell.png b/thirtydollarwebsite/icons/minecraft_bell.png
new file mode 100644
index 00000000..2ea39119
Binary files /dev/null and b/thirtydollarwebsite/icons/minecraft_bell.png differ
diff --git a/thirtydollarwebsite/icons/minecraft_explosion.png b/thirtydollarwebsite/icons/minecraft_explosion.png
new file mode 100644
index 00000000..2d32ee73
Binary files /dev/null and b/thirtydollarwebsite/icons/minecraft_explosion.png differ
diff --git a/thirtydollarwebsite/icons/morshu.png b/thirtydollarwebsite/icons/morshu.png
new file mode 100644
index 00000000..95faf80d
Binary files /dev/null and b/thirtydollarwebsite/icons/morshu.png differ
diff --git a/thirtydollarwebsite/icons/mrbeast.png b/thirtydollarwebsite/icons/mrbeast.png
new file mode 100644
index 00000000..36d6916b
Binary files /dev/null and b/thirtydollarwebsite/icons/mrbeast.png differ
diff --git a/thirtydollarwebsite/icons/necoarc.png b/thirtydollarwebsite/icons/necoarc.png
new file mode 100644
index 00000000..9c98e739
Binary files /dev/null and b/thirtydollarwebsite/icons/necoarc.png differ
diff --git a/thirtydollarwebsite/icons/nope.png b/thirtydollarwebsite/icons/nope.png
new file mode 100644
index 00000000..6b95174d
Binary files /dev/null and b/thirtydollarwebsite/icons/nope.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_banjo.png b/thirtydollarwebsite/icons/noteblock_banjo.png
new file mode 100644
index 00000000..d2d7eb2f
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_banjo.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_bass.png b/thirtydollarwebsite/icons/noteblock_bass.png
new file mode 100644
index 00000000..1b99d79e
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_bass.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_bell.png b/thirtydollarwebsite/icons/noteblock_bell.png
new file mode 100644
index 00000000..1dd03296
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_bell.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_bit.png b/thirtydollarwebsite/icons/noteblock_bit.png
new file mode 100644
index 00000000..00e04c51
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_bit.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_chime.png b/thirtydollarwebsite/icons/noteblock_chime.png
new file mode 100644
index 00000000..61a7c354
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_chime.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_click.png b/thirtydollarwebsite/icons/noteblock_click.png
new file mode 100644
index 00000000..458d306b
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_click.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_flute.png b/thirtydollarwebsite/icons/noteblock_flute.png
new file mode 100644
index 00000000..4583079d
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_flute.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_guitar.png b/thirtydollarwebsite/icons/noteblock_guitar.png
new file mode 100644
index 00000000..7efa463d
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_guitar.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_harp.png b/thirtydollarwebsite/icons/noteblock_harp.png
new file mode 100644
index 00000000..557536c0
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_harp.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_pling.png b/thirtydollarwebsite/icons/noteblock_pling.png
new file mode 100644
index 00000000..32c76808
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_pling.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_snare.png b/thirtydollarwebsite/icons/noteblock_snare.png
new file mode 100644
index 00000000..1b638d70
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_snare.png differ
diff --git a/thirtydollarwebsite/icons/noteblock_xylophone.png b/thirtydollarwebsite/icons/noteblock_xylophone.png
new file mode 100644
index 00000000..f9885cda
Binary files /dev/null and b/thirtydollarwebsite/icons/noteblock_xylophone.png differ
diff --git a/thirtydollarwebsite/icons/obama.png b/thirtydollarwebsite/icons/obama.png
new file mode 100644
index 00000000..69949ded
Binary files /dev/null and b/thirtydollarwebsite/icons/obama.png differ
diff --git a/thirtydollarwebsite/icons/oof.png b/thirtydollarwebsite/icons/oof.png
new file mode 100644
index 00000000..58d44ddd
Binary files /dev/null and b/thirtydollarwebsite/icons/oof.png differ
diff --git a/thirtydollarwebsite/icons/ook.png b/thirtydollarwebsite/icons/ook.png
new file mode 100644
index 00000000..efbab026
Binary files /dev/null and b/thirtydollarwebsite/icons/ook.png differ
diff --git a/thirtydollarwebsite/icons/op.png b/thirtydollarwebsite/icons/op.png
new file mode 100644
index 00000000..a71fd4c2
Binary files /dev/null and b/thirtydollarwebsite/icons/op.png differ
diff --git a/thirtydollarwebsite/icons/otto_happy.png b/thirtydollarwebsite/icons/otto_happy.png
new file mode 100644
index 00000000..66e129ac
Binary files /dev/null and b/thirtydollarwebsite/icons/otto_happy.png differ
diff --git a/thirtydollarwebsite/icons/otto_off.png b/thirtydollarwebsite/icons/otto_off.png
new file mode 100644
index 00000000..ecf0c544
Binary files /dev/null and b/thirtydollarwebsite/icons/otto_off.png differ
diff --git a/thirtydollarwebsite/icons/otto_on.png b/thirtydollarwebsite/icons/otto_on.png
new file mode 100644
index 00000000..5c30b7a7
Binary files /dev/null and b/thirtydollarwebsite/icons/otto_on.png differ
diff --git a/thirtydollarwebsite/icons/otto_stress.png b/thirtydollarwebsite/icons/otto_stress.png
new file mode 100644
index 00000000..86effb87
Binary files /dev/null and b/thirtydollarwebsite/icons/otto_stress.png differ
diff --git a/thirtydollarwebsite/icons/pan.png b/thirtydollarwebsite/icons/pan.png
new file mode 100644
index 00000000..3fd6ae11
Binary files /dev/null and b/thirtydollarwebsite/icons/pan.png differ
diff --git a/thirtydollarwebsite/icons/perfectfail.png b/thirtydollarwebsite/icons/perfectfail.png
new file mode 100644
index 00000000..0ff7deba
Binary files /dev/null and b/thirtydollarwebsite/icons/perfectfail.png differ
diff --git a/thirtydollarwebsite/icons/pingas.png b/thirtydollarwebsite/icons/pingas.png
new file mode 100644
index 00000000..6e9a103e
Binary files /dev/null and b/thirtydollarwebsite/icons/pingas.png differ
diff --git a/thirtydollarwebsite/icons/preecho.png b/thirtydollarwebsite/icons/preecho.png
new file mode 100644
index 00000000..7f7aa899
Binary files /dev/null and b/thirtydollarwebsite/icons/preecho.png differ
diff --git a/thirtydollarwebsite/icons/puyo.png b/thirtydollarwebsite/icons/puyo.png
new file mode 100644
index 00000000..cc8a0446
Binary files /dev/null and b/thirtydollarwebsite/icons/puyo.png differ
diff --git a/thirtydollarwebsite/icons/rdclap.png b/thirtydollarwebsite/icons/rdclap.png
new file mode 100644
index 00000000..e5da4938
Binary files /dev/null and b/thirtydollarwebsite/icons/rdclap.png differ
diff --git a/thirtydollarwebsite/icons/rdmistake.png b/thirtydollarwebsite/icons/rdmistake.png
new file mode 100644
index 00000000..8821a62c
Binary files /dev/null and b/thirtydollarwebsite/icons/rdmistake.png differ
diff --git a/thirtydollarwebsite/icons/ride2.png b/thirtydollarwebsite/icons/ride2.png
new file mode 100644
index 00000000..c7f43517
Binary files /dev/null and b/thirtydollarwebsite/icons/ride2.png differ
diff --git a/thirtydollarwebsite/icons/robtopphone.png b/thirtydollarwebsite/icons/robtopphone.png
new file mode 100644
index 00000000..82285353
Binary files /dev/null and b/thirtydollarwebsite/icons/robtopphone.png differ
diff --git a/thirtydollarwebsite/icons/samurai.png b/thirtydollarwebsite/icons/samurai.png
new file mode 100644
index 00000000..6203f04f
Binary files /dev/null and b/thirtydollarwebsite/icons/samurai.png differ
diff --git a/thirtydollarwebsite/icons/sans_voice.png b/thirtydollarwebsite/icons/sans_voice.png
new file mode 100644
index 00000000..24410b45
Binary files /dev/null and b/thirtydollarwebsite/icons/sans_voice.png differ
diff --git a/thirtydollarwebsite/icons/shaker.png b/thirtydollarwebsite/icons/shaker.png
new file mode 100644
index 00000000..f8d8f135
Binary files /dev/null and b/thirtydollarwebsite/icons/shaker.png differ
diff --git a/thirtydollarwebsite/icons/shatter.png b/thirtydollarwebsite/icons/shatter.png
new file mode 100644
index 00000000..45754909
Binary files /dev/null and b/thirtydollarwebsite/icons/shatter.png differ
diff --git a/thirtydollarwebsite/icons/sidestick.png b/thirtydollarwebsite/icons/sidestick.png
new file mode 100644
index 00000000..9e365a81
Binary files /dev/null and b/thirtydollarwebsite/icons/sidestick.png differ
diff --git a/thirtydollarwebsite/icons/skipshot.png b/thirtydollarwebsite/icons/skipshot.png
new file mode 100644
index 00000000..54395090
Binary files /dev/null and b/thirtydollarwebsite/icons/skipshot.png differ
diff --git a/thirtydollarwebsite/icons/slip.png b/thirtydollarwebsite/icons/slip.png
new file mode 100644
index 00000000..7ca53de4
Binary files /dev/null and b/thirtydollarwebsite/icons/slip.png differ
diff --git a/thirtydollarwebsite/icons/sm64_hurt.png b/thirtydollarwebsite/icons/sm64_hurt.png
new file mode 100644
index 00000000..5bac2ed1
Binary files /dev/null and b/thirtydollarwebsite/icons/sm64_hurt.png differ
diff --git a/thirtydollarwebsite/icons/sm64_painting.png b/thirtydollarwebsite/icons/sm64_painting.png
new file mode 100644
index 00000000..20a08dee
Binary files /dev/null and b/thirtydollarwebsite/icons/sm64_painting.png differ
diff --git a/thirtydollarwebsite/icons/smm_scream.png b/thirtydollarwebsite/icons/smm_scream.png
new file mode 100644
index 00000000..1cd36c54
Binary files /dev/null and b/thirtydollarwebsite/icons/smm_scream.png differ
diff --git a/thirtydollarwebsite/icons/smw_1up.png b/thirtydollarwebsite/icons/smw_1up.png
new file mode 100644
index 00000000..c5dab611
Binary files /dev/null and b/thirtydollarwebsite/icons/smw_1up.png differ
diff --git a/thirtydollarwebsite/icons/smw_coin.png b/thirtydollarwebsite/icons/smw_coin.png
new file mode 100644
index 00000000..8163b0b9
Binary files /dev/null and b/thirtydollarwebsite/icons/smw_coin.png differ
diff --git a/thirtydollarwebsite/icons/smw_kick.png b/thirtydollarwebsite/icons/smw_kick.png
new file mode 100644
index 00000000..c8ccf380
Binary files /dev/null and b/thirtydollarwebsite/icons/smw_kick.png differ
diff --git a/thirtydollarwebsite/icons/smw_spinjump.png b/thirtydollarwebsite/icons/smw_spinjump.png
new file mode 100644
index 00000000..c5c8a10d
Binary files /dev/null and b/thirtydollarwebsite/icons/smw_spinjump.png differ
diff --git a/thirtydollarwebsite/icons/smw_stomp.png b/thirtydollarwebsite/icons/smw_stomp.png
new file mode 100644
index 00000000..c5c0b2e5
Binary files /dev/null and b/thirtydollarwebsite/icons/smw_stomp.png differ
diff --git a/thirtydollarwebsite/icons/smw_stomp2.png b/thirtydollarwebsite/icons/smw_stomp2.png
new file mode 100644
index 00000000..8fe0ee24
Binary files /dev/null and b/thirtydollarwebsite/icons/smw_stomp2.png differ
diff --git a/thirtydollarwebsite/icons/smw_yoshi.png b/thirtydollarwebsite/icons/smw_yoshi.png
new file mode 100644
index 00000000..69241cb2
Binary files /dev/null and b/thirtydollarwebsite/icons/smw_yoshi.png differ
diff --git a/thirtydollarwebsite/icons/steve_oof.png b/thirtydollarwebsite/icons/steve_oof.png
new file mode 100644
index 00000000..66ae0301
Binary files /dev/null and b/thirtydollarwebsite/icons/steve_oof.png differ
diff --git a/thirtydollarwebsite/icons/stopposting.png b/thirtydollarwebsite/icons/stopposting.png
new file mode 100644
index 00000000..e3eb70e4
Binary files /dev/null and b/thirtydollarwebsite/icons/stopposting.png differ
diff --git a/thirtydollarwebsite/icons/subaluwa.png b/thirtydollarwebsite/icons/subaluwa.png
new file mode 100644
index 00000000..dec707b6
Binary files /dev/null and b/thirtydollarwebsite/icons/subaluwa.png differ
diff --git a/thirtydollarwebsite/icons/tab_actions.png b/thirtydollarwebsite/icons/tab_actions.png
new file mode 100644
index 00000000..4d286cc6
Binary files /dev/null and b/thirtydollarwebsite/icons/tab_actions.png differ
diff --git a/thirtydollarwebsite/icons/tab_decorations.png b/thirtydollarwebsite/icons/tab_decorations.png
new file mode 100644
index 00000000..335f68bc
Binary files /dev/null and b/thirtydollarwebsite/icons/tab_decorations.png differ
diff --git a/thirtydollarwebsite/icons/tab_rooms.png b/thirtydollarwebsite/icons/tab_rooms.png
new file mode 100644
index 00000000..74cf4268
Binary files /dev/null and b/thirtydollarwebsite/icons/tab_rooms.png differ
diff --git a/thirtydollarwebsite/icons/tab_rows.png b/thirtydollarwebsite/icons/tab_rows.png
new file mode 100644
index 00000000..4187c802
Binary files /dev/null and b/thirtydollarwebsite/icons/tab_rows.png differ
diff --git a/thirtydollarwebsite/icons/tab_sounds.png b/thirtydollarwebsite/icons/tab_sounds.png
new file mode 100644
index 00000000..25ecacdd
Binary files /dev/null and b/thirtydollarwebsite/icons/tab_sounds.png differ
diff --git a/thirtydollarwebsite/icons/taiko_don.png b/thirtydollarwebsite/icons/taiko_don.png
new file mode 100644
index 00000000..7752eb3e
Binary files /dev/null and b/thirtydollarwebsite/icons/taiko_don.png differ
diff --git a/thirtydollarwebsite/icons/taiko_ka.png b/thirtydollarwebsite/icons/taiko_ka.png
new file mode 100644
index 00000000..d6543b36
Binary files /dev/null and b/thirtydollarwebsite/icons/taiko_ka.png differ
diff --git a/thirtydollarwebsite/icons/taunt.png b/thirtydollarwebsite/icons/taunt.png
new file mode 100644
index 00000000..29692a53
Binary files /dev/null and b/thirtydollarwebsite/icons/taunt.png differ
diff --git a/thirtydollarwebsite/icons/terraria_axe.png b/thirtydollarwebsite/icons/terraria_axe.png
new file mode 100644
index 00000000..92ad4e14
Binary files /dev/null and b/thirtydollarwebsite/icons/terraria_axe.png differ
diff --git a/thirtydollarwebsite/icons/terraria_guitar.png b/thirtydollarwebsite/icons/terraria_guitar.png
new file mode 100644
index 00000000..1d21dd87
Binary files /dev/null and b/thirtydollarwebsite/icons/terraria_guitar.png differ
diff --git a/thirtydollarwebsite/icons/terraria_pot.png b/thirtydollarwebsite/icons/terraria_pot.png
new file mode 100644
index 00000000..20a0de6c
Binary files /dev/null and b/thirtydollarwebsite/icons/terraria_pot.png differ
diff --git a/thirtydollarwebsite/icons/terraria_reforge.png b/thirtydollarwebsite/icons/terraria_reforge.png
new file mode 100644
index 00000000..7d56412b
Binary files /dev/null and b/thirtydollarwebsite/icons/terraria_reforge.png differ
diff --git a/thirtydollarwebsite/icons/terraria_star.png b/thirtydollarwebsite/icons/terraria_star.png
new file mode 100644
index 00000000..41d468b3
Binary files /dev/null and b/thirtydollarwebsite/icons/terraria_star.png differ
diff --git a/thirtydollarwebsite/icons/tf2_crit.png b/thirtydollarwebsite/icons/tf2_crit.png
new file mode 100644
index 00000000..2e2fc267
Binary files /dev/null and b/thirtydollarwebsite/icons/tf2_crit.png differ
diff --git a/thirtydollarwebsite/icons/thwomp.png b/thirtydollarwebsite/icons/thwomp.png
new file mode 100644
index 00000000..5a53a001
Binary files /dev/null and b/thirtydollarwebsite/icons/thwomp.png differ
diff --git a/thirtydollarwebsite/icons/toby.png b/thirtydollarwebsite/icons/toby.png
new file mode 100644
index 00000000..056a9cfa
Binary files /dev/null and b/thirtydollarwebsite/icons/toby.png differ
diff --git a/thirtydollarwebsite/icons/tonk.png b/thirtydollarwebsite/icons/tonk.png
new file mode 100644
index 00000000..a121f53d
Binary files /dev/null and b/thirtydollarwebsite/icons/tonk.png differ
diff --git a/thirtydollarwebsite/icons/ultrainstinct.png b/thirtydollarwebsite/icons/ultrainstinct.png
new file mode 100644
index 00000000..336a6e4a
Binary files /dev/null and b/thirtydollarwebsite/icons/ultrainstinct.png differ
diff --git a/thirtydollarwebsite/icons/undertale_crack.png b/thirtydollarwebsite/icons/undertale_crack.png
new file mode 100644
index 00000000..efe5bea3
Binary files /dev/null and b/thirtydollarwebsite/icons/undertale_crack.png differ
diff --git a/thirtydollarwebsite/icons/undertale_encounter.png b/thirtydollarwebsite/icons/undertale_encounter.png
new file mode 100644
index 00000000..11f8758e
Binary files /dev/null and b/thirtydollarwebsite/icons/undertale_encounter.png differ
diff --git a/thirtydollarwebsite/icons/undertale_hit.png b/thirtydollarwebsite/icons/undertale_hit.png
new file mode 100644
index 00000000..e6cb1ffe
Binary files /dev/null and b/thirtydollarwebsite/icons/undertale_hit.png differ
diff --git a/thirtydollarwebsite/icons/vvvvvv_checkpoint.png b/thirtydollarwebsite/icons/vvvvvv_checkpoint.png
new file mode 100644
index 00000000..00bd1be7
Binary files /dev/null and b/thirtydollarwebsite/icons/vvvvvv_checkpoint.png differ
diff --git a/thirtydollarwebsite/icons/vvvvvv_flash.png b/thirtydollarwebsite/icons/vvvvvv_flash.png
new file mode 100644
index 00000000..c6193512
Binary files /dev/null and b/thirtydollarwebsite/icons/vvvvvv_flash.png differ
diff --git a/thirtydollarwebsite/icons/vvvvvv_flip.png b/thirtydollarwebsite/icons/vvvvvv_flip.png
new file mode 100644
index 00000000..c17e50e3
Binary files /dev/null and b/thirtydollarwebsite/icons/vvvvvv_flip.png differ
diff --git a/thirtydollarwebsite/icons/vvvvvv_hurt.png b/thirtydollarwebsite/icons/vvvvvv_hurt.png
new file mode 100644
index 00000000..bcf8f34f
Binary files /dev/null and b/thirtydollarwebsite/icons/vvvvvv_hurt.png differ
diff --git a/thirtydollarwebsite/icons/whatsapp.png b/thirtydollarwebsite/icons/whatsapp.png
new file mode 100644
index 00000000..4c0744ce
Binary files /dev/null and b/thirtydollarwebsite/icons/whatsapp.png differ
diff --git a/thirtydollarwebsite/icons/whipcrack.png b/thirtydollarwebsite/icons/whipcrack.png
new file mode 100644
index 00000000..0d0bdc13
Binary files /dev/null and b/thirtydollarwebsite/icons/whipcrack.png differ
diff --git a/thirtydollarwebsite/icons/yahoo.png b/thirtydollarwebsite/icons/yahoo.png
new file mode 100644
index 00000000..3f46c755
Binary files /dev/null and b/thirtydollarwebsite/icons/yahoo.png differ
diff --git a/thirtydollarwebsite/icons/yoda.png b/thirtydollarwebsite/icons/yoda.png
new file mode 100644
index 00000000..7b109efb
Binary files /dev/null and b/thirtydollarwebsite/icons/yoda.png differ
diff --git a/thirtydollarwebsite/index.html b/thirtydollarwebsite/index.html
new file mode 100644
index 00000000..99f529d0
--- /dev/null
+++ b/thirtydollarwebsite/index.html
@@ -0,0 +1,401 @@
+
+
+
+
+
DON'T YOU LECTURE ME WITH YOUR THIRTY DOLLAR WEBSITE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
DON'T YOU LECTURE ME WITH YOUR THIRTY DOLLAR WEBSITE
+
+
+
+
+
+
+
Sounds
+
+
+
+
+
Left click to add sound
Right click to preview
+
+
+
+
+
+
+
Actions
+
+
+
+
+
Left click to add action
+
+
+
+
+
+
+
+
+
+
Sequence
+
+ Left click to remove
+ Right click to preview
+ Shift click to clone
+ Scroll to change pitch
+ Ctrl+scroll to change volume
+
+
+
+
+
+
+
+
+
Selected section: None
+
+
+ Ctrl+Click to select a section
+ Ctrl+Up/Down to change section
+ Ctrl+D to deselect
+
+
Sounds will be added to the end of the selected section, and playback will begin from the beginning of it. You can pin these section controls from the settings.
+
+
+
+
+
+
+
+
+
+
+
#thirtydollarwebsite creations on:
+
+
+
+
+
+
+
+ NEW: 12 new sounds for all your particle accelerator needs
+
Check out my other silly projects over at gdcolon.com
+
+
+
+
Created by Colon :
+
I own pretty much nothing on this site please don't kill me
+
+
+
+ Settings
+ Shortcuts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/thirtydollarwebsite/sounds.json b/thirtydollarwebsite/sounds.json
new file mode 100644
index 00000000..352a16d4
--- /dev/null
+++ b/thirtydollarwebsite/sounds.json
@@ -0,0 +1,222 @@
+[
+ { "id": "_pause", "img": "empty", "name": "Silence", "source": "", "tags": ["note", "percussion"] },
+ { "id": "boom", "name": "Vine Boom", "source": "", "tags": ["percussion"] },
+ { "id": "bruh", "name": "Bruh Sound Effect #2", "source": "" },
+ { "id": "bong", "name": "Bong", "source": "Taco Bell", "tags": ["note"] },
+ { "id": "skeleton", "emoji": "💀", "name": "Skeleton", "source": "Minecraft" },
+ { "id": "clap", "emoji": "👏", "name": "Reverb Clap", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "dog", "emoji": "🐶", "name": "what the dog doin", "source": "TonyBakerComedy" },
+ { "id": "cave", "emoji": "👽", "name": "Cave Noise", "source": "Minecraft" },
+ { "id": "bell", "emoji": "🔔", "name": "Bell", "source": "", "tags": ["note"] },
+ { "id": "boink", "emoji": "💢", "name": "Boink", "source": "Rhythm Heaven" },
+ { "id": "fart", "emoji": "💨", "name": "Reverb Fart", "source": "", "tags": ["percussion"] },
+ { "id": "error", "emoji": "🚫", "name": "Error", "source": "Windows XP", "tags": ["note"] },
+
+ { "id": "kaching", "emoji": "💰", "name": "Kaching", "source": "" },
+ { "id": "bonk", "emoji": "🏏", "name": "Bonk", "source": "", "tags": ["percussion"] },
+ { "id": "bleep", "emoji": "🤬", "name": "Bleep", "source": "", "tags": ["note"] },
+ { "id": "alarm", "emoji": "🚨", "name": "Alarm", "source": "" },
+ { "id": "buzzer", "name": "Incorrect Buzzer", "source": "", "tags": ["note"] },
+ { "id": "aah", "emoji": "🅰", "name": "aah", "source": "Zaytoven" },
+ { "id": "e", "name": "E", "source": "Unknown" },
+ { "id": "eight", "name": "8", "source": "The Stanley Parable" },
+ { "id": "pizza", "emoji": "🍕", "name": "ayo the pizza here", "source": "CalebCity" },
+ { "id": "augh", "emoji": "🐡", "name": "Pufferfish Augh", "source": "Yummyboy" },
+ { "id": "quack", "emoji": "🦆", "name": "Quack", "source": "Mac OS" },
+ { "id": "honk", "emoji": "🦢", "name": "Honk", "source": "Untitled Goose Game" },
+
+ { "id": "samsung", "emoji": "📲", "name": "Skyline Notification", "source": "Samsung" },
+ { "id": "morningflower", "emoji": "🌄", "name": "Morning Flower", "source": "Samsung" },
+ { "id": "shatter", "name": "Glass Shatter", "source": "", "tags": ["percussion"] },
+ { "id": "noice", "emoji": "👌", "name": "Noice Click", "source": "Michael Rosen", "tags": ["percussion"] },
+ { "id": "slap", "emoji": "🖐", "name": "Slap", "source": "", "tags": ["percussion"] },
+ { "id": "krabs", "emoji": "🦀", "name": "Mr. Krabs Walking", "source": "SpongeBob SquarePants" },
+ { "id": "wowowow", "emoji": "🚬", "name": "wowowowow", "source": "Kill Bill" },
+ { "id": "whatsapp", "name": "Whistle Notification", "source": "Samsung" },
+ { "id": "recordscratch", "emoji": "💿", "name": "Record Scratch", "source": "" },
+ { "id": "pianoriff", "emoji": "🎹", "name": "Piano Riff", "source": "iPhone" },
+ { "id": "alert", "emoji": "❗", "name": "Alert", "source": "Metal Gear Solid" },
+ { "id": "slip", "name": "Slip", "source": "" },
+
+ { "id": "tada", "emoji": "🎉", "name": "Tada", "source": "Windows 3.1" },
+ { "id": "pan", "name": "Frying Pan", "source": "Scott the Woz", "tags": ["percussion"] },
+ { "id": "gun", "name": "Gun Reload", "source": "" },
+ { "id": "hitmarker", "name": "Hitmarker", "source": "Call of Duty", "tags": ["percussion"] },
+ { "id": "suspense", "emoji": "😱", "name": "Suspense", "source": "" },
+ { "id": "yawn", "emoji": "🥱", "name": "Goofy Yawn", "source": ".mlkey(?)" },
+ { "id": "nerdhorn", "emoji": "🤓", "name": "Old Car Horn", "source": "iPhone" },
+ { "id": "babylaugh", "emoji": "👶", "name": "Baby Laugh", "source": "" },
+ { "id": "airhorn", "name": "Airhorn", "source": "", "tags": ["note"] },
+ { "id": "metalpipe", "name": "Metal Pipe", "source": "" },
+ { "id": "boing", "name": "Boing", "source": "" },
+ { "id": "explosion", "name": "Explosion", "source": "DELTARUNE" },
+
+ { "id": "dodgeball", "name": "Dodgeball", "source": "", "tags": ["percussion"] },
+ { "id": "whipcrack", "name": "Whip Crack", "source": "", "tags": ["percussion"] },
+ { "id": "boowomp", "name": "Boowomp", "source": "SpongeBob SquarePants" },
+ { "id": "taiko_don", "name": "Don", "source": "Taiko no Tatsujin", "tags": ["percussion"] },
+ { "id": "taiko_ka", "name": "Ka", "source": "Taiko no Tatsujin", "tags": ["percussion"] },
+ { "id": "puyo", "name": "Puyo", "source": "Puyo Puyo", "tags": ["note"] },
+ { "id": "robtopphone", "name": "Xylophone", "source": "", "tags": ["note"] },
+ { "id": "waterphone", "emoji": "🎻", "name": "Waterphone", "source": "Hell's Kitchen" },
+ { "id": "slapbass", "emoji": "🎸", "name": "Slap Bass", "source": "", "tags": ["note"] },
+ { "id": "dimrainsynth", "name": "Synth", "source": "", "tags": ["note"] },
+ { "id": "hoenn", "name": "Hoenn Trumpet", "source": "Pokémon", "tags": ["note"] },
+ { "id": "zunpet", "emoji": "🎺", "name": "ZUNpet", "source": "Touhou", "tags": ["note"] },
+
+ { "id": "oof", "name": "Oof", "source": "Roblox" },
+ { "id": "steve_oof", "name": "Oof", "source": "Minecraft" },
+ { "id": "gnome", "name": "Gnome", "source": "You've Been Gnomed" },
+ { "id": "nope", "name": "nope.avi", "source": "Team Fortress 2" },
+ { "id": "tf2_crit", "name": "Critical Hit", "source": "Team Fortress 2", "tags": ["percussion"] },
+ { "id": "mrbeast", "name": "MR BEAST", "source": "Freshy Kanal" },
+ { "id": "obama", "name": "BARACK OBAMA", "source": "ERB", "tags": ["note"] },
+ { "id": "op", "name": "op", "source": "Psy" },
+ { "id": "SLAM", "name": "SLAM!", "source": "Space Jam" },
+ { "id": "stopposting", "name": "Ding", "source": "biggayrapper" },
+ { "id": "21", "name": "21", "source": "DREHYPEMSU" },
+ { "id": "americano", "name": "dog dancing we no speak americano", "source": "Unknown" },
+
+ { "id": "taunt", "name": "Taunt", "source": "Pizza Tower", "tags": ["note"] },
+ { "id": "subaluwa", "name": "Subaluwa", "source": "Ed, Edd n Eddy" },
+ { "id": "necoarc", "name": "Neco-Arc", "source": "Carnival Phantasm" },
+ { "id": "samurai", "name": "Samurai Techno", "source": "Rhythm Doctor", "tags": ["note"] },
+ { "id": "flipnote", "name": "Frog", "source": "Flipnote Studio" },
+ { "id": "familyguy", "name": "Family Guy Intro", "source": "Family Guy", "tags": ["note"] },
+ { "id": "pingas", "name": "PINGAS", "source": "AoStH" },
+ { "id": "yoda", "name": "Lego Yoda Death", "source": "LEGO Star Wars" },
+ { "id": "hehehehaw", "name": "HE HE HE HAW", "source": "Clash Royale" },
+ { "id": "ultrainstinct", "name": "Ultra Instinct", "source": "Dragon Ball Z", "tags": ["note"] },
+ { "id": "granddad", "name": "GRAND DAD", "source": "Vargskelethor Joel" },
+ { "id": "morshu", "name": "Morshu MMMMMMM", "source": "Link: The Faces of Evil", "tags": ["note"] },
+
+ { "id": "smw_coin", "name": "Coin", "source": "Super Mario World" },
+ { "id": "smw_1up", "name": "1-Up", "source": "Super Mario World" },
+ { "id": "smw_spinjump", "name": "Spin Jump", "source": "Super Mario World" },
+ { "id": "smw_stomp2", "name": "Stomp", "source": "Super Mario World", "tags": ["percussion"] },
+ { "id": "smw_kick", "name": "Kick", "source": "Super Mario World" },
+ { "id": "smw_stomp", "name": "Boss Stomp", "source": "Super Mario World" },
+ { "id": "yahoo", "name": "Long Jump", "source": "Super Mario 64" },
+ { "id": "sm64_hurt", "name": "Damage", "source": "Super Mario 64" },
+ { "id": "thwomp", "name": "Thwomp", "source": "Super Mario 64" },
+ { "id": "bup", "name": "Bup", "source": "Mario Kart 64", "tags": ["note"] },
+ { "id": "sm64_painting", "name": "Painting", "source": "Super Mario 64", "tags": ["percussion"] },
+ { "id": "smm_scream", "name": "Scream", "source": "Super Mario Maker" },
+
+ { "id": "mariopaint_mario", "name": "Mario", "source": "Mario Paint", "tags": ["note"] },
+ { "id": "mariopaint_luigi", "name": "Steel Drum", "source": "Super Mario World", "tags": ["note"] },
+ { "id": "smw_yoshi", "name": "Yoshi", "source": "Mario Paint" },
+ { "id": "mariopaint_star", "name": "Star", "source": "Mario Paint", "tags": ["note"] },
+ { "id": "mariopaint_flower", "name": "Flower", "source": "Mario Paint", "tags": ["note"] },
+ { "id": "mariopaint_gameboy", "name": "Gameboy", "source": "Mario Paint", "tags": ["note"] },
+ { "id": "mariopaint_dog", "name": "Dog", "source": "Mario Paint", "tags": ["note"] },
+ { "id": "mariopaint_cat", "name": "Cat", "source": "Mario Paint", "tags": ["note"] },
+ { "id": "mariopaint_swan", "name": "Swan", "source": "Mario Paint", "tags": ["note"] },
+ { "id": "mariopaint_baby", "name": "Baby", "source": "Mario Paint", "tags": ["note"] },
+ { "id": "mariopaint_plane", "name": "Plane", "source": "Mario Paint", "tags": ["note"] },
+ { "id": "mariopaint_car", "name": "Car", "source": "Mario Paint", "tags": ["note"] },
+
+ { "id": "shaker", "name": "Shaker", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "kick", "emoji": "🥁", "name": "Kick", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "hammer", "name": "Hammer", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "tom", "emoji": "🪘", "name": "Tom Drum", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "sidestick", "name": "Sidestick", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "ride2", "name": "Ride", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "buttonpop", "name": "Pop", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "skipshot", "name": "Skipshot", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "otto_on", "name": "Otto - Enabled", "source": "Rhythm Doctor" },
+ { "id": "otto_off", "name": "Otto - Disabled", "source": "Rhythm Doctor" },
+ { "id": "otto_happy", "name": "Otto - Happy", "source": "Rhythm Doctor" },
+ { "id": "otto_stress", "name": "Otto - Stressed", "source": "A Dance of Fire And Ice" },
+
+ { "id": "tab_sounds", "name": "Sounds Tab", "source": "Rhythm Doctor", "tags": ["note"] },
+ { "id": "tab_rows", "name": "Rows Tab", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "tab_actions", "name": "Actions Tab", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "tab_decorations", "name": "Decorations Tab", "source": "Rhythm Doctor" },
+ { "id": "tab_rooms", "name": "Rooms Tab", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "preecho", "name": "Pre-echo Clap", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "tonk", "name": "Tonk", "source": "Rhythm Doctor" },
+ { "id": "rdclap", "name": "Clap Hit", "source": "Rhythm Doctor", "tags": ["percussion"] },
+ { "id": "rdmistake", "name": "Mistake", "source": "Rhythm Doctor" },
+ { "id": "midspin", "name": "Midspin Clack", "source": "A Dance of Fire and Ice", "tags": ["percussion"] },
+ { "id": "adofai_fire", "name": "Fire Midspin", "source": "A Dance of Fire and Ice", "tags": ["percussion"] },
+ { "id": "adofai_ice", "name": "Ice Midspin", "source": "A Dance of Fire and Ice", "tags": ["percussion"] },
+
+ { "id": "adofaikick", "name": "Kick", "source": "A Dance of Fire and Ice", "tags": ["percussion"] },
+ { "id": "adofaicymbal", "name": "Level Complete", "source": "A Dance of Fire and Ice", "tags": ["percussion"] },
+ { "id": "cowbell", "name": "Cowbell", "source": "Rhythm Heaven", "tags": ["percussion"] },
+ { "id": "karateman_throw", "name": "Karate Man - Toss", "source": "Rhythm Heaven", "tags": ["percussion"] },
+ { "id": "karateman_offbeat", "name": "Karate Man - Offbeat Toss", "source": "Rhythm Heaven", "tags": ["percussion"] },
+ { "id": "karateman_hit", "name": "Karate Man - Hit", "source": "Rhythm Heaven", "tags": ["percussion"] },
+ { "id": "karateman_bulb", "name": "Karate Man - Bulb", "source": "Rhythm Heaven", "tags": ["percussion"] },
+ { "id": "ook", "name": "Ook", "source": "Rhythm Heaven" },
+ { "id": "choruskid", "name": "Chorus Kid", "source": "Rhythm Heaven", "tags": ["note"] },
+ { "id": "builttoscale", "name": "Widget", "source": "Rhythm Heaven", "tags": ["note"] },
+ { "id": "perfectfail", "name": "Perfect Failed", "source": "Rhythm Heaven" },
+ { "id": "skillstar", "emoji": "🌟", "name": "Skill Star", "source": "Rhythm Heaven" },
+
+ { "id": "fnf_left", "name": "Left", "source": "Friday Night Funkin'", "tags": ["note"] },
+ { "id": "fnf_down", "name": "Down", "source": "Friday Night Funkin'", "tags": ["note"] },
+ { "id": "fnf_up", "name": "Up", "source": "Friday Night Funkin'", "tags": ["note"] },
+ { "id": "fnf_right", "name": "Right", "source": "Friday Night Funkin'", "tags": ["note"] },
+ { "id": "fnf_death", "name": "Fail", "source": "Friday Night Funkin'" },
+ { "id": "gdcrash", "name": "Crash", "source": "Geometry Dash" },
+ { "id": "gdcrash_orbs", "name": "Crash + Orbs", "source": "Geometry Dash" },
+ { "id": "gd_coin", "name": "Secret Coin", "source": "Geometry Dash" },
+ { "id": "gd_orbs", "name": "Mana Orbs", "source": "Geometry Dash" },
+ { "id": "gd_diamonds", "name": "Diamond", "source": "Geometry Dash" },
+ { "id": "gd_quit", "name": "Quit", "source": "Geometry Dash", "tags": ["note"] },
+ { "id": "bwomp", "name": "Blast Processing", "source": "Geometry Dash", "tags": ["note"] },
+
+ { "id": "undertale_hit", "name": "Damage", "source": "UNDERTALE", "tags": ["percussion"] },
+ { "id": "undertale_crack", "name": "Game Over", "source": "UNDERTALE", "tags": ["percussion"] },
+ { "id": "sans_voice", "name": "sans", "source": "UNDERTALE" },
+ { "id": "megalovania", "name": "Megalovania", "source": "UNDERTALE" },
+ { "id": "megalovania_note", "emoji": "🦴", "name": "Megalovania Note", "source": "UNDERTALE", "tags": ["note"] },
+ { "id": "undertale_encounter", "name": "Encounter", "source": "UNDERTALE" },
+ { "id": "toby", "name": "Bark", "source": "UNDERTALE" },
+ { "id": "gaster", "name": "Vanish", "source": "UNDERTALE" },
+ { "id": "lancersplat", "name": "Lancer Splat", "source": "DELTARUNE", "tags": ["percussion"] },
+ { "id": "isaac_hurt", "name": "Damage", "source": "The Binding of Isaac: Rebirth" },
+ { "id": "isaac_dead", "name": "Death", "source": "The Binding of Isaac: Rebirth" },
+ { "id": "isaac_mantle", "name": "Holy Mantle", "source": "The Binding of Isaac: Repentance", "tags": ["percussion"] },
+
+ { "id": "BABA", "name": "MOVE", "source": "Baba Is You" },
+ { "id": "YOU", "name": "RULE", "source": "Baba Is You", "tags": ["note"] },
+ { "id": "DEFEAT", "name": "DEFEAT", "source": "Baba Is You", "tags": ["percussion"] },
+ { "id": "vvvvvv_flip", "name": "Flip", "source": "VVVVVV" },
+ { "id": "vvvvvv_hurt", "name": "Sad", "source": "VVVVVV" },
+ { "id": "vvvvvv_checkpoint", "name": "Checkpoint", "source": "VVVVVV" },
+ { "id": "vvvvvv_flash", "name": "Flash", "source": "VVVVVV", "tags": ["percussion"] },
+ { "id": "terraria_star", "name": "Magic", "source": "Terraria" },
+ { "id": "terraria_pot", "name": "Shatter", "source": "Terraria" },
+ { "id": "terraria_reforge", "name": "Reforge", "source": "Terraria" },
+ { "id": "terraria_guitar", "name": "Stellar Tune", "source": "Terraria", "tags": ["note"] },
+ { "id": "terraria_axe", "name": "The Axe", "source": "Terraria", "tags": ["note"] },
+
+ { "id": "celeste_dash", "name": "Dash", "source": "Celeste", "tags": ["percussion"] },
+ { "id": "celeste_death", "name": "Death", "source": "Celeste", "tags": ["percussion"] },
+ { "id": "celeste_spring", "name": "Spring", "source": "Celeste", "tags": ["percussion"] },
+ { "id": "celeste_diamond", "name": "Dash Gem", "source": "Celeste", "tags": ["percussion"] },
+ { "id": "amogus_emergency", "name": "Emergency Meeting", "source": "Among Us", "tags": ["note"] },
+ { "id": "amogus_kill", "name": "Kill", "source": "Among Us", "tags": ["percussion"] },
+ { "id": "amongus", "name": "AMONG US", "source": "Unknown" },
+ { "id": "amongdrip", "name": "Among Drip", "source": "Leonz", "tags": ["note"] },
+ { "id": "amogus", "name": "Amogus", "source": "Unknown" },
+ { "id": "minecraft_explosion", "name": "Explosion", "source": "Minecraft" },
+ { "id": "minecraft_anvil", "name": "Anvil", "source": "Minecraft" },
+ { "id": "minecraft_bell", "name": "Bell", "source": "Minecraft", "tags": ["note"] },
+
+ { "id": "noteblock_harp", "name": "Note Block - Harp", "source": "Minecraft", "tags": ["note"] },
+ { "id": "noteblock_bass", "name": "Note Block - Bass", "source": "Minecraft", "tags": ["note"] },
+ { "id": "noteblock_snare", "name": "Note Block - Snare", "source": "Minecraft", "tags": ["percussion"] },
+ { "id": "noteblock_click", "name": "Note Block - Hat", "source": "Minecraft", "tags": ["percussion"] },
+ { "id": "noteblock_bell", "name": "Note Block - Bell", "source": "Minecraft", "tags": ["note"] },
+ { "id": "noteblock_banjo", "name": "Note Block - Banjo", "source": "Minecraft", "tags": ["note"] },
+ { "id": "noteblock_bit", "name": "Note Block - Bit", "source": "Minecraft", "tags": ["note"] },
+ { "id": "noteblock_chime", "name": "Note Block - Chime", "source": "Minecraft", "tags": ["note"] },
+ { "id": "noteblock_xylophone", "name": "Note Block - Xylophone", "source": "Minecraft", "tags": ["note"] },
+ { "id": "noteblock_guitar", "name": "Note Block - Guitar", "source": "Minecraft", "tags": ["note"] },
+ { "id": "noteblock_flute", "name": "Note Block - Flute", "source": "Minecraft", "tags": ["note"] },
+ { "id": "noteblock_pling", "name": "Note Block - Pling", "source": "Minecraft", "tags": ["note"] }
+]
\ No newline at end of file
diff --git a/thirtydollarwebsite/sounds/21.wav b/thirtydollarwebsite/sounds/21.wav
new file mode 100644
index 00000000..a607f239
Binary files /dev/null and b/thirtydollarwebsite/sounds/21.wav differ
diff --git a/thirtydollarwebsite/sounds/BABA.wav b/thirtydollarwebsite/sounds/BABA.wav
new file mode 100644
index 00000000..54d6bb3c
Binary files /dev/null and b/thirtydollarwebsite/sounds/BABA.wav differ
diff --git a/thirtydollarwebsite/sounds/DEFEAT.wav b/thirtydollarwebsite/sounds/DEFEAT.wav
new file mode 100644
index 00000000..3286e4a3
Binary files /dev/null and b/thirtydollarwebsite/sounds/DEFEAT.wav differ
diff --git a/thirtydollarwebsite/sounds/SLAM.wav b/thirtydollarwebsite/sounds/SLAM.wav
new file mode 100644
index 00000000..b30fcdad
Binary files /dev/null and b/thirtydollarwebsite/sounds/SLAM.wav differ
diff --git a/thirtydollarwebsite/sounds/YOU.wav b/thirtydollarwebsite/sounds/YOU.wav
new file mode 100644
index 00000000..e33dff3f
Binary files /dev/null and b/thirtydollarwebsite/sounds/YOU.wav differ
diff --git a/thirtydollarwebsite/sounds/_pause.wav b/thirtydollarwebsite/sounds/_pause.wav
new file mode 100644
index 00000000..5c55217d
Binary files /dev/null and b/thirtydollarwebsite/sounds/_pause.wav differ
diff --git a/thirtydollarwebsite/sounds/aah.wav b/thirtydollarwebsite/sounds/aah.wav
new file mode 100644
index 00000000..ecc5903e
Binary files /dev/null and b/thirtydollarwebsite/sounds/aah.wav differ
diff --git a/thirtydollarwebsite/sounds/adofai_fire.wav b/thirtydollarwebsite/sounds/adofai_fire.wav
new file mode 100644
index 00000000..af9746cd
Binary files /dev/null and b/thirtydollarwebsite/sounds/adofai_fire.wav differ
diff --git a/thirtydollarwebsite/sounds/adofai_ice.wav b/thirtydollarwebsite/sounds/adofai_ice.wav
new file mode 100644
index 00000000..8e0cbff1
Binary files /dev/null and b/thirtydollarwebsite/sounds/adofai_ice.wav differ
diff --git a/thirtydollarwebsite/sounds/adofaicymbal.wav b/thirtydollarwebsite/sounds/adofaicymbal.wav
new file mode 100644
index 00000000..66261ad5
Binary files /dev/null and b/thirtydollarwebsite/sounds/adofaicymbal.wav differ
diff --git a/thirtydollarwebsite/sounds/adofaikick.wav b/thirtydollarwebsite/sounds/adofaikick.wav
new file mode 100644
index 00000000..d5ad3577
Binary files /dev/null and b/thirtydollarwebsite/sounds/adofaikick.wav differ
diff --git a/thirtydollarwebsite/sounds/airhorn.wav b/thirtydollarwebsite/sounds/airhorn.wav
new file mode 100644
index 00000000..d01b1753
Binary files /dev/null and b/thirtydollarwebsite/sounds/airhorn.wav differ
diff --git a/thirtydollarwebsite/sounds/alarm.wav b/thirtydollarwebsite/sounds/alarm.wav
new file mode 100644
index 00000000..cbad48a5
Binary files /dev/null and b/thirtydollarwebsite/sounds/alarm.wav differ
diff --git a/thirtydollarwebsite/sounds/alert.wav b/thirtydollarwebsite/sounds/alert.wav
new file mode 100644
index 00000000..c6c98892
Binary files /dev/null and b/thirtydollarwebsite/sounds/alert.wav differ
diff --git a/thirtydollarwebsite/sounds/americano.wav b/thirtydollarwebsite/sounds/americano.wav
new file mode 100644
index 00000000..acd08537
Binary files /dev/null and b/thirtydollarwebsite/sounds/americano.wav differ
diff --git a/thirtydollarwebsite/sounds/amogus.wav b/thirtydollarwebsite/sounds/amogus.wav
new file mode 100644
index 00000000..5fa96b2e
Binary files /dev/null and b/thirtydollarwebsite/sounds/amogus.wav differ
diff --git a/thirtydollarwebsite/sounds/amogus_emergency.wav b/thirtydollarwebsite/sounds/amogus_emergency.wav
new file mode 100644
index 00000000..8fce2bf5
Binary files /dev/null and b/thirtydollarwebsite/sounds/amogus_emergency.wav differ
diff --git a/thirtydollarwebsite/sounds/amogus_kill.wav b/thirtydollarwebsite/sounds/amogus_kill.wav
new file mode 100644
index 00000000..7cf3e0f7
Binary files /dev/null and b/thirtydollarwebsite/sounds/amogus_kill.wav differ
diff --git a/thirtydollarwebsite/sounds/amongdrip.wav b/thirtydollarwebsite/sounds/amongdrip.wav
new file mode 100644
index 00000000..40f12e27
Binary files /dev/null and b/thirtydollarwebsite/sounds/amongdrip.wav differ
diff --git a/thirtydollarwebsite/sounds/amongus.wav b/thirtydollarwebsite/sounds/amongus.wav
new file mode 100644
index 00000000..82de2ce5
Binary files /dev/null and b/thirtydollarwebsite/sounds/amongus.wav differ
diff --git a/thirtydollarwebsite/sounds/augh.wav b/thirtydollarwebsite/sounds/augh.wav
new file mode 100644
index 00000000..4f75da8b
Binary files /dev/null and b/thirtydollarwebsite/sounds/augh.wav differ
diff --git a/thirtydollarwebsite/sounds/babylaugh.wav b/thirtydollarwebsite/sounds/babylaugh.wav
new file mode 100644
index 00000000..6eb35a70
Binary files /dev/null and b/thirtydollarwebsite/sounds/babylaugh.wav differ
diff --git a/thirtydollarwebsite/sounds/bell.wav b/thirtydollarwebsite/sounds/bell.wav
new file mode 100644
index 00000000..dcd0a1db
Binary files /dev/null and b/thirtydollarwebsite/sounds/bell.wav differ
diff --git a/thirtydollarwebsite/sounds/bleep.wav b/thirtydollarwebsite/sounds/bleep.wav
new file mode 100644
index 00000000..1ca535fc
Binary files /dev/null and b/thirtydollarwebsite/sounds/bleep.wav differ
diff --git a/thirtydollarwebsite/sounds/boing.wav b/thirtydollarwebsite/sounds/boing.wav
new file mode 100644
index 00000000..2d3e1984
Binary files /dev/null and b/thirtydollarwebsite/sounds/boing.wav differ
diff --git a/thirtydollarwebsite/sounds/boink(1).wav b/thirtydollarwebsite/sounds/boink(1).wav
new file mode 100644
index 00000000..59d56749
Binary files /dev/null and b/thirtydollarwebsite/sounds/boink(1).wav differ
diff --git a/thirtydollarwebsite/sounds/boink.wav b/thirtydollarwebsite/sounds/boink.wav
new file mode 100644
index 00000000..59d56749
Binary files /dev/null and b/thirtydollarwebsite/sounds/boink.wav differ
diff --git a/thirtydollarwebsite/sounds/bong.wav b/thirtydollarwebsite/sounds/bong.wav
new file mode 100644
index 00000000..1b6ce4c8
Binary files /dev/null and b/thirtydollarwebsite/sounds/bong.wav differ
diff --git a/thirtydollarwebsite/sounds/bonk.wav b/thirtydollarwebsite/sounds/bonk.wav
new file mode 100644
index 00000000..3df64fd0
Binary files /dev/null and b/thirtydollarwebsite/sounds/bonk.wav differ
diff --git a/thirtydollarwebsite/sounds/boom.wav b/thirtydollarwebsite/sounds/boom.wav
new file mode 100644
index 00000000..7dfebb12
Binary files /dev/null and b/thirtydollarwebsite/sounds/boom.wav differ
diff --git a/thirtydollarwebsite/sounds/boowomp.wav b/thirtydollarwebsite/sounds/boowomp.wav
new file mode 100644
index 00000000..90060173
Binary files /dev/null and b/thirtydollarwebsite/sounds/boowomp.wav differ
diff --git a/thirtydollarwebsite/sounds/bruh.wav b/thirtydollarwebsite/sounds/bruh.wav
new file mode 100644
index 00000000..45542f13
Binary files /dev/null and b/thirtydollarwebsite/sounds/bruh.wav differ
diff --git a/thirtydollarwebsite/sounds/builttoscale.wav b/thirtydollarwebsite/sounds/builttoscale.wav
new file mode 100644
index 00000000..5d5f4133
Binary files /dev/null and b/thirtydollarwebsite/sounds/builttoscale.wav differ
diff --git a/thirtydollarwebsite/sounds/bup.wav b/thirtydollarwebsite/sounds/bup.wav
new file mode 100644
index 00000000..258fa95e
Binary files /dev/null and b/thirtydollarwebsite/sounds/bup.wav differ
diff --git a/thirtydollarwebsite/sounds/buttonpop.wav b/thirtydollarwebsite/sounds/buttonpop.wav
new file mode 100644
index 00000000..2cd78271
Binary files /dev/null and b/thirtydollarwebsite/sounds/buttonpop.wav differ
diff --git a/thirtydollarwebsite/sounds/buzzer.wav b/thirtydollarwebsite/sounds/buzzer.wav
new file mode 100644
index 00000000..2e29cdc8
Binary files /dev/null and b/thirtydollarwebsite/sounds/buzzer.wav differ
diff --git a/thirtydollarwebsite/sounds/bwomp.wav b/thirtydollarwebsite/sounds/bwomp.wav
new file mode 100644
index 00000000..911decde
Binary files /dev/null and b/thirtydollarwebsite/sounds/bwomp.wav differ
diff --git a/thirtydollarwebsite/sounds/cave.wav b/thirtydollarwebsite/sounds/cave.wav
new file mode 100644
index 00000000..c43be6b7
Binary files /dev/null and b/thirtydollarwebsite/sounds/cave.wav differ
diff --git a/thirtydollarwebsite/sounds/celeste_dash.wav b/thirtydollarwebsite/sounds/celeste_dash.wav
new file mode 100644
index 00000000..4dbad3f5
Binary files /dev/null and b/thirtydollarwebsite/sounds/celeste_dash.wav differ
diff --git a/thirtydollarwebsite/sounds/celeste_death.wav b/thirtydollarwebsite/sounds/celeste_death.wav
new file mode 100644
index 00000000..7faefa0d
Binary files /dev/null and b/thirtydollarwebsite/sounds/celeste_death.wav differ
diff --git a/thirtydollarwebsite/sounds/celeste_diamond.wav b/thirtydollarwebsite/sounds/celeste_diamond.wav
new file mode 100644
index 00000000..99b5a1d5
Binary files /dev/null and b/thirtydollarwebsite/sounds/celeste_diamond.wav differ
diff --git a/thirtydollarwebsite/sounds/celeste_spring.wav b/thirtydollarwebsite/sounds/celeste_spring.wav
new file mode 100644
index 00000000..a5e2b6d2
Binary files /dev/null and b/thirtydollarwebsite/sounds/celeste_spring.wav differ
diff --git a/thirtydollarwebsite/sounds/choruskid.wav b/thirtydollarwebsite/sounds/choruskid.wav
new file mode 100644
index 00000000..7d6c0165
Binary files /dev/null and b/thirtydollarwebsite/sounds/choruskid.wav differ
diff --git a/thirtydollarwebsite/sounds/clap.wav b/thirtydollarwebsite/sounds/clap.wav
new file mode 100644
index 00000000..bc30e645
Binary files /dev/null and b/thirtydollarwebsite/sounds/clap.wav differ
diff --git a/thirtydollarwebsite/sounds/cowbell.wav b/thirtydollarwebsite/sounds/cowbell.wav
new file mode 100644
index 00000000..39a6aee2
Binary files /dev/null and b/thirtydollarwebsite/sounds/cowbell.wav differ
diff --git a/thirtydollarwebsite/sounds/dimrainsynth.wav b/thirtydollarwebsite/sounds/dimrainsynth.wav
new file mode 100644
index 00000000..36f37de2
Binary files /dev/null and b/thirtydollarwebsite/sounds/dimrainsynth.wav differ
diff --git a/thirtydollarwebsite/sounds/dodgeball.wav b/thirtydollarwebsite/sounds/dodgeball.wav
new file mode 100644
index 00000000..ec950e34
Binary files /dev/null and b/thirtydollarwebsite/sounds/dodgeball.wav differ
diff --git a/thirtydollarwebsite/sounds/dog.wav b/thirtydollarwebsite/sounds/dog.wav
new file mode 100644
index 00000000..489cb29c
Binary files /dev/null and b/thirtydollarwebsite/sounds/dog.wav differ
diff --git a/thirtydollarwebsite/sounds/e.wav b/thirtydollarwebsite/sounds/e.wav
new file mode 100644
index 00000000..b2ec2529
Binary files /dev/null and b/thirtydollarwebsite/sounds/e.wav differ
diff --git a/thirtydollarwebsite/sounds/eight.wav b/thirtydollarwebsite/sounds/eight.wav
new file mode 100644
index 00000000..19f51831
Binary files /dev/null and b/thirtydollarwebsite/sounds/eight.wav differ
diff --git a/thirtydollarwebsite/sounds/error.wav b/thirtydollarwebsite/sounds/error.wav
new file mode 100644
index 00000000..df684959
Binary files /dev/null and b/thirtydollarwebsite/sounds/error.wav differ
diff --git a/thirtydollarwebsite/sounds/explosion.wav b/thirtydollarwebsite/sounds/explosion.wav
new file mode 100644
index 00000000..ca3310dd
Binary files /dev/null and b/thirtydollarwebsite/sounds/explosion.wav differ
diff --git a/thirtydollarwebsite/sounds/familyguy.wav b/thirtydollarwebsite/sounds/familyguy.wav
new file mode 100644
index 00000000..430f7032
Binary files /dev/null and b/thirtydollarwebsite/sounds/familyguy.wav differ
diff --git a/thirtydollarwebsite/sounds/fart.wav b/thirtydollarwebsite/sounds/fart.wav
new file mode 100644
index 00000000..0947e59c
Binary files /dev/null and b/thirtydollarwebsite/sounds/fart.wav differ
diff --git a/thirtydollarwebsite/sounds/flipnote.wav b/thirtydollarwebsite/sounds/flipnote.wav
new file mode 100644
index 00000000..0126707c
Binary files /dev/null and b/thirtydollarwebsite/sounds/flipnote.wav differ
diff --git a/thirtydollarwebsite/sounds/fnf_death.wav b/thirtydollarwebsite/sounds/fnf_death.wav
new file mode 100644
index 00000000..89312eda
Binary files /dev/null and b/thirtydollarwebsite/sounds/fnf_death.wav differ
diff --git a/thirtydollarwebsite/sounds/fnf_down.wav b/thirtydollarwebsite/sounds/fnf_down.wav
new file mode 100644
index 00000000..0ecaea89
Binary files /dev/null and b/thirtydollarwebsite/sounds/fnf_down.wav differ
diff --git a/thirtydollarwebsite/sounds/fnf_left.wav b/thirtydollarwebsite/sounds/fnf_left.wav
new file mode 100644
index 00000000..e867244e
Binary files /dev/null and b/thirtydollarwebsite/sounds/fnf_left.wav differ
diff --git a/thirtydollarwebsite/sounds/fnf_right.wav b/thirtydollarwebsite/sounds/fnf_right.wav
new file mode 100644
index 00000000..6221e12a
Binary files /dev/null and b/thirtydollarwebsite/sounds/fnf_right.wav differ
diff --git a/thirtydollarwebsite/sounds/fnf_up.wav b/thirtydollarwebsite/sounds/fnf_up.wav
new file mode 100644
index 00000000..15e90d42
Binary files /dev/null and b/thirtydollarwebsite/sounds/fnf_up.wav differ
diff --git a/thirtydollarwebsite/sounds/gaster.wav b/thirtydollarwebsite/sounds/gaster.wav
new file mode 100644
index 00000000..6f9b5341
Binary files /dev/null and b/thirtydollarwebsite/sounds/gaster.wav differ
diff --git a/thirtydollarwebsite/sounds/gd_coin.wav b/thirtydollarwebsite/sounds/gd_coin.wav
new file mode 100644
index 00000000..90a1b91c
Binary files /dev/null and b/thirtydollarwebsite/sounds/gd_coin.wav differ
diff --git a/thirtydollarwebsite/sounds/gd_diamonds.wav b/thirtydollarwebsite/sounds/gd_diamonds.wav
new file mode 100644
index 00000000..64eef3f5
Binary files /dev/null and b/thirtydollarwebsite/sounds/gd_diamonds.wav differ
diff --git a/thirtydollarwebsite/sounds/gd_orbs.wav b/thirtydollarwebsite/sounds/gd_orbs.wav
new file mode 100644
index 00000000..f08bb5ee
Binary files /dev/null and b/thirtydollarwebsite/sounds/gd_orbs.wav differ
diff --git a/thirtydollarwebsite/sounds/gd_quit.wav b/thirtydollarwebsite/sounds/gd_quit.wav
new file mode 100644
index 00000000..dcda0deb
Binary files /dev/null and b/thirtydollarwebsite/sounds/gd_quit.wav differ
diff --git a/thirtydollarwebsite/sounds/gdcrash.wav b/thirtydollarwebsite/sounds/gdcrash.wav
new file mode 100644
index 00000000..671389da
Binary files /dev/null and b/thirtydollarwebsite/sounds/gdcrash.wav differ
diff --git a/thirtydollarwebsite/sounds/gdcrash_orbs.wav b/thirtydollarwebsite/sounds/gdcrash_orbs.wav
new file mode 100644
index 00000000..8e095bce
Binary files /dev/null and b/thirtydollarwebsite/sounds/gdcrash_orbs.wav differ
diff --git a/thirtydollarwebsite/sounds/gnome.wav b/thirtydollarwebsite/sounds/gnome.wav
new file mode 100644
index 00000000..5a83cb07
Binary files /dev/null and b/thirtydollarwebsite/sounds/gnome.wav differ
diff --git a/thirtydollarwebsite/sounds/granddad.wav b/thirtydollarwebsite/sounds/granddad.wav
new file mode 100644
index 00000000..4d13e261
Binary files /dev/null and b/thirtydollarwebsite/sounds/granddad.wav differ
diff --git a/thirtydollarwebsite/sounds/gun.wav b/thirtydollarwebsite/sounds/gun.wav
new file mode 100644
index 00000000..fe2f5bd9
Binary files /dev/null and b/thirtydollarwebsite/sounds/gun.wav differ
diff --git a/thirtydollarwebsite/sounds/hammer.wav b/thirtydollarwebsite/sounds/hammer.wav
new file mode 100644
index 00000000..b4bfae45
Binary files /dev/null and b/thirtydollarwebsite/sounds/hammer.wav differ
diff --git a/thirtydollarwebsite/sounds/hehehehaw.wav b/thirtydollarwebsite/sounds/hehehehaw.wav
new file mode 100644
index 00000000..684fe0af
Binary files /dev/null and b/thirtydollarwebsite/sounds/hehehehaw.wav differ
diff --git a/thirtydollarwebsite/sounds/hitmarker.wav b/thirtydollarwebsite/sounds/hitmarker.wav
new file mode 100644
index 00000000..2f0f9e29
Binary files /dev/null and b/thirtydollarwebsite/sounds/hitmarker.wav differ
diff --git a/thirtydollarwebsite/sounds/hoenn.wav b/thirtydollarwebsite/sounds/hoenn.wav
new file mode 100644
index 00000000..48017af6
Binary files /dev/null and b/thirtydollarwebsite/sounds/hoenn.wav differ
diff --git a/thirtydollarwebsite/sounds/honk.wav b/thirtydollarwebsite/sounds/honk.wav
new file mode 100644
index 00000000..31450ca5
Binary files /dev/null and b/thirtydollarwebsite/sounds/honk.wav differ
diff --git a/thirtydollarwebsite/sounds/isaac_dead.wav b/thirtydollarwebsite/sounds/isaac_dead.wav
new file mode 100644
index 00000000..5c49067b
Binary files /dev/null and b/thirtydollarwebsite/sounds/isaac_dead.wav differ
diff --git a/thirtydollarwebsite/sounds/isaac_hurt.wav b/thirtydollarwebsite/sounds/isaac_hurt.wav
new file mode 100644
index 00000000..c423784f
Binary files /dev/null and b/thirtydollarwebsite/sounds/isaac_hurt.wav differ
diff --git a/thirtydollarwebsite/sounds/isaac_mantle.wav b/thirtydollarwebsite/sounds/isaac_mantle.wav
new file mode 100644
index 00000000..b8dccf79
Binary files /dev/null and b/thirtydollarwebsite/sounds/isaac_mantle.wav differ
diff --git a/thirtydollarwebsite/sounds/kaching.wav b/thirtydollarwebsite/sounds/kaching.wav
new file mode 100644
index 00000000..7a96ca20
Binary files /dev/null and b/thirtydollarwebsite/sounds/kaching.wav differ
diff --git a/thirtydollarwebsite/sounds/karateman_bulb.wav b/thirtydollarwebsite/sounds/karateman_bulb.wav
new file mode 100644
index 00000000..e357c83d
Binary files /dev/null and b/thirtydollarwebsite/sounds/karateman_bulb.wav differ
diff --git a/thirtydollarwebsite/sounds/karateman_hit.wav b/thirtydollarwebsite/sounds/karateman_hit.wav
new file mode 100644
index 00000000..3ad28a39
Binary files /dev/null and b/thirtydollarwebsite/sounds/karateman_hit.wav differ
diff --git a/thirtydollarwebsite/sounds/karateman_offbeat.wav b/thirtydollarwebsite/sounds/karateman_offbeat.wav
new file mode 100644
index 00000000..38c03691
Binary files /dev/null and b/thirtydollarwebsite/sounds/karateman_offbeat.wav differ
diff --git a/thirtydollarwebsite/sounds/karateman_throw.wav b/thirtydollarwebsite/sounds/karateman_throw.wav
new file mode 100644
index 00000000..5334c896
Binary files /dev/null and b/thirtydollarwebsite/sounds/karateman_throw.wav differ
diff --git a/thirtydollarwebsite/sounds/kick.wav b/thirtydollarwebsite/sounds/kick.wav
new file mode 100644
index 00000000..ad11cf5f
Binary files /dev/null and b/thirtydollarwebsite/sounds/kick.wav differ
diff --git a/thirtydollarwebsite/sounds/krabs.wav b/thirtydollarwebsite/sounds/krabs.wav
new file mode 100644
index 00000000..c37eb645
Binary files /dev/null and b/thirtydollarwebsite/sounds/krabs.wav differ
diff --git a/thirtydollarwebsite/sounds/lancersplat.wav b/thirtydollarwebsite/sounds/lancersplat.wav
new file mode 100644
index 00000000..58b152ad
Binary files /dev/null and b/thirtydollarwebsite/sounds/lancersplat.wav differ
diff --git a/thirtydollarwebsite/sounds/mariopaint_baby.wav b/thirtydollarwebsite/sounds/mariopaint_baby.wav
new file mode 100644
index 00000000..02701b1a
Binary files /dev/null and b/thirtydollarwebsite/sounds/mariopaint_baby.wav differ
diff --git a/thirtydollarwebsite/sounds/mariopaint_car.wav b/thirtydollarwebsite/sounds/mariopaint_car.wav
new file mode 100644
index 00000000..64c1186a
Binary files /dev/null and b/thirtydollarwebsite/sounds/mariopaint_car.wav differ
diff --git a/thirtydollarwebsite/sounds/mariopaint_cat.wav b/thirtydollarwebsite/sounds/mariopaint_cat.wav
new file mode 100644
index 00000000..25100328
Binary files /dev/null and b/thirtydollarwebsite/sounds/mariopaint_cat.wav differ
diff --git a/thirtydollarwebsite/sounds/mariopaint_dog.wav b/thirtydollarwebsite/sounds/mariopaint_dog.wav
new file mode 100644
index 00000000..199902cb
Binary files /dev/null and b/thirtydollarwebsite/sounds/mariopaint_dog.wav differ
diff --git a/thirtydollarwebsite/sounds/mariopaint_flower.wav b/thirtydollarwebsite/sounds/mariopaint_flower.wav
new file mode 100644
index 00000000..d87bad97
Binary files /dev/null and b/thirtydollarwebsite/sounds/mariopaint_flower.wav differ
diff --git a/thirtydollarwebsite/sounds/mariopaint_gameboy.wav b/thirtydollarwebsite/sounds/mariopaint_gameboy.wav
new file mode 100644
index 00000000..1b76958e
Binary files /dev/null and b/thirtydollarwebsite/sounds/mariopaint_gameboy.wav differ
diff --git a/thirtydollarwebsite/sounds/mariopaint_luigi.wav b/thirtydollarwebsite/sounds/mariopaint_luigi.wav
new file mode 100644
index 00000000..069b7894
Binary files /dev/null and b/thirtydollarwebsite/sounds/mariopaint_luigi.wav differ
diff --git a/thirtydollarwebsite/sounds/mariopaint_mario.wav b/thirtydollarwebsite/sounds/mariopaint_mario.wav
new file mode 100644
index 00000000..3f24780b
Binary files /dev/null and b/thirtydollarwebsite/sounds/mariopaint_mario.wav differ
diff --git a/thirtydollarwebsite/sounds/mariopaint_plane.wav b/thirtydollarwebsite/sounds/mariopaint_plane.wav
new file mode 100644
index 00000000..dc7f3229
Binary files /dev/null and b/thirtydollarwebsite/sounds/mariopaint_plane.wav differ
diff --git a/thirtydollarwebsite/sounds/mariopaint_star.wav b/thirtydollarwebsite/sounds/mariopaint_star.wav
new file mode 100644
index 00000000..7a828cd4
Binary files /dev/null and b/thirtydollarwebsite/sounds/mariopaint_star.wav differ
diff --git a/thirtydollarwebsite/sounds/mariopaint_swan.wav b/thirtydollarwebsite/sounds/mariopaint_swan.wav
new file mode 100644
index 00000000..6f793c20
Binary files /dev/null and b/thirtydollarwebsite/sounds/mariopaint_swan.wav differ
diff --git a/thirtydollarwebsite/sounds/megalovania.wav b/thirtydollarwebsite/sounds/megalovania.wav
new file mode 100644
index 00000000..21d27f11
Binary files /dev/null and b/thirtydollarwebsite/sounds/megalovania.wav differ
diff --git a/thirtydollarwebsite/sounds/megalovania_note.wav b/thirtydollarwebsite/sounds/megalovania_note.wav
new file mode 100644
index 00000000..cad7af1f
Binary files /dev/null and b/thirtydollarwebsite/sounds/megalovania_note.wav differ
diff --git a/thirtydollarwebsite/sounds/metalpipe.wav b/thirtydollarwebsite/sounds/metalpipe.wav
new file mode 100644
index 00000000..d6ff0a12
Binary files /dev/null and b/thirtydollarwebsite/sounds/metalpipe.wav differ
diff --git a/thirtydollarwebsite/sounds/midspin.wav b/thirtydollarwebsite/sounds/midspin.wav
new file mode 100644
index 00000000..ceca2162
Binary files /dev/null and b/thirtydollarwebsite/sounds/midspin.wav differ
diff --git a/thirtydollarwebsite/sounds/minecraft_anvil.wav b/thirtydollarwebsite/sounds/minecraft_anvil.wav
new file mode 100644
index 00000000..9cdbde43
Binary files /dev/null and b/thirtydollarwebsite/sounds/minecraft_anvil.wav differ
diff --git a/thirtydollarwebsite/sounds/minecraft_bell.wav b/thirtydollarwebsite/sounds/minecraft_bell.wav
new file mode 100644
index 00000000..52813103
Binary files /dev/null and b/thirtydollarwebsite/sounds/minecraft_bell.wav differ
diff --git a/thirtydollarwebsite/sounds/minecraft_explosion.wav b/thirtydollarwebsite/sounds/minecraft_explosion.wav
new file mode 100644
index 00000000..1f2c8344
Binary files /dev/null and b/thirtydollarwebsite/sounds/minecraft_explosion.wav differ
diff --git a/thirtydollarwebsite/sounds/morningflower.wav b/thirtydollarwebsite/sounds/morningflower.wav
new file mode 100644
index 00000000..69d8fdaa
Binary files /dev/null and b/thirtydollarwebsite/sounds/morningflower.wav differ
diff --git a/thirtydollarwebsite/sounds/morshu.wav b/thirtydollarwebsite/sounds/morshu.wav
new file mode 100644
index 00000000..3205864b
Binary files /dev/null and b/thirtydollarwebsite/sounds/morshu.wav differ
diff --git a/thirtydollarwebsite/sounds/mrbeast.wav b/thirtydollarwebsite/sounds/mrbeast.wav
new file mode 100644
index 00000000..c249de12
Binary files /dev/null and b/thirtydollarwebsite/sounds/mrbeast.wav differ
diff --git a/thirtydollarwebsite/sounds/necoarc.wav b/thirtydollarwebsite/sounds/necoarc.wav
new file mode 100644
index 00000000..e2b72bd9
Binary files /dev/null and b/thirtydollarwebsite/sounds/necoarc.wav differ
diff --git a/thirtydollarwebsite/sounds/nerdhorn.wav b/thirtydollarwebsite/sounds/nerdhorn.wav
new file mode 100644
index 00000000..9d36aa6b
Binary files /dev/null and b/thirtydollarwebsite/sounds/nerdhorn.wav differ
diff --git a/thirtydollarwebsite/sounds/noice.wav b/thirtydollarwebsite/sounds/noice.wav
new file mode 100644
index 00000000..7d7dfacf
Binary files /dev/null and b/thirtydollarwebsite/sounds/noice.wav differ
diff --git a/thirtydollarwebsite/sounds/nope.wav b/thirtydollarwebsite/sounds/nope.wav
new file mode 100644
index 00000000..aa69491c
Binary files /dev/null and b/thirtydollarwebsite/sounds/nope.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_banjo.wav b/thirtydollarwebsite/sounds/noteblock_banjo.wav
new file mode 100644
index 00000000..3309337b
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_banjo.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_bass.wav b/thirtydollarwebsite/sounds/noteblock_bass.wav
new file mode 100644
index 00000000..0680f510
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_bass.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_bell.wav b/thirtydollarwebsite/sounds/noteblock_bell.wav
new file mode 100644
index 00000000..f8086f94
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_bell.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_bit.wav b/thirtydollarwebsite/sounds/noteblock_bit.wav
new file mode 100644
index 00000000..f190414c
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_bit.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_chime.wav b/thirtydollarwebsite/sounds/noteblock_chime.wav
new file mode 100644
index 00000000..1453a634
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_chime.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_click.wav b/thirtydollarwebsite/sounds/noteblock_click.wav
new file mode 100644
index 00000000..5d8e05a6
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_click.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_flute.wav b/thirtydollarwebsite/sounds/noteblock_flute.wav
new file mode 100644
index 00000000..30f94959
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_flute.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_guitar.wav b/thirtydollarwebsite/sounds/noteblock_guitar.wav
new file mode 100644
index 00000000..277545ca
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_guitar.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_harp.wav b/thirtydollarwebsite/sounds/noteblock_harp.wav
new file mode 100644
index 00000000..32eebc74
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_harp.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_pling.wav b/thirtydollarwebsite/sounds/noteblock_pling.wav
new file mode 100644
index 00000000..0cae501f
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_pling.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_snare.wav b/thirtydollarwebsite/sounds/noteblock_snare.wav
new file mode 100644
index 00000000..438af4f0
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_snare.wav differ
diff --git a/thirtydollarwebsite/sounds/noteblock_xylophone.wav b/thirtydollarwebsite/sounds/noteblock_xylophone.wav
new file mode 100644
index 00000000..0f0e9cee
Binary files /dev/null and b/thirtydollarwebsite/sounds/noteblock_xylophone.wav differ
diff --git a/thirtydollarwebsite/sounds/obama.wav b/thirtydollarwebsite/sounds/obama.wav
new file mode 100644
index 00000000..a44cfb4f
Binary files /dev/null and b/thirtydollarwebsite/sounds/obama.wav differ
diff --git a/thirtydollarwebsite/sounds/oof.wav b/thirtydollarwebsite/sounds/oof.wav
new file mode 100644
index 00000000..60b9f8f3
Binary files /dev/null and b/thirtydollarwebsite/sounds/oof.wav differ
diff --git a/thirtydollarwebsite/sounds/ook.wav b/thirtydollarwebsite/sounds/ook.wav
new file mode 100644
index 00000000..e0415cd1
Binary files /dev/null and b/thirtydollarwebsite/sounds/ook.wav differ
diff --git a/thirtydollarwebsite/sounds/op.wav b/thirtydollarwebsite/sounds/op.wav
new file mode 100644
index 00000000..d8a70808
Binary files /dev/null and b/thirtydollarwebsite/sounds/op.wav differ
diff --git a/thirtydollarwebsite/sounds/otto_happy.wav b/thirtydollarwebsite/sounds/otto_happy.wav
new file mode 100644
index 00000000..d45099c7
Binary files /dev/null and b/thirtydollarwebsite/sounds/otto_happy.wav differ
diff --git a/thirtydollarwebsite/sounds/otto_off.wav b/thirtydollarwebsite/sounds/otto_off.wav
new file mode 100644
index 00000000..0a60738c
Binary files /dev/null and b/thirtydollarwebsite/sounds/otto_off.wav differ
diff --git a/thirtydollarwebsite/sounds/otto_on.wav b/thirtydollarwebsite/sounds/otto_on.wav
new file mode 100644
index 00000000..21079136
Binary files /dev/null and b/thirtydollarwebsite/sounds/otto_on.wav differ
diff --git a/thirtydollarwebsite/sounds/otto_stress.wav b/thirtydollarwebsite/sounds/otto_stress.wav
new file mode 100644
index 00000000..94d9a9a3
Binary files /dev/null and b/thirtydollarwebsite/sounds/otto_stress.wav differ
diff --git a/thirtydollarwebsite/sounds/pan.wav b/thirtydollarwebsite/sounds/pan.wav
new file mode 100644
index 00000000..f08cfd8c
Binary files /dev/null and b/thirtydollarwebsite/sounds/pan.wav differ
diff --git a/thirtydollarwebsite/sounds/perfectfail.wav b/thirtydollarwebsite/sounds/perfectfail.wav
new file mode 100644
index 00000000..9d7a28ad
Binary files /dev/null and b/thirtydollarwebsite/sounds/perfectfail.wav differ
diff --git a/thirtydollarwebsite/sounds/pianoriff.wav b/thirtydollarwebsite/sounds/pianoriff.wav
new file mode 100644
index 00000000..21679d3a
Binary files /dev/null and b/thirtydollarwebsite/sounds/pianoriff.wav differ
diff --git a/thirtydollarwebsite/sounds/pingas.wav b/thirtydollarwebsite/sounds/pingas.wav
new file mode 100644
index 00000000..069b98e6
Binary files /dev/null and b/thirtydollarwebsite/sounds/pingas.wav differ
diff --git a/thirtydollarwebsite/sounds/pizza.wav b/thirtydollarwebsite/sounds/pizza.wav
new file mode 100644
index 00000000..b5b5523b
Binary files /dev/null and b/thirtydollarwebsite/sounds/pizza.wav differ
diff --git a/thirtydollarwebsite/sounds/preecho.wav b/thirtydollarwebsite/sounds/preecho.wav
new file mode 100644
index 00000000..8d6e553e
Binary files /dev/null and b/thirtydollarwebsite/sounds/preecho.wav differ
diff --git a/thirtydollarwebsite/sounds/puyo.wav b/thirtydollarwebsite/sounds/puyo.wav
new file mode 100644
index 00000000..2082f7a7
Binary files /dev/null and b/thirtydollarwebsite/sounds/puyo.wav differ
diff --git a/thirtydollarwebsite/sounds/quack.wav b/thirtydollarwebsite/sounds/quack.wav
new file mode 100644
index 00000000..0b92f5b3
Binary files /dev/null and b/thirtydollarwebsite/sounds/quack.wav differ
diff --git a/thirtydollarwebsite/sounds/rdclap.wav b/thirtydollarwebsite/sounds/rdclap.wav
new file mode 100644
index 00000000..f6700534
Binary files /dev/null and b/thirtydollarwebsite/sounds/rdclap.wav differ
diff --git a/thirtydollarwebsite/sounds/rdmistake.wav b/thirtydollarwebsite/sounds/rdmistake.wav
new file mode 100644
index 00000000..65eaeab7
Binary files /dev/null and b/thirtydollarwebsite/sounds/rdmistake.wav differ
diff --git a/thirtydollarwebsite/sounds/recordscratch.wav b/thirtydollarwebsite/sounds/recordscratch.wav
new file mode 100644
index 00000000..48ddbaa1
Binary files /dev/null and b/thirtydollarwebsite/sounds/recordscratch.wav differ
diff --git a/thirtydollarwebsite/sounds/ride2.wav b/thirtydollarwebsite/sounds/ride2.wav
new file mode 100644
index 00000000..572de4e8
Binary files /dev/null and b/thirtydollarwebsite/sounds/ride2.wav differ
diff --git a/thirtydollarwebsite/sounds/robtopphone.wav b/thirtydollarwebsite/sounds/robtopphone.wav
new file mode 100644
index 00000000..85c5f2f5
Binary files /dev/null and b/thirtydollarwebsite/sounds/robtopphone.wav differ
diff --git a/thirtydollarwebsite/sounds/samsung.wav b/thirtydollarwebsite/sounds/samsung.wav
new file mode 100644
index 00000000..43e5b42e
Binary files /dev/null and b/thirtydollarwebsite/sounds/samsung.wav differ
diff --git a/thirtydollarwebsite/sounds/samurai.wav b/thirtydollarwebsite/sounds/samurai.wav
new file mode 100644
index 00000000..2360235a
Binary files /dev/null and b/thirtydollarwebsite/sounds/samurai.wav differ
diff --git a/thirtydollarwebsite/sounds/sans_voice.wav b/thirtydollarwebsite/sounds/sans_voice.wav
new file mode 100644
index 00000000..542f1e8b
Binary files /dev/null and b/thirtydollarwebsite/sounds/sans_voice.wav differ
diff --git a/thirtydollarwebsite/sounds/shaker.wav b/thirtydollarwebsite/sounds/shaker.wav
new file mode 100644
index 00000000..e113227d
Binary files /dev/null and b/thirtydollarwebsite/sounds/shaker.wav differ
diff --git a/thirtydollarwebsite/sounds/shatter.wav b/thirtydollarwebsite/sounds/shatter.wav
new file mode 100644
index 00000000..aa92b874
Binary files /dev/null and b/thirtydollarwebsite/sounds/shatter.wav differ
diff --git a/thirtydollarwebsite/sounds/sidestick.wav b/thirtydollarwebsite/sounds/sidestick.wav
new file mode 100644
index 00000000..0f3af78a
Binary files /dev/null and b/thirtydollarwebsite/sounds/sidestick.wav differ
diff --git a/thirtydollarwebsite/sounds/skeleton.wav b/thirtydollarwebsite/sounds/skeleton.wav
new file mode 100644
index 00000000..8c17b9a3
Binary files /dev/null and b/thirtydollarwebsite/sounds/skeleton.wav differ
diff --git a/thirtydollarwebsite/sounds/skillstar.wav b/thirtydollarwebsite/sounds/skillstar.wav
new file mode 100644
index 00000000..c5059b67
Binary files /dev/null and b/thirtydollarwebsite/sounds/skillstar.wav differ
diff --git a/thirtydollarwebsite/sounds/skipshot.wav b/thirtydollarwebsite/sounds/skipshot.wav
new file mode 100644
index 00000000..0b413217
Binary files /dev/null and b/thirtydollarwebsite/sounds/skipshot.wav differ
diff --git a/thirtydollarwebsite/sounds/slap.wav b/thirtydollarwebsite/sounds/slap.wav
new file mode 100644
index 00000000..e8baa068
Binary files /dev/null and b/thirtydollarwebsite/sounds/slap.wav differ
diff --git a/thirtydollarwebsite/sounds/slapbass.wav b/thirtydollarwebsite/sounds/slapbass.wav
new file mode 100644
index 00000000..b8084e05
Binary files /dev/null and b/thirtydollarwebsite/sounds/slapbass.wav differ
diff --git a/thirtydollarwebsite/sounds/slip.wav b/thirtydollarwebsite/sounds/slip.wav
new file mode 100644
index 00000000..1c7f2638
Binary files /dev/null and b/thirtydollarwebsite/sounds/slip.wav differ
diff --git a/thirtydollarwebsite/sounds/sm64_hurt.wav b/thirtydollarwebsite/sounds/sm64_hurt.wav
new file mode 100644
index 00000000..6017bbe1
Binary files /dev/null and b/thirtydollarwebsite/sounds/sm64_hurt.wav differ
diff --git a/thirtydollarwebsite/sounds/sm64_painting.wav b/thirtydollarwebsite/sounds/sm64_painting.wav
new file mode 100644
index 00000000..11812352
Binary files /dev/null and b/thirtydollarwebsite/sounds/sm64_painting.wav differ
diff --git a/thirtydollarwebsite/sounds/smm_scream.wav b/thirtydollarwebsite/sounds/smm_scream.wav
new file mode 100644
index 00000000..cb22d72d
Binary files /dev/null and b/thirtydollarwebsite/sounds/smm_scream.wav differ
diff --git a/thirtydollarwebsite/sounds/smw_1up.wav b/thirtydollarwebsite/sounds/smw_1up.wav
new file mode 100644
index 00000000..1fb8e1b9
Binary files /dev/null and b/thirtydollarwebsite/sounds/smw_1up.wav differ
diff --git a/thirtydollarwebsite/sounds/smw_coin.wav b/thirtydollarwebsite/sounds/smw_coin.wav
new file mode 100644
index 00000000..58b3df33
Binary files /dev/null and b/thirtydollarwebsite/sounds/smw_coin.wav differ
diff --git a/thirtydollarwebsite/sounds/smw_kick.wav b/thirtydollarwebsite/sounds/smw_kick.wav
new file mode 100644
index 00000000..2784180b
Binary files /dev/null and b/thirtydollarwebsite/sounds/smw_kick.wav differ
diff --git a/thirtydollarwebsite/sounds/smw_spinjump.wav b/thirtydollarwebsite/sounds/smw_spinjump.wav
new file mode 100644
index 00000000..5c1e3462
Binary files /dev/null and b/thirtydollarwebsite/sounds/smw_spinjump.wav differ
diff --git a/thirtydollarwebsite/sounds/smw_stomp.wav b/thirtydollarwebsite/sounds/smw_stomp.wav
new file mode 100644
index 00000000..2609a31b
Binary files /dev/null and b/thirtydollarwebsite/sounds/smw_stomp.wav differ
diff --git a/thirtydollarwebsite/sounds/smw_stomp2.wav b/thirtydollarwebsite/sounds/smw_stomp2.wav
new file mode 100644
index 00000000..fcbf9b1a
Binary files /dev/null and b/thirtydollarwebsite/sounds/smw_stomp2.wav differ
diff --git a/thirtydollarwebsite/sounds/smw_yoshi.wav b/thirtydollarwebsite/sounds/smw_yoshi.wav
new file mode 100644
index 00000000..d4b5029b
Binary files /dev/null and b/thirtydollarwebsite/sounds/smw_yoshi.wav differ
diff --git a/thirtydollarwebsite/sounds/steve_oof.wav b/thirtydollarwebsite/sounds/steve_oof.wav
new file mode 100644
index 00000000..97bb2546
Binary files /dev/null and b/thirtydollarwebsite/sounds/steve_oof.wav differ
diff --git a/thirtydollarwebsite/sounds/stopposting.wav b/thirtydollarwebsite/sounds/stopposting.wav
new file mode 100644
index 00000000..b1c54bf5
Binary files /dev/null and b/thirtydollarwebsite/sounds/stopposting.wav differ
diff --git a/thirtydollarwebsite/sounds/subaluwa.wav b/thirtydollarwebsite/sounds/subaluwa.wav
new file mode 100644
index 00000000..96772a80
Binary files /dev/null and b/thirtydollarwebsite/sounds/subaluwa.wav differ
diff --git a/thirtydollarwebsite/sounds/suspense.wav b/thirtydollarwebsite/sounds/suspense.wav
new file mode 100644
index 00000000..d909f09f
Binary files /dev/null and b/thirtydollarwebsite/sounds/suspense.wav differ
diff --git a/thirtydollarwebsite/sounds/tab_actions.wav b/thirtydollarwebsite/sounds/tab_actions.wav
new file mode 100644
index 00000000..01254c7f
Binary files /dev/null and b/thirtydollarwebsite/sounds/tab_actions.wav differ
diff --git a/thirtydollarwebsite/sounds/tab_decorations.wav b/thirtydollarwebsite/sounds/tab_decorations.wav
new file mode 100644
index 00000000..aa4c18e7
Binary files /dev/null and b/thirtydollarwebsite/sounds/tab_decorations.wav differ
diff --git a/thirtydollarwebsite/sounds/tab_rooms.wav b/thirtydollarwebsite/sounds/tab_rooms.wav
new file mode 100644
index 00000000..d620e065
Binary files /dev/null and b/thirtydollarwebsite/sounds/tab_rooms.wav differ
diff --git a/thirtydollarwebsite/sounds/tab_rows.wav b/thirtydollarwebsite/sounds/tab_rows.wav
new file mode 100644
index 00000000..be1b8bc6
Binary files /dev/null and b/thirtydollarwebsite/sounds/tab_rows.wav differ
diff --git a/thirtydollarwebsite/sounds/tab_sounds.wav b/thirtydollarwebsite/sounds/tab_sounds.wav
new file mode 100644
index 00000000..816acfd5
Binary files /dev/null and b/thirtydollarwebsite/sounds/tab_sounds.wav differ
diff --git a/thirtydollarwebsite/sounds/tada.wav b/thirtydollarwebsite/sounds/tada.wav
new file mode 100644
index 00000000..ebab47ec
Binary files /dev/null and b/thirtydollarwebsite/sounds/tada.wav differ
diff --git a/thirtydollarwebsite/sounds/taiko_don.wav b/thirtydollarwebsite/sounds/taiko_don.wav
new file mode 100644
index 00000000..889f6f72
Binary files /dev/null and b/thirtydollarwebsite/sounds/taiko_don.wav differ
diff --git a/thirtydollarwebsite/sounds/taiko_ka.wav b/thirtydollarwebsite/sounds/taiko_ka.wav
new file mode 100644
index 00000000..38788c93
Binary files /dev/null and b/thirtydollarwebsite/sounds/taiko_ka.wav differ
diff --git a/thirtydollarwebsite/sounds/taunt.wav b/thirtydollarwebsite/sounds/taunt.wav
new file mode 100644
index 00000000..38a562ab
Binary files /dev/null and b/thirtydollarwebsite/sounds/taunt.wav differ
diff --git a/thirtydollarwebsite/sounds/terraria_axe.wav b/thirtydollarwebsite/sounds/terraria_axe.wav
new file mode 100644
index 00000000..da4ca268
Binary files /dev/null and b/thirtydollarwebsite/sounds/terraria_axe.wav differ
diff --git a/thirtydollarwebsite/sounds/terraria_guitar.wav b/thirtydollarwebsite/sounds/terraria_guitar.wav
new file mode 100644
index 00000000..4a942c56
Binary files /dev/null and b/thirtydollarwebsite/sounds/terraria_guitar.wav differ
diff --git a/thirtydollarwebsite/sounds/terraria_pot.wav b/thirtydollarwebsite/sounds/terraria_pot.wav
new file mode 100644
index 00000000..cba9232e
Binary files /dev/null and b/thirtydollarwebsite/sounds/terraria_pot.wav differ
diff --git a/thirtydollarwebsite/sounds/terraria_reforge.wav b/thirtydollarwebsite/sounds/terraria_reforge.wav
new file mode 100644
index 00000000..49aa5ba5
Binary files /dev/null and b/thirtydollarwebsite/sounds/terraria_reforge.wav differ
diff --git a/thirtydollarwebsite/sounds/terraria_star.wav b/thirtydollarwebsite/sounds/terraria_star.wav
new file mode 100644
index 00000000..ab56844a
Binary files /dev/null and b/thirtydollarwebsite/sounds/terraria_star.wav differ
diff --git a/thirtydollarwebsite/sounds/tf2_crit.wav b/thirtydollarwebsite/sounds/tf2_crit.wav
new file mode 100644
index 00000000..b81bafda
Binary files /dev/null and b/thirtydollarwebsite/sounds/tf2_crit.wav differ
diff --git a/thirtydollarwebsite/sounds/thwomp.wav b/thirtydollarwebsite/sounds/thwomp.wav
new file mode 100644
index 00000000..339402a8
Binary files /dev/null and b/thirtydollarwebsite/sounds/thwomp.wav differ
diff --git a/thirtydollarwebsite/sounds/toby.wav b/thirtydollarwebsite/sounds/toby.wav
new file mode 100644
index 00000000..13e54cc9
Binary files /dev/null and b/thirtydollarwebsite/sounds/toby.wav differ
diff --git a/thirtydollarwebsite/sounds/tom.wav b/thirtydollarwebsite/sounds/tom.wav
new file mode 100644
index 00000000..709f3c7b
Binary files /dev/null and b/thirtydollarwebsite/sounds/tom.wav differ
diff --git a/thirtydollarwebsite/sounds/tonk.wav b/thirtydollarwebsite/sounds/tonk.wav
new file mode 100644
index 00000000..37c5bb39
Binary files /dev/null and b/thirtydollarwebsite/sounds/tonk.wav differ
diff --git a/thirtydollarwebsite/sounds/ultrainstinct.wav b/thirtydollarwebsite/sounds/ultrainstinct.wav
new file mode 100644
index 00000000..edf2546b
Binary files /dev/null and b/thirtydollarwebsite/sounds/ultrainstinct.wav differ
diff --git a/thirtydollarwebsite/sounds/undertale_crack.wav b/thirtydollarwebsite/sounds/undertale_crack.wav
new file mode 100644
index 00000000..7d0b6a64
Binary files /dev/null and b/thirtydollarwebsite/sounds/undertale_crack.wav differ
diff --git a/thirtydollarwebsite/sounds/undertale_encounter.wav b/thirtydollarwebsite/sounds/undertale_encounter.wav
new file mode 100644
index 00000000..333d51d7
Binary files /dev/null and b/thirtydollarwebsite/sounds/undertale_encounter.wav differ
diff --git a/thirtydollarwebsite/sounds/undertale_hit.wav b/thirtydollarwebsite/sounds/undertale_hit.wav
new file mode 100644
index 00000000..b08409de
Binary files /dev/null and b/thirtydollarwebsite/sounds/undertale_hit.wav differ
diff --git a/thirtydollarwebsite/sounds/vvvvvv_checkpoint.wav b/thirtydollarwebsite/sounds/vvvvvv_checkpoint.wav
new file mode 100644
index 00000000..9af06846
Binary files /dev/null and b/thirtydollarwebsite/sounds/vvvvvv_checkpoint.wav differ
diff --git a/thirtydollarwebsite/sounds/vvvvvv_flash.wav b/thirtydollarwebsite/sounds/vvvvvv_flash.wav
new file mode 100644
index 00000000..0ebb2778
Binary files /dev/null and b/thirtydollarwebsite/sounds/vvvvvv_flash.wav differ
diff --git a/thirtydollarwebsite/sounds/vvvvvv_flip.wav b/thirtydollarwebsite/sounds/vvvvvv_flip.wav
new file mode 100644
index 00000000..899eaf14
Binary files /dev/null and b/thirtydollarwebsite/sounds/vvvvvv_flip.wav differ
diff --git a/thirtydollarwebsite/sounds/vvvvvv_hurt.wav b/thirtydollarwebsite/sounds/vvvvvv_hurt.wav
new file mode 100644
index 00000000..fc4e7cb9
Binary files /dev/null and b/thirtydollarwebsite/sounds/vvvvvv_hurt.wav differ
diff --git a/thirtydollarwebsite/sounds/waterphone.wav b/thirtydollarwebsite/sounds/waterphone.wav
new file mode 100644
index 00000000..d5281909
Binary files /dev/null and b/thirtydollarwebsite/sounds/waterphone.wav differ
diff --git a/thirtydollarwebsite/sounds/whatsapp.wav b/thirtydollarwebsite/sounds/whatsapp.wav
new file mode 100644
index 00000000..03b90bae
Binary files /dev/null and b/thirtydollarwebsite/sounds/whatsapp.wav differ
diff --git a/thirtydollarwebsite/sounds/whipcrack.wav b/thirtydollarwebsite/sounds/whipcrack.wav
new file mode 100644
index 00000000..0443bc66
Binary files /dev/null and b/thirtydollarwebsite/sounds/whipcrack.wav differ
diff --git a/thirtydollarwebsite/sounds/wowowow.wav b/thirtydollarwebsite/sounds/wowowow.wav
new file mode 100644
index 00000000..9faa67c6
Binary files /dev/null and b/thirtydollarwebsite/sounds/wowowow.wav differ
diff --git a/thirtydollarwebsite/sounds/yahoo.wav b/thirtydollarwebsite/sounds/yahoo.wav
new file mode 100644
index 00000000..f62d8ec0
Binary files /dev/null and b/thirtydollarwebsite/sounds/yahoo.wav differ
diff --git a/thirtydollarwebsite/sounds/yawn.wav b/thirtydollarwebsite/sounds/yawn.wav
new file mode 100644
index 00000000..63353dc6
Binary files /dev/null and b/thirtydollarwebsite/sounds/yawn.wav differ
diff --git a/thirtydollarwebsite/sounds/yoda.wav b/thirtydollarwebsite/sounds/yoda.wav
new file mode 100644
index 00000000..77d8e07e
Binary files /dev/null and b/thirtydollarwebsite/sounds/yoda.wav differ
diff --git a/thirtydollarwebsite/sounds/zunpet.wav b/thirtydollarwebsite/sounds/zunpet.wav
new file mode 100644
index 00000000..2cf42d0f
Binary files /dev/null and b/thirtydollarwebsite/sounds/zunpet.wav differ
diff --git a/thirtydollarwebsite/▶.js b/thirtydollarwebsite/▶.js
new file mode 100644
index 00000000..d1aa5147
--- /dev/null
+++ b/thirtydollarwebsite/▶.js
@@ -0,0 +1,421 @@
+// hi hello this is the code for actually preloading and playing sequences
+
+let MAX_BPM_LIMIT = 20_000 // wow this seems suspiciously easy to redefine
+
+// convert sequence to json
+function getSequenceData() {
+ let sequenceData = $('#sequence div').map(function (index) {
+ return {
+ index,
+ element: $(this),
+ sound: $(this).attr("sound"),
+ pitch: $(this).attr("pitch"),
+ volume: $(this).attr("vol"),
+ action: $(this).attr("action"),
+ icon: $(this).attr("img"),
+ group: +$(this).parent().attr("group") || 0,
+ amount: $(this).attr("amount"),
+ operator: $(this).attr("num"),
+ dualVal: [$(this).attr("val1"), $(this).attr("val2")]
+ }
+ }).toArray()
+ return sequenceData
+}
+
+function beatLength(bpm) {
+ return 60 / bpm * 1000
+}
+
+function modifyNumber(num, newNum, operator) {
+ switch (operator) {
+ case "add": return num + newNum
+ case "multiply": return num * newNum
+ default: return newNum
+ }
+}
+
+// fetches any uncached sounds in the sequence to prevent lag spikes
+async function fetchRequiredSounds(sequence=getSequenceData()) {
+ // for loops are better for async stuff
+ let soundKeys = Object.keys(sounds)
+ for (let i=0; i < sequence.length; i++) {
+ let x = sequence[i]
+ if (x.sound && x.sound != "sounds/_pause.wav" && !soundKeys.includes(x.sound)) {
+ await fetchSound(x.sound)
+ soundKeys.push(x.sound)
+ }
+ }
+}
+
+function preloadSequence(sequence=getSequenceData()) {
+ let order = []
+
+ let bpm = defaultTempo
+ let volume = defaultVolume
+ let loopTarget = 0
+ let transposition = 0
+
+ let index = 0
+ let timer = 0
+ let scrubPos = 0
+ let pulseID = 0
+
+ let startPositions = sequence.filter(x => x.action == "startpos" && (selectedDivider >= 0 ? x.group == selectedDivider : true))
+ if (startPositions.length) scrubPos = startPositions[startPositions.length - 1].index
+ else if (selectedDivider >= 0) scrubPos = (sequence.find(x => x.group == selectedDivider) || {}).index || 0
+
+ let scrubbing = scrubPos > 0
+
+ function untrigger(idx, except=[]) {
+ let untriggered = []
+ sequence.slice(idx + 1).map((x, y) => {
+ if (!except.includes(x.action)) {
+ if (x.triggered) { x.triggered = false; untriggered.push(idx + 1 + y) }
+ if (x.remaining <= 0) { delete x.remaining; untriggered.push(idx + 1 + y) }
+ }
+ return x;
+ })
+ return untriggered
+ }
+
+ while (index < sequence.length) {
+ let x = sequence[index]
+ let incrementTimer = false
+
+ if (scrubbing && index == scrubPos) scrubbing = false
+
+ // if the event is a sound...
+ if (x.sound) {
+ let vol = !isNaN(+x.volume) ? +x.volume : 100 // dead certain theres a browser that wont support ??
+ // construct the sound data
+ let soundObj = {
+ index,
+ sound: x.sound,
+ volume: volume * clamp((vol) / 100, 0, 4),
+ pitch: clamp((+x.pitch || 0) + transposition, -72, 72),
+ time: timer / 1000,
+ element: x.element,
+ img: x.element.find("img")
+ }
+
+ let nextSound = sequence[index + 1] || {}
+ if (nextSound.action != "combine") incrementTimer = true
+ if (!scrubbing) order.push(soundObj)
+ }
+
+ // if the event is an action...
+ else if (x.action) {
+
+ let val = Number(x.amount) || 0
+
+ let actionObj = {
+ index,
+ action: x.action,
+ pulse: true,
+ trigger: true,
+ scrub: scrubbing,
+ time: timer / 1000,
+ element: x.element,
+ img: x.element.find("img")
+ }
+
+ // do something different for each action
+ switch (x.action) {
+
+ // ⏩ change BPM
+ case "speed":
+ bpm = modifyNumber(bpm, val, x.operator)
+ bpm = Number(clamp(bpm, 5, MAX_BPM_LIMIT).toFixed(4))
+ actionObj.bpm = bpm
+ break;
+
+ // 🔊 change volume
+ case "volume":
+ volume = modifyNumber(volume, val, x.operator)
+ volume = Number(clamp(volume, 0, 600).toFixed(4))
+ actionObj.volume = volume
+ break;
+
+ // ⏸ pause for duration
+ case "stop":
+ let beatsRemaining = isNaN(x.remaining) ? val : x.remaining // i could have used ?? but i'm sure theres a browser out there that doesnt support it. fuck webdev
+ if (!scrubbing && beatsRemaining > 0) {
+ let timeToRemove = Math.min(1, beatsRemaining)
+ timer += beatLength(bpm) * timeToRemove
+
+ beatsRemaining -= 1
+ if (beatsRemaining < 0) beatsRemaining = 0
+
+ actionObj.remaining = beatsRemaining
+ sequence[index].remaining = beatsRemaining
+ index--
+ actionObj.trigger = false
+ }
+ else {
+ actionObj.finished = true
+ actionObj.duration = val
+ }
+ break;
+
+ // 🔁 multiple loops
+ case "loopmany":
+ let loopsRemaining = isNaN(x.remaining) ? val : x.remaining
+ if (!scrubbing && loopsRemaining > 0) {
+ loopsRemaining--
+ actionObj.remaining = loopsRemaining
+ sequence[index].remaining = loopsRemaining
+ index = loopTarget - 1
+ if (loopsRemaining < 1) actionObj.pulse = false
+ else actionObj.trigger = false
+
+ // untrigger: single loops, targets
+ actionObj.untriggered = untrigger(index, ["loopmany"])
+ }
+ else actionObj.skip = true;
+ break;
+
+ // 🔂 single loop
+ case "loop":
+ if (!x.triggered) {
+ sequence[index].triggered = true
+ index = loopTarget - 1
+
+ // untrigger: targets
+ actionObj.untriggered = untrigger(index, ["loop", "loopmany"])
+ }
+ else actionObj.skip = true;
+ break;
+
+ // ◇ loop target
+ case "looptarget":
+ loopTarget = index
+ break;
+
+ // ❎ stop sounds
+ case "cut":
+ break; // nothing, actually
+
+ // 📍 startpos
+ case "startpos":
+ break; // handled earlier
+
+ // ↔ combine
+ case "combine":
+ if (scrubbing) actionObj.skip = true
+ break; // combining is checked for sounds
+
+ // ⏺ go to target
+ case "jump":
+ if (!x.triggered) {
+ let foundTarget = sequence.findIndex(e => e.action == "target" && !e.triggered && e.amount == x.amount)
+ if (foundTarget >= 0) {
+ sequence[index].triggered = true
+ // sequence[foundTarget].triggered = true ???
+ actionObj.target = foundTarget
+ index = foundTarget
+ }
+
+ actionObj.untriggered = untrigger(index, ["loop", "loopmany", "jump", "target"])
+ }
+ else actionObj.skip = true;
+ break;
+
+ // ⭕ target
+ case "target":
+ actionObj.trigger = false
+ actionObj.pulse = false
+ break; // handled by jump action
+
+ // 🔼 raise or lower pitch of all future sounds
+ case "transpose":
+ transposition = modifyNumber(transposition, val, x.operator)
+ transposition = Number(clamp(transposition, -60, 60).toFixed(4))
+ break;
+
+ // ⚡ flash
+ case "flash":
+ break; // nothing here, go figure
+
+ // ⛶ pulse screen
+ case "pulse":
+ if (scrubbing) actionObj.skip = true // disable pulse scrubbing, will fix eventually
+ else {
+ actionObj.count = Math.floor(clamp(+x.dualVal[0], 0, 1000))
+ actionObj.frequency = clamp(Number(x.dualVal[1]).toFixed(4), 0, 1000)
+ actionObj.trigger = false
+ actionObj.pulseID = pulseID
+ if (!actionObj.frequency) actionObj.skip = true
+
+ if (actionObj.count > 1 && actionObj.frequency > 0) {
+ for (let i=1; i < actionObj.count; i++) {
+ let pulseTime = timer + ((beatLength(bpm) * actionObj.frequency * i))
+ if (!order.find(e => e.action == x.action && e.time == pulseTime)) order.push({
+ index,
+ action: x.action,
+ pulse: true,
+ pulseID,
+ trigger: i == actionObj.count - 1,
+ time: pulseTime / 1000,
+ element: x.element, img: actionObj.img
+ })
+ }
+ pulseID++
+ }
+ else actionObj.trigger = true
+ if (actionObj.count < 1) actionObj.stopPulses = true
+ }
+ break;
+
+ // 🎨 background color
+ case "bg":
+ actionObj.bgColor = x.dualVal[0].match(colorRegex) ? x.dualVal[0] : defaultBG
+ actionObj.fadeTime = scrubbing ? 0.1 : clamp(Number(x.dualVal[1]).toFixed(4), 0, 200)
+ break;
+ }
+
+ if (!actionObj.skip) order.push(actionObj)
+
+ }
+
+ index++
+ if (!scrubbing && incrementTimer) timer += beatLength(bpm)
+ }
+ return order.sort((a, b) => a.time - b.time)
+}
+
+let lastPos = -200 // last scroll position
+let lastPulse = 0 // last pulse action
+let startTime = 0 // time when sequence started
+
+let playingSequence = [];
+let nextSoundToQueue = 0;
+let nextAction = 0;
+
+function playSequence(sequence) {
+ updateTempo(defaultTempo)
+ setVolume(defaultVolume)
+ lastPulse = 0
+ startTime = soundcloud.currentTime
+
+ playingSequence = sequence;
+ nextSoundToQueue = 0;
+ nextAction = 0;
+ queueSounds();
+ checkActions();
+}
+
+// how many seconds of sound to queue ahead.
+const queueAhead = 5;
+
+function queueSounds() {
+ for ("tempooptimizer wtf is this for loop -colon"; nextSoundToQueue < playingSequence.length; nextSoundToQueue++) {
+ let x = playingSequence[nextSoundToQueue];
+ if (startTime + x.time > soundcloud.currentTime + queueAhead) break;
+
+ // this is either a sound or a cut
+ if (x.action === "cut") cutSounds(startTime + x.time);
+ else if (x.sound !== undefined) {
+ let pitch = semitonesToPercent(clamp(x.pitch, -72, 72))
+ playSound(x.sound, { pitch, playAt: startTime + x.time, index: x.index, volume: x.volume / 200 })
+ }
+ }
+ if (nextSoundToQueue < playingSequence.length) {
+ // use setTimeout for background playback, requestAnimationFrame for less lag spikes -TempoOptimizer
+ // works for me -Colon
+ setTimeout(queueSounds, 1000);
+ }
+}
+
+function checkActions() {
+ if (!active) return;
+
+ // run for each action where time > current time
+ for ("ksdjfsdf8sdkfjsdkfjak"; nextAction < playingSequence.length; nextAction++) {
+ let x = playingSequence[nextAction];
+ if (startTime + x.time > soundcloud.currentTime) break; // stops the loop
+ if (x.triggered) continue; // does not stop the loop
+
+ x.triggered = true
+ let icon = x.element
+ let img = x.img
+
+ // sounds just bounce!
+ if (x.sound) {
+ icon.runAnimation('bounce')
+ }
+
+ else if (x.action && !settings.noAnimations) {
+
+ if (x.pulse) icon.runAnimation('pulse');
+ if (x.trigger) img.runAnimation('triggered');
+
+ if (x.untriggered && x.untriggered.length) {
+ x.untriggered.forEach(n => {
+ let foundUntrigger = $('#sequence div').eq(n)
+ foundUntrigger.find('img').removeClass('triggered')
+ })
+ }
+
+ // here we go again!
+ switch (x.action) {
+
+ case "speed":
+ updateTempo(x.bpm)
+ break;
+
+ case "volume":
+ setVolume(x.volume);
+ break;
+
+ case "stop":
+ let beatsLeft = icon.find('p')
+ beatsLeft.attr("triggeredCountdown", true)
+ if (x.finished) beatsLeft.text(x.duration)
+ else beatsLeft.text(x.remaining + 1)
+ break;
+
+ case "loopmany":
+ let loopsLeft = icon.find('p')
+ loopsLeft.attr("triggeredCountdown", true)
+ if (x.remaining <= 0) loopsLeft.text("")
+ else loopsLeft.text(x.remaining)
+ break;
+
+ case "jump":
+ let jumpTarget = $('#sequence div').eq(x.target)
+ jumpTarget.runAnimation('pulse')
+ jumpTarget.find('img').runAnimation('triggered')
+ break;
+
+ case "flash":
+ if (!x.scrub) $('#everything').runAnimation('screenflash');
+ break;
+
+ case "pulse":
+ if (x.pulseID > lastPulse) lastPulse = x.pulseID
+ if (!x.scrub && !x.stopPulses && (lastPulse == x.pulseID)) $('body').runAnimation('screenpulse');
+ break;
+
+ case "bg":
+ if (!x.ignore) $('html').css('transition-duration', x.fadeTime + "s").css('background-color', x.bgColor)
+ }
+
+ }
+
+ if (settings.autoScroll) {
+ let pixelsBeforeScroll = 600
+ let newPos = icon.prop("offsetTop") - 150
+ if (Math.abs(newPos - lastPos) > pixelsBeforeScroll) {
+ $('#everything').stop().animate({ scrollTop: newPos }, 350)
+ lastPos = newPos
+ }
+ if (x.action == "divider") lastPos = -1000 // dividers always trigger autoscroll
+ }
+ }
+
+ if (nextAction < playingSequence.length) {
+ requestAnimationFrame(checkActions);
+ } else {
+ cancel({ keepAnimations: true });
+ }
+}
diff --git a/thirtydollarwebsite/🎨.css b/thirtydollarwebsite/🎨.css
new file mode 100644
index 00000000..511d63c8
--- /dev/null
+++ b/thirtydollarwebsite/🎨.css
@@ -0,0 +1,753 @@
+@import url('https://fonts.googleapis.com/css?family=Lato');
+
+html {
+ --bg: #36393c;
+ --emojired: #DD2E44;
+ --emojiyellow: #F4900C;
+ --emojigreen: #77B255;
+ --emojiblue: #3B88C3;
+ --emojipurple: #9266CC;
+
+ --yellowfont: #ccff55;
+ --greenfont: #00FF64;
+ --bluefont: #00A2FF;
+
+ background-color: var(--bg);
+ height: 100%;
+
+ overflow: hidden;
+ transition-duration: 0.2s;
+ transition-property: background-color;
+
+ --mainhotbarwidth: 855px;
+ --mobilehotbarwidth: 90%;
+ --largehotbarwidth: calc(var(--mainhotbarwidth) * 2)
+}
+
+body {
+ margin: 0 0;
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ height: 100%;
+}
+
+body.dragOver {
+ background-color: rgba(255, 255, 255, 0.2);
+ transition-duration: 0.2s;
+}
+
+#everything {
+ position: fixed;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+}
+
+p, h1, vol {
+ font-family: Lato, Helvetica, Arial, sans-serif;
+ font-size: 16px;
+ color: white;
+ margin-bottom: 10px;
+ -webkit-text-size-adjust: none
+}
+
+h1 {
+ font-size: 24px;
+}
+
+vol {
+ display: block;
+ margin: 0px 0px;
+}
+
+a {
+ color: aqua !important;
+}
+
+img {
+ -webkit-user-drag: none;
+}
+
+.iconbox, .infobox, .title {
+ margin: auto;
+}
+
+.iconbox.loadingIcons {
+ flex-wrap: nowrap;
+ justify-content: center;
+}
+
+.multiline {
+ line-height: 27px;
+}
+
+.title {
+ font-size: 40px;
+ margin-top: 15px;
+ margin-bottom: 10px;
+ white-space: nowrap;
+ cursor: pointer;
+}
+
+#main {
+ display: flex;
+ flex-direction: column;
+ margin: auto;
+ padding: 0px 30px;
+}
+
+.sideboxes {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+}
+
+.infobox {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-end;
+}
+
+.infobox span {
+ display: flex;
+ flex-wrap: wrap;
+ margin-bottom: 10px;
+}
+
+.infobox span p {
+ margin: 0px 0px;
+ display: block;
+}
+
+.infobox span p:after { content: "•"; margin: 0px 7px; font-size: 14px; }
+.infobox span p:last-child:after { content: none; }
+
+.iconbox {
+ display: flex;
+ flex-wrap: wrap;
+ align-content: flex-start;
+ align-items: center;
+ border-radius: 8px;
+ background-color: rgba(0, 0, 0, 0.25);
+ min-height: 80px;
+ user-select: none;
+ padding: 20px 10px;
+ margin-bottom: 20px;
+ scrollbar-width: thin;
+ touch-action: manipulation;
+}
+
+.iconbox img, .hotbar img {
+ cursor: pointer;
+ border-radius: 8px;
+ color: white;
+ object-fit: contain;
+ width: 56px;
+ height: 56px;
+ padding: 5px 5px;
+ display: block;
+ font-family: Lato, Helvetica, Arial, sans-serif;
+ color: rgba(255, 255, 255, 0.7);
+}
+
+.iconbox div, .hotbar div {
+ border-radius: 8px;
+ position: relative;
+}
+
+.iconbox div:hover img, .hotbar div:hover img {
+ background-color: rgba(255, 255, 255, 0.15);
+}
+
+#sequence .holdingShift:hover img {
+ background-color: rgba(64, 255, 64, 0.33);
+}
+
+.iconbox .group {
+ width: 1000px;
+}
+
+#icons, #actions, .hotbar {
+ overflow-y: auto;
+}
+
+#everything::-webkit-scrollbar, .iconbox::-webkit-scrollbar, .fancyScroll::-webkit-scrollbar {
+ width: 12px;
+ background: rgba(0, 0, 0, 0.15);
+ border-radius: 10px;
+}
+
+#everything::-webkit-scrollbar-thumb, .iconbox::-webkit-scrollbar-thumb, .fancyScroll::-webkit-scrollbar-thumb {
+ background: rgba(0, 0, 0, 0.33);
+ border-radius: 10px;
+}
+
+#everything::-webkit-scrollbar-corner, .iconbox::-webkit-scrollbar-corner, .fancyScroll::-webkit-scrollbar-corner {
+ background: rgba(0, 0, 0, 0);
+}
+
+#sequence {
+ flex-direction: column;
+ align-items: flex-start;
+ justify-content: flex-start;
+ padding: 20px 7.5px 20px;
+ margin-bottom: 0px;
+}
+
+#sequence div {
+ height: 70px;
+ overflow-y: scroll;
+ scrollbar-width: none;
+}
+
+#sequence img {
+ width: 58px;
+ height: 58px;
+ padding: 6.5px 6px;
+ margin-bottom: 200px;
+ margin-top: 200px;
+}
+
+#sequence div::-webkit-scrollbar {
+ width: 0px;
+ background: rgba(0, 0, 0, 0);
+}
+
+#sequence section {
+ display: flex;
+ flex-wrap: wrap;
+ border: 2.5px solid rgba(0, 0, 0, 0);
+ border-radius: 8px;
+ min-height: 75px;
+ min-width: 75px;
+}
+
+section:not(:empty) + section:empty {
+ background-color: rgba(255, 255, 255, 0.05);
+}
+
+#sequence section:not(:last-child) {
+ margin-bottom: 40px;
+}
+
+#sequence section.holdingCtrl:not(.removedDivider) {
+ border-color: aqua;
+ background-color: rgba(255, 255, 255, 0.1);
+ cursor: pointer;
+}
+
+#sequence section.selectedDivider {
+ border-color: lime !important;
+}
+
+#sequence section.sectionHidden:not(.selectedDivider) {
+ height: 40px;
+ min-height: 40px;
+ max-height: 40px;
+ border-color: rgba(255, 255, 255, 0.25);
+ overflow: hidden;
+}
+
+#sequence section.sectionHidden {
+ opacity: 33%;
+}
+
+#sequence section.sectionHidden:not(.selectedDivider) div {
+ pointer-events: none;
+}
+
+.iconbox p, .iconbox vol {
+ width: 100%;
+ font-weight: bold;
+ text-shadow: 0px 0px 4px black;
+ position: absolute;
+}
+
+#sequence p {
+ top: 235px;
+ white-space: nowrap;
+ overflow-x: auto;
+}
+
+#sequence vol {
+ top: 201px;
+ text-align: right;
+ white-space: nowrap;
+ overflow-x: auto;
+ font-size: 13px;
+ color: #cccccc;
+}
+
+#actions p {
+ right: 25px;
+ top: 16px;
+ font-size: 26px;
+}
+
+.playbuttons {
+ display: flex;
+ justify-content: left;
+ flex-direction: column;
+ user-select: none;
+}
+
+.playbuttons div {
+ display: flex;
+ align-items: center;
+ margin-bottom: 18px;
+ border-radius: 8px;
+ padding-left: 15px;
+ transition-duration: 0.1s;
+ cursor: pointer;
+}
+
+.playbuttons p {
+ font-size: 16px;
+ margin: 0px 0px 7px 0px;
+ text-align: left;
+}
+
+.playbuttons h1 {
+ margin: 0px 0px 2px 0px;
+}
+
+.playbuttons img {
+ margin: 12px 16px 12px 0px;
+ width: 36px;
+ height: 36px;
+}
+
+.playbuttons div:hover { transform: scale(1.02) }
+.playbuttons div:active { transform: scale(1.05) }
+
+.sectionControls {
+ display: flex;
+}
+
+.sectionControls img {
+ height: 40px;
+ margin-right: 15px;
+ cursor: pointer;
+ user-select: none;
+}
+
+.sectionControls img.cantSelect {
+ opacity: 33%;
+ pointer-events: none;
+}
+
+.sectionControls img:hover { transform: scale(1.02) }
+.sectionControls img:active { transform: scale(1.05) }
+
+#sectionSettings.pinnedSettings {
+ position: fixed;
+ background-color: #262626;
+ border-top-right-radius: 8px;
+ border-top: 3px solid #202020;
+ border-right: 3px solid #202020;
+ bottom: 0px;
+ left: 0px;
+ z-index: 2;
+ padding: 12px 0px 12px 12px;
+ transition-duration: 0.2s;
+ transition-timing-function: ease-in-out;
+ transition-property: transform;
+}
+
+#sectionSettings.pinnedSettings .noPin {
+ display: none;
+}
+
+#sectionSettings.pinnedSettings.pinnedHidden {
+ transform: translateY(250%);
+}
+
+.saveButtons div {
+ width: 180px;
+ background-color: var(--emojipurple);
+ margin: 8px 16px 16px 16px;
+}
+
+.alreadySaved {
+ pointer-events: none;
+ opacity: 50%;
+ /* background-color: rgba(120, 100, 140, 0.5) !important; */
+}
+
+.credits {
+ display: flex;
+ justify-content: center;
+}
+
+.credits p {
+ color: rgba(255, 255, 255, 0.33) !important;
+ margin: 10px 20px;
+}
+.credits a { color: rgba(255, 255, 255, 0.66) !important }
+
+.socialLinks {
+ display: flex;
+ justify-content: center;
+}
+
+.socialTag {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-left: 15px;
+ width: 105px;
+}
+
+.socialTag a {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ text-decoration: underline white;
+}
+
+.socialTag p {
+ font-size: 20px;
+ margin: 0px 0px 0px 2px;
+}
+
+.socialTag img {
+ height: 20px;
+ margin-right: 5px;
+}
+
+.sortPlaceholder {
+ opacity: 15%;
+}
+
+.shiftPlaceholder {
+ display: block !important;
+}
+
+.popup {
+ position: fixed;
+ display: flex;
+ align-content: center;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+ top: 0; left: 0; right: 0; bottom: 0;
+ background-color: rgba(0,0,0,0.66);
+ z-index: 3;
+ text-align: center;
+}
+
+.popupbox {
+ background-color: var(--bg);
+ border-radius: 5px;
+ width: 500px;
+ padding: 10px 5px 30px 5px;
+}
+
+.popupdesc {
+ margin-top: 0px;
+ width: 400px;
+ margin: auto;
+ line-height: 24px;
+}
+
+.popupinput {
+ margin-top: 20px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.popupinput p {
+ margin: 0px 0px 0px 10px;
+ font-size: 18px;
+}
+
+.extraSetting {
+ display: flex;
+ align-items: center;
+ margin: 5px 00px;
+ width: 200px;
+ cursor: pointer;
+}
+
+.extraSetting p {
+ margin: 0px 5px;
+ text-align: left;
+}
+
+.extraSetting:hover {
+ text-decoration: underline;
+ text-decoration-color: white;
+ text-decoration-style: dotted;
+}
+
+.settingList {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ padding: 3px 45px;
+ margin-top: 10px;
+}
+
+.shortcutList {
+ display: flex;
+ flex-wrap: wrap;
+ text-align: left;
+ height: 515px;
+ overflow: auto;
+ justify-content: space-between;
+ margin: 0px 15px 30px 15px;
+ padding-left: 30px;
+ background-color: rgba(0, 0, 0, 0.2);
+ border-radius: 10px;
+}
+
+.shortcutList .groupName {
+ text-decoration: underline;
+}
+
+.shortcutSection {
+ width: 320px;
+ margin-bottom: 20px;
+}
+
+button, input {
+ font-family: Lato, Helvetica, Arial, sans-serif;
+ font-size: 18px;
+ text-align: center;
+ color: white;
+ height: 40px;
+ border-radius: 5px;
+ outline: none;
+ border: none;
+ background-color: rgba(0, 0, 0, 0.5);
+}
+
+input[type=number] {
+ font-weight: bold;
+ width: 90px;
+ -moz-appearance: textfield;
+}
+
+input[type=checkbox] {
+ cursor: pointer;
+ width: 24px;
+ height: 24px;
+}
+
+input[type=checkbox]:before {
+ width: 24px;
+ height: 24px;
+ display: inline-block;
+ content: "";
+ background-image: url(../assets/check_off.svg);
+}
+
+input[type=checkbox]:checked:before {
+ background-image: url(../assets/check_on.svg);
+}
+
+input[type=color] {
+ visibility: hidden;
+ pointer-events: none;
+}
+
+.colorPreview {
+ border-radius: 5px;
+ border: 2px solid black;
+ width: 38px;
+ height: 38px;
+ margin-left: 12px;
+ cursor: pointer;
+}
+
+button {
+ width: 100px;
+ background-color: rgba(255, 255, 255, 0.2);
+ cursor: pointer;
+ transition-duration: 0.1s;
+ margin: 0px 5px;
+}
+
+#proHotbar {
+ position: fixed;
+ bottom: 30px;
+ z-index: 1;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: center;
+ pointer-events: none;
+ --hotbarwidth: var(--mainhotbarwidth);
+ transition-duration: 0.2s;
+ transition-timing-function: ease-in-out;
+ transition-property: transform;
+}
+
+#proHotbar.playing {
+ transform: translateY(250%);
+}
+
+.hotbar {
+ pointer-events: all;
+ border: 3px solid black;
+ width: var(--hotbarwidth);
+ height: 140px;
+ border-radius: 8px;
+ background-color: #1d1d1d;
+ display: flex;
+ flex-wrap: wrap;
+ align-content: flex-start;
+ justify-content: flex-start;
+ align-items: center;
+ user-select: none;
+ touch-action: manipulation;
+ scrollbar-width: thin;
+ padding: 6px 6px;
+ overflow: auto;
+}
+
+.hotbar img {
+ width: 48px;
+ height: 48px;
+ padding: 5px 11px;
+}
+
+.hotbar p {
+ position: absolute;
+ right: 48px;
+ top: 8px;
+ font-size: 24px;
+}
+
+.hotbarLabel {
+ margin-bottom: 5px;
+ margin-left: 10px;
+ text-shadow: 1px 1px 3px black, -1px -1px 3px black, 1px -1px 3px black, -1px 1px 3px black;
+}
+
+.hotbarTabs {
+ width: var(--hotbarwidth);
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: flex-end;
+}
+
+.hotbarTab {
+ pointer-events: all;
+ width: 70px;
+ height: 36px;
+ border: 3px solid black;
+ border-bottom: 0px;
+ border-top-left-radius: 8px;
+ border-top-right-radius: 8px;
+ margin-right: 5px;
+ background-color: #1d1d1d;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ transition-duration: 0.1s;
+}
+
+.hotbarTab:first-child {
+ margin-left: 5px
+}
+
+.hotbarTab img {
+ user-select: none;
+ height: 65%;
+ opacity: 50%;
+ transition-duration: 0.1s;
+}
+
+.hotbarTab.selectedTab {
+ transform: translateY(3px);
+ height: 38px;
+ cursor: default;
+}
+
+.hotbarTab.selectedTab img {
+ opacity: 100%;
+}
+
+.hotbarTab:hover img {
+ opacity: 75%;
+}
+
+#hotbarHovertext {
+ max-width: 445px;
+}
+
+button:hover, .imgButton:hover { transform: scale(1.05); }
+button:active, .imgButton:active { transform: scale(1.1); }
+
+input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0 }
+
+@media screen and (max-width: 1000px) {
+ #icons_container { width: 428px !important; }
+ #main { width: 750px !important; }
+ .title { width: 720px !important; white-space: normal !important; }
+ .infobox { flex-direction: column; align-items: flex-start; }
+ .infobox h1 { margin-bottom: 3px; }
+ .infobox span p { text-align: right; margin: 4px 0px 0px 0px; }
+ .infobox span p:after { content: "•"; margin: 0px 4px; font-size: 12px; }
+ .hotbar, .hotbarTabs { width: var(--mobilehotbarwidth) }
+ #proHotbar { --hotbarwidth: --mobilehotbarwidth; bottom: 50px; }
+ #hotbarNotes { height: 250px; }
+ #hotbarHovertext { max-width: 250px; }
+ #extraPadding { height: 400px !important }
+}
+@media screen and (min-width: 1000px) {
+ .mobileOnly { display: none !important; }
+}
+@media screen and (min-width: 2500px) {
+ #hotbarNotes { height: 15vh; }
+}
+@media screen and (min-width: 3250px) {
+ #proHotbar { --hotbarwidth: var(--largehotbarwidth) }
+}
+
+.placed { animation: smallbounce 0.3s }
+.bounce { animation: bounce 0.4s }
+.pulse { animation: pulse 0.4s }
+.screenflash { animation: screenflash 0.66s }
+.screenpulse { animation: screenpulse 0.33s }
+.triggered { animation: greyout 0.2s; animation-fill-mode: forwards; }
+
+@keyframes bounce {
+ 0% { transform: translateY(0); animation-timing-function: ease-out; }
+ 40% { transform: translateY(-15px); animation-timing-function: ease-in; }
+ 0% { transform: translateY(0); }
+}
+
+@keyframes smallbounce {
+ 0% { transform: translateY(0); animation-timing-function: ease-out; }
+ 40% { transform: translateY(-5px); animation-timing-function: ease-in; }
+ 0% { transform: translateY(0); }
+}
+
+@keyframes pulse {
+ 0% { transform: scale(1); animation-timing-function: ease-out; }
+ 50% { transform: scale(1.1); animation-timing-function: ease-in; }
+ 0% { transform: scale(1); }
+}
+
+@keyframes greyout {
+ 0% { opacity: 100%; filter: grayscale(0); animation-timing-function: ease-out; }
+ 100% { opacity: 50%; filter: grayscale(0.15); }
+}
+
+@keyframes screenflash {
+ 0% { background-color: rgba(255, 255, 255, 0.66); }
+ 100% { background-color: rgba(255, 255, 255, 0); }
+}
+
+@keyframes screenpulse {
+ 40% { transform: scale(1.05); animation-timing-function: ease-out; }
+ 100% { transform: scale(1); animation-timing-function: ease-in; }
+}
\ No newline at end of file
diff --git a/thirtydollarwebsite/💾.js b/thirtydollarwebsite/💾.js
new file mode 100644
index 00000000..d75deed6
--- /dev/null
+++ b/thirtydollarwebsite/💾.js
@@ -0,0 +1,266 @@
+let filename = "sequence"
+let extension = ".🗿"
+
+function enableNewSaving() {
+ sexySaving = true
+ $('#saveAsText').text("Save As")
+ $('#saveBtn').show()
+}
+
+function disableNewSaving() {
+ sexySaving = false
+ $('#saveAsText').text("Save")
+ $('#saveBtn').hide()
+}
+
+let sexySavingSupported = typeof window.showSaveFilePicker === "function" // very few browsers support this awesome api
+let sexySaving = !settings.oldSaving && sexySavingSupported
+if (!sexySaving) disableNewSaving()
+else enableNewSaving()
+
+$('#saveOptions').show()
+if (sexySavingSupported) $('.requiresNewSaving').show()
+
+// read placed sounds and create sequence file
+function generateSequenceFile() {
+ let startingTime = Date.now()
+ console.log(`Exporting sequence... (${$('#sequence div').length} icons)`)
+ let sequenceList = []
+ let toAdd = ""
+ $('#sequence div').each(function() {
+ let x = $(this)
+ if (x.attr('sound')) {
+ let snd = x.attr('str')
+ let pitch = x.attr('pitch')
+ let vol = x.attr('vol')
+ let foundSnd = soundList.find(x => x.id == snd)
+ let soundID = foundSnd ? (foundSnd.emoji || foundSnd.id) : (snd || "_pause")
+ let hasPitch = (pitch && pitch != 0)
+ toAdd = (hasPitch ? `${soundID}@${pitch}` : soundID)
+ if (vol && vol != 100) toAdd += `${!hasPitch ? "@0" : ""}%${vol}`
+ }
+ else if (x.attr('action')) {
+ let action = x.attr('action')
+ let actionStr = "!" + action
+ if (action == "divider") actionStr += "\n"
+ else if (x.attr('advanced')) {
+ actionStr += `@${x.attr("val1")},${x.attr("val2")}`
+ }
+ else if (x.attr('amount')) {
+ let num = x.attr('num')
+ actionStr += ("@" + Number(x.attr('amount')))
+ actionStr += (num == "add" ? "@+" : num == "multiply" ? "@x" : "")
+ }
+ toAdd = (actionStr)
+ }
+ if (sequenceList.length && sequenceList[sequenceList.length - 1][0] == toAdd) sequenceList[sequenceList.length - 1][1]++
+ else sequenceList.push([toAdd, 1])
+ })
+ let finalString = sequenceList.map(x => `${x[0]}${x[1] > 1 ? "=" + x[1] : ""}`).join("|")
+ console.log(`Exporting took ${+((Date.now() - startingTime) / 1000).toFixed(2)}s`)
+ return finalString
+}
+
+// upon clicking 'save as' (or just save for old browsers)
+$('#downloadBtn').click(function() {
+ let saveData = generateSequenceFile()
+ if (!saveData.length) return
+ let blob = new Blob([saveData], {type: 'text/txt;charset=UTF-8'});
+ if (ctrlHeld && altHeld) return openSequencePreview(blob)
+ return sexySaving ? modernSave(blob) : classicSave(blob)
+})
+
+// saving through
element, for browsers that don't support the new file reading stuff
+function classicSave(data) {
+ let saveData = generateSequenceFile()
+ if (!saveData.length) return
+ let downloader = document.createElement('a');
+ downloader.href = URL.createObjectURL(data)
+ downloader.dataset.downloadurl = ['text/txt', downloader.download, downloader.href].join(':');
+ downloader.style.display = "none"; downloader.download = filename + extension
+ downloader.target = "_blank"; document.body.appendChild(downloader);
+ downloader.click(); document.body.removeChild(downloader);
+ setUnsavedChanges(false)
+ $('#saveBtn').addClass('alreadySaved')
+}
+
+// saving through file api, for cool browsers
+function modernSave(data) {
+ window.showSaveFilePicker({suggestedName: filename + extension})
+ .then(selectedFile => {
+ selectedFile.createWritable().then(writable => {
+ setSaveLocation(selectedFile)
+ setUnsavedChanges(false)
+ writable.write(data).then(() => writable.close()).catch(console.error)
+ }).catch(console.error)
+ }).catch(console.error)
+}
+
+// moai-ify the filename
+function setFilename(name) {
+ filename = name
+ if (filename.endsWith(extension)) filename = filename.slice(0, extension.length * -1)
+ $('#saveName').val(filename)
+}
+
+// set location for quick saving
+let saveLocation = null
+function setSaveLocation(file) {
+ setFilename(file.name)
+ saveLocation = file
+}
+
+// save to last opened/saved file
+function quickSave() {
+ if (!saveLocation || saveLocation.name != filename + extension) return $('#downloadBtn').trigger('click') // save as
+ let saveData = generateSequenceFile()
+ if (!saveData.length) return
+ if (ctrlHeld && altHeld) return openSequencePreview(new Blob([saveData], {type: 'text/txt;charset=UTF-8'}))
+ saveLocation.createWritable().then(async writable => {
+ writable.write(saveData).then(() => {
+ setUnsavedChanges(false)
+ writable.close()
+ }).catch((e) => alert(e))
+ }).catch(() => {})
+}
+
+// open sequence preview in new tab
+function openSequencePreview(blob) {
+ let blobURL = URL.createObjectURL(blob)
+ window.open(blobURL)
+}
+
+// on file input
+let reader = new FileReader();
+$("#loadFile").on('change', function() {
+ readLoadedFile(this.files[0])
+})
+
+function readLoadedFile(file) {
+ if (!file) return
+ $('#sequence').html("")
+ $('#loadFile').val("")
+ reader.readAsText(file)
+ reader.onload = (function(f) {
+ loadSequence(f.target.result)
+ saveLocation = null
+ setFilename(file.name)
+ });
+}
+
+// load/read/parse sequence file
+function loadSequence(data) {
+ let startingTime = Date.now()
+ console.log(`Loading sequence... (size: ${+(data.length / 1000).toFixed(2)} KB)`)
+ try {
+ let sequenceData = "";
+ (data || "").replace(/\s/g, "").split("|").forEach(x => {
+ let [data, count] = x.split("=")
+ let [main, pitch, num] = data.split("@")
+ if (!main || !data) return
+ let isAction = main.startsWith("!")
+ let element = null
+ if (isAction) {
+ main = main.slice(1) // remove !
+ element = $(`.action[action=${main}]`).first().clone()
+ if (!element.length) return
+ let actionData = actions.find(x => x.name == main)
+ if (actionData.twoValues) {
+ if (!element.find("p").length) element.append("
")
+ for (let i=0; i<(count || 1); i++) sequenceData += addAdvancedAction(actionData.name, pitch.split(","), element, true).prop('outerHTML')
+ return
+ }
+ else if (actionData.amount || actionData.isTarget) {
+ if (actionData.isTarget && !pitch) pitch = 1
+ if (!element.find("p").length) element.append("
")
+ if (num == "x") num = "multiply"
+ else if (num == "+") num = "add"
+ for (let i=0; i<(count || 1); i++) sequenceData += addAction(main, +pitch, num, element, true).prop('outerHTML');
+ return
+ }
+ }
+ else {
+ if (main.includes("%")) { [main, pitch] = main.split("%"); pitch = "%" + pitch }
+ let [pitchVal, volVal] = (pitch || "").split("%").map(x => +x)
+ let foundSound = soundList.find(x => x.id != "_pause" && (x.id == main || x.emoji == main))
+ element = $(`.sound[str=${foundSound ? foundSound.id : "_pause"}]`).first().clone()
+ if (foundSound) {
+ if (pitchVal) {
+ element.attr('pitch', pitchVal)
+ element.append(`${pitchVal > 0 ? "+" : ""}${pitchVal}
`)
+ }
+
+ if (volVal || volVal === 0
+ ) {
+ element.attr('vol', volVal)
+ element.append(`${volVal}% `)
+ }
+ }
+ element.removeAttr("soundorigin")
+ element.removeAttr("soundname")
+ }
+ if (element) for (let i=0; i<(count || 1); i++) sequenceData += (element[0].outerHTML)
+ })
+ $('#sequence')[0].innerHTML = sequenceData
+ deselectSection()
+ syncSections()
+ fetchRequiredSounds()
+ setUnsavedChanges(false)
+ cancel()
+ console.log(`Loading took ${+((Date.now() - startingTime) / 1000).toFixed(2)}s`)
+ }
+ catch(e) { alert("That file couldn't be loaded!"); console.warn(e) }
+}
+
+// remove unsafe filename characters
+function safeFilename(str) { return str.replace(/[/\\:*?"<>|]/g, "") }
+
+$('#saveName').on('input keydown keyup blur', function() {
+ let safeName = safeFilename($(this).val())
+ filename = safeName || "sequence"
+ $(this).val(safeName)
+})
+
+// dragging
+$('body').on('dragover dragenter', function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ if (!active && e.originalEvent.dataTransfer.types.includes("Files")) $('body').addClass('dragOver')
+ return false
+})
+
+$('body').on('dragleave dragend drop', function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ $('body').removeClass('dragOver')
+ return false
+})
+
+$('body').on('drop', function(e){
+ if (active) return false
+ if (e.originalEvent.dataTransfer){
+ if (e.originalEvent.dataTransfer.files.length) {
+ e.preventDefault();
+ e.stopPropagation();
+ let hasUnsaved = unsavedChanges && $('#sequence').children().length
+ if (hasUnsaved && !confirm("Are you sure you want to load this file? Any unsaved changes will be lost.")) return
+ readLoadedFile(e.originalEvent.dataTransfer.files[0])
+ }
+ }
+});
+
+function setUnsavedChanges(unsaved) {
+ unsavedChanges = !!unsaved
+ if (unsavedChanges) $('#saveBtn').removeClass('alreadySaved')
+ else $('#saveBtn').addClass('alreadySaved')
+}
+
+// exit confirmation
+let unsavedChanges = false
+$('#sequence').on('DOMSubtreeModified', function() { setUnsavedChanges(true) });
+window.onbeforeunload = function(e) {
+ if (unsavedChanges && $('#sequence').children().length && settings.exitConfirmation) {
+ e.returnValue = "🗿";
+ return cancel()
+ }
+};
\ No newline at end of file
diff --git a/thirtydollarwebsite/🗿.js b/thirtydollarwebsite/🗿.js
new file mode 100644
index 00000000..882cda6e
--- /dev/null
+++ b/thirtydollarwebsite/🗿.js
@@ -0,0 +1,1011 @@
+let sounds = {}
+let soundcloud = new AudioContext();
+let recent = new Set()
+
+const mobile = ( /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent) )
+if (mobile) $('p[mobile]').each(function() { $(this).text($(this).attr('mobile')); $('.nomobile').hide() })
+
+const intros = [
+ {name: $('#caption').text(), path: "assets/dont_you_lecture_me.wav" },
+ {name: "how you gonna talk behind my back when you deadass built like a", path: "assets/you_deadass_built_like_a.wav" },
+ {name: "white people be like", path: "assets/white_people_be_like.wav" }
+]
+
+const actions = [
+ { shortcut: "t", action: "Set tempo", amount: true, name: "speed", image: "assets/action_speed.png", default: 300, set: [10, 10000], add: [-10000, 10000], multiply: [0.01, 1000, 0.1] },
+ { shortcut: "v", action: "Set volume", amount: true, name: "volume", image: "assets/action_volume.png", default: 100, set: [0, 600, 1, "%"], add: [-600, 600, 1, "%"], multiply: [0.01, 1000, 0.1] },
+ { shortcut: "p", action: "Pause for duration", amount: true, name: "stop", image: "assets/action_stop.png", default: 4, set: [0, 1000] },
+ { shortcut: "m", action: "Transpose", amount: true, name: "transpose", image: "assets/action_transpose.png", default: 1, set: [-60, 60], add: [-60, 60], multiply: [0.01, 100, 0.1] },
+
+ { shortcut: "l", action: "Loop", amount: true, name: "loopmany", image: "assets/action_loopmany.png", default: 4, set: [1, 1000] },
+ { shortcut: "r", action: "Loop once", name: "loop", image: "assets/action_loop.png" },
+ { shortcut: "s", action: "Set loop start point", name: "looptarget", image: "assets/action_looptarget.png" },
+ { shortcut: "c", action: "Combine sounds", name: "combine", image: "assets/action_combine.png" },
+
+ { shortcut: "g", action: "Go to target", isTarget: true, name: "jump", image: "assets/action_jump.png", set: [1, 9999] },
+ { shortcut: "a", action: "Target", isTarget: true, name: "target", image: "assets/action_target.png", set: [1, 9999] },
+ { shortcut: "x", action: "Stop all sounds", name: "cut", stopSounds: true, image: "assets/action_cut.png" },
+ { shortcut: "o", action: "Set start position", name: "startpos", image: "assets/action_startpos.png" },
+
+ { shortcut: "d", action: "Add divider", name: "divider", image: "assets/action_divider.png" },
+ { shortcut: "f", action: "Flash screen", name: "flash", image: "assets/action_flash.png" },
+ { shortcut: "u", action: "Pulse screen", amount: true, twoValues: [[0, 1000], [0.1, 128]], scroll: [0, 1], default: [1, 2], name: "pulse", image: "assets/action_pulse.png" },
+ { shortcut: "b", action: "Set background color", amount: true, colorMode: true, twoValues: [["color"], [0, 128]], scroll: [1, 0.25], default: ["X", 1], name: "bg", image: "assets/action_bg.png" }
+]
+actions.forEach(x => { $('#actions').append(`${x.amount ? "
+
" : ""}
`) })
+
+let soundList = []
+fetch("./sounds.json").then(x => x.json()).then(list => {
+ soundList = list
+ $('#iconboxLoading').hide()
+ $('#icons').removeClass('loadingIcons')
+ list.forEach(x => {
+ let imageLink = (!x.emoji && x.id.match(/[a-z0-9]/i)) ? `icons/${x.img || x.id}.png` : `https://cdnjs.cloudflare.com/ajax/libs/twemoji/14.0.2/svg/${(x.emoji || x.id).codePointAt(0).toString(16)}.svg`
+ $('#icons').append(` "tag_" + x).join(" ")}>
`)
+ lastGroup = x.group
+
+ if (settings.proMode) {
+ $('.hotbarTab').first().trigger('click')
+ $('#proHotbar').show()
+ $('#extraPadding').show()
+ buildHotbar()
+ }
+ })
+}).catch((e) => {
+ console.error(e)
+ $('#icons img').hide()
+ $('#icons').addClass('loadingIcons')
+ $('#iconboxLoading').show()
+ $('#loadingText').text("Something went wrong!")
+ $('#errorInfo').text(e.message)
+})
+
+let hotbar = $('#hotbarNotes')
+function buildHotbar(filter="sounds") {
+ $('#hotbarNotes .placed').removeClass('placed')
+ hotbar.html("") // clear hotbar
+
+ if (filter == "recent") {
+ let recentNotes = [...recent].slice(-48).reverse()
+ recentNotes.forEach(x => {
+ if (x.startsWith(".")) hotbar.append($(`#actions div[action=${x.slice(1)}]`).prop('outerHTML') || "") // action
+ else hotbar.append($(`#icons div[str=${x}]`).prop('outerHTML') || "") // sound
+ })
+ return
+ }
+
+ // whether to pull from sounds, actions, or both
+ let pool = (filter == "actions" ? "#actions div" : ["recent", "favorite"].includes(filter) ? "#icons div, #actions div" : "#icons div")
+
+ $(pool).each(function() {
+ let x = $(this)
+ if (filter == "notes" && !x.is('[tag_note]')) return
+ else if (filter == "percussion" && !x.is('[tag_percussion]')) return
+ hotbar.append(x.prop('outerHTML'))
+ })
+}
+
+function updateRecent(id) {
+ recent.delete(id); recent.add(id)
+}
+
+let defaultBG = "#36393c"
+let colorRegex = /^#[a-f0-9]{6}$/i
+
+let cloneSort = false
+
+$('#sequence').sortable({
+ tolerance: "pointer",
+ helper: "clone",
+ containment: "#sequence",
+ placeholder: "sortPlaceholder",
+ items: "div",
+ cursor: "move",
+ delay: mobile ? 1500 : 0,
+ forcePlaceholderSize: true, forceHelperSize: true,
+ start: function(event, ui) {
+ cloneSort = shiftHeld || altHeld
+ if (cloneSort) ui.item.addClass('shiftPlaceholder')
+ ui.placeholder.html(ui.item.html())
+ },
+ stop: function(event, ui) {
+ if (cloneSort) {
+ ui.item.clone().insertAfter(ui.item);
+ $(this).sortable('cancel');
+ ui.item.clone()
+ }
+ cloneSort = false
+ $('.shiftPlaceholder').removeClass('shiftPlaceholder')
+ $('.placed').removeClass('placed')
+ cancel()
+ if ($("#sequence section").length > 1) {
+ if (ui.item.attr("action") == "divider") deselectSection()
+ syncSections()
+ }
+ }
+})
+
+$(document).on('mouseover', '#icons div', function () {
+ let soundCredit = $(this).attr('soundName')
+ let soundOrigin = $(this).attr('soundOrigin')
+ $('#soundText').hide()
+ $('#soundName').text(soundCredit)
+ $('#soundOrigin').text(soundOrigin ? ` (${soundOrigin})` : "")
+ $('#soundInfo').show()
+})
+
+$(document).on('mouseleave', '#icons div', function () {
+ $('#soundInfo').hide()
+ $('#soundText').show()
+})
+
+$(document).on('mouseover', '#actions div', function () {
+ $('#actionText').hide()
+ $('#actionInfo').show()
+ $('#actionName').text($(this).attr('info'))
+ if (!mobile && !settings.noActionShortcuts) $('#actionKey').text("(" + $(this).attr('key') + ")").show()
+ else $('#actionKey').hide()
+})
+
+$(document).on('mouseleave', '#actions div', function () {
+ $('#actionInfo').hide()
+ $('#actionText').show()
+})
+
+$(document).on('mouseover', '#sequence div', function () {
+ if (shiftHeld || altHeld) $(this).addClass('holdingShift')
+})
+
+$(document).on('mouseleave', '#sequence div', function () {
+ $('.holdingShift').removeClass('holdingShift')
+})
+
+$(document).on('mouseover', '#sequence section', function () {
+ if (ctrlHeld && hasDividers()) $(this).addClass('holdingCtrl')
+})
+
+$(document).on('mouseleave', '#sequence section', function () {
+ $('.holdingCtrl').removeClass('holdingCtrl')
+})
+
+$(document).on('mouseleave', '#sequence .removedDivider', function (e) {
+ if (!e.isTrigger) $(this).removeClass('removedDivider')
+})
+
+$(document).on('mouseover', '.hotbarTab', function() {
+ $('#hotbarText').css('color', 'var(--yellowfont)').text($(this).attr('desc')).show()
+ $('#hotbarContext').css('color', 'var(--yellowfont)').text("(" + ($(this).index() + 1) + ")").show()
+})
+
+$(document).on('mouseover', '#hotbarNotes div.sound', function() {
+ let origin = $(this).attr("soundOrigin")
+ $('#hotbarText').css('color', 'var(--greenfont)').text($(this).attr('soundName')).show()
+ if (!mobile) $('#hotbarContext').css('color', 'var(--greenfont)').text(origin ? `(${origin})` : "").show()
+})
+
+$(document).on('mouseover', '#hotbarNotes div.action', function() {
+ $('#hotbarText').css('color', 'var(--bluefont)').text($(this).attr('info')).show()
+ if (!mobile && !settings.noActionShortcuts) $('#hotbarContext').css('color', 'var(--bluefont)').text("(" + $(this).attr('key') + ")").show()
+})
+
+$(document).on('mouseleave', '#hotbarNotes div, .hotbarTab', function (e) {
+ $('#hotbarText, #hotbarContext').text("").hide()
+})
+
+// prevents right click menu from showing
+$(document).on('click contextmenu', '.iconbox, #proHotbar', function () { return false })
+
+$(document).on('click contextmenu', '#icons div, #hotbarNotes div.sound', function (event) {
+ cancel()
+ let sound = $(this).attr('sound')
+ let soundID = $(this).attr('str')
+ let added = $(this.outerHTML)
+ let pitch = null
+ if (event.type == "contextmenu") {
+ if (!settings.noAnimations) $(this).runAnimation('placed')
+ playSound(sound)
+ return false
+ }
+ if (pitch) added.append(`${pitch >= 0 ? "+" : ""}${pitch}
`) // ???
+ if (!sound.startsWith("_")) {
+ if (!settings.noAnimations) added.runAnimation('placed')
+ playSound(sound, { pitch: semitonesToPercent(pitch)} )
+ }
+ added.removeAttr("soundorigin")
+ added.removeAttr("soundname")
+ updateRecent(soundID);
+ addToSequence(added)
+})
+
+$(document).on('click contextmenu', '#actions div, #hotbarNotes div.action', function (event) {
+ cancel()
+ let actionName = $(this).attr('action')
+ let action = actions.find(x => x.name == actionName)
+ if (!action) return
+
+ let added = $(this.outerHTML)
+ added.removeAttr("info").removeAttr("key")
+
+ if (action.amount) {
+ stash = added
+ if (event.type == "contextmenu" && action.default) {
+ if (action.twoValues) return addAdvancedAction(actionName, action.default)
+ else return addAction(actionName, action.default)
+ }
+ else {
+ if (shiftHeld) stash.attr("addToStart", true)
+ let actionPopup = $(`#action_${actionName}`)
+ actionPopup.css('display', 'flex')
+
+ // action editing - fill values
+ if (replaceAction && replaceAction.attr("action") == actionName) {
+ if (action.twoValues) {
+ $(actionPopup.find('input').first().val(replaceAction.attr("val1"))).trigger('input')
+ $(actionPopup.find('input').last().val(replaceAction.attr("val2"))).trigger('input')
+ }
+ else $(actionPopup.find('input').first().val(replaceAction.attr("amount"))).trigger('input')
+ }
+
+ return
+ }
+ }
+ else if (action.isTarget) {
+ let nextFree = 1
+ while ($(`.action[action=jump][amount=${nextFree}]`).length && $(`.action[action=target][amount=${nextFree}]`).length) nextFree++
+ added.attr("amount", nextFree).append(`${nextFree}
`)
+ }
+ else if (action.set) {
+ if (action.showPlus) added.attr("num", "plus")
+ added.attr("amount", action.default).append(`${getPrefix(added.attr("num"), action.default)}${action.default}
`)
+ }
+ if (action.stopSounds) stopSounds()
+ if (!settings.noAnimations) added.addClass('placed')
+ if (action.name == "divider") {
+ if (!shiftHeld && selectedDivider >= 0) selectedDivider++
+ }
+
+ updateRecent("." + actionName)
+ addToSequence(added)
+})
+
+function getPrefix(num, amt) {
+ return num == "plus" ? (amt >= 0 ? "+" : "") : num == "add" ? "+" : num == "multiply" ? "⨯" : ""
+}
+
+function addToSequence(element, noPrepend, copyGroup) {
+ let startAttr = element.attr("addToStart")
+ if (startAttr) element.removeAttr("addToStart")
+ let prependMode = (shiftHeld && !noPrepend) || startAttr
+ let container = $(`#sequence section[group="${selectedDivider}"]`)
+ if (copyGroup >= 0 && selectedDivider != copyGroup) container = []
+ if (!container.length) container = prependMode ? $(`#sequence section`).first() : $(`#sequence section`).last()
+ if (!container.length) { // jquery isn't exactly good at 'or', whatever
+ $("#sequence").append(``)
+ return addToSequence(element)
+ }
+ prependMode ? container.prepend(element) : appendToSection(container, element)
+ if (element.attr("action") == "divider") syncSections()
+}
+
+// add to end, or second last if it ends with a divider
+function appendToSection(container, element) {
+ let lastChild = container.children().last()
+ let hasDivider = (lastChild.attr("action") == "divider")
+ if (hasDivider) element.insertBefore(lastChild)
+ else container.append(element)
+}
+
+function addAction(action, input, num="set", element=stash, dontAppend=false) {
+ if (typeof input == "string" && input.startsWith("#")) input = $(input).val()
+ if (!element || isNaN(input)) return
+ let amount = Number(Number(input).toFixed(3)) // tofixed converts to string lmao
+ let foundAction = actions.find(x => x.name == action)
+ let actionData = foundAction[num]
+
+ amount = clamp(amount, actionData[0], actionData[1])
+ let prefix = getPrefix(num, amount)
+ let amountStr = prefix + String(amount) + (actionData[3] || "")
+ //element.attr("min", actionData[0]).attr("max", actionData[1])
+ if (num != "set") element.attr("num", num)
+ if (!isNaN(actionData[2])) element.attr("step", actionData[2])
+ if (actionData[3]) element.attr("suffix", actionData[3])
+ if (!settings.noAnimations) element.addClass('placed')
+ element.attr("amount", amount).find('p').text(amountStr)
+
+ if (replaceAction) editAction(element)
+ else if (!dontAppend) addToSequence(element)
+ else return element
+ updateRecent("." + action)
+ if (stash) stash = null
+ $('.popup').hide()
+}
+
+// eh i'm just gonna make a new function for this
+function addAdvancedAction(action, inputs, element=stash, dontAppend=false) {
+ let foundAction = actions.find(x => x.name == action)
+ if (!foundAction || !Array.isArray(inputs)) return
+ let cleanInputs = inputs.map((x, y) => {
+ let bounds = foundAction.twoValues[y]
+ if (bounds == "color") x = x.match(colorRegex) ? x : defaultBG
+ else if (Array.isArray(bounds)) x = clamp(x, bounds[0], bounds[1])
+ return x
+ })
+
+ element.attr("advanced", true).attr("val1", cleanInputs[0]).attr("val2", cleanInputs[1])
+
+ if (foundAction.colorMode) element.find('p').html(`⬤ ${cleanInputs[1]}`)
+ else element.find('p').text(`${cleanInputs[0]}, ${cleanInputs[1]}`)
+
+ if (replaceAction) editAction(element)
+ else if (!dontAppend) addToSequence(element)
+ else return element
+ if (stash) stash = null
+ $('.popup').hide()
+}
+
+function editAction(element) {
+ replaceAction.replaceWith(element)
+ replaceAction.runAnimation('placed')
+ replaceAction = null
+}
+
+function syncSections() {
+ let noteGroups = [""]
+ let dividerIndex = 0
+ let collapsedSections = []
+ $('.placed').removeClass('placed')
+ $('.selectedDivider').removeClass('selectedDivider')
+ $('#sequence div').each(function() {
+ let isDivider = $(this).attr("action") == "divider"
+ if (isDivider) {
+ let oldSection = Number($(this).attr("section"))
+ if (oldSection >= 0 && $(this).parent().hasClass("sectionHidden")) collapsedSections.push(dividerIndex)
+ $(this).attr("section", dividerIndex)
+ }
+
+ noteGroups[dividerIndex] += $(this).prop("outerHTML")
+
+ if (isDivider) {
+ dividerIndex++
+ noteGroups.push("")
+ }
+ })
+ $('#sequence').html(noteGroups.map((x, y) => ``).join(""))
+ if (dividerIndex > 0) $('#sectionSettings').show()
+ else $('#sectionSettings').hide()
+}
+
+function hasDividers() {
+ return $("#sequence section").length > 1
+}
+
+function deselectSection() {
+ selectedDivider = -1
+ if (ctrlHeld) $('.selectedDivider').addClass('removedDivider')
+ displaySection()
+}
+
+function changeSection(change, scroll) {
+ let totalDividers = $('#sequence section').length
+ if (totalDividers <= 1) return selectedDivider = -1
+
+ if (selectedDivider == -1 && change < 0) selectedDivider = totalDividers - 1
+ else if (selectedDivider == -1 && change > 0) selectedDivider = 0
+ else selectedDivider = selectedDivider + change
+
+ if (selectedDivider < 0) selectedDivider = totalDividers - 1
+ else if (selectedDivider >= totalDividers) selectedDivider = 0
+
+ displaySection(scroll)
+}
+
+function displaySection(scroll) {
+ $(".selectedDivider").removeClass("selectedDivider")
+ if (selectedDivider >= 0) {
+ let foundDivider = $(`#sequence section[group="${selectedDivider}"]`)
+ foundDivider.addClass("selectedDivider")
+ $('.requiresSelected').removeClass('cantSelect')
+ $('#selectedSection').text(selectedDivider + 1)
+ if (foundDivider.hasClass("sectionHidden")) { $('#hideSection').hide(); $('#showSection').show() }
+ else { $('#hideSection').show(); $('#showSection').hide() }
+ if (!active && scroll) $('#everything').stop().animate({ scrollTop: foundDivider.prop("offsetTop") - 150 }, 100)
+ }
+ else {
+ $('.requiresSelected').addClass('cantSelect')
+ $('#selectedSection').text("None")
+ $('#hideSection').show();
+ $('#showSection').hide()
+ }
+}
+
+function toggleSectionVisibility(section=selectedDivider) {
+ if (section < 0) return
+ $(`#sequence section[group="${section}"]`).toggleClass('sectionHidden')
+ displaySection()
+}
+
+$(document).on('click contextmenu', '#sequence section', function (e) {
+ if (!ctrlHeld) return
+ e.stopPropagation()
+ if (!hasDividers()) return
+ let dividerGroup = parseInt($(this).attr("group"))
+ if (isNaN(dividerGroup)) return
+
+ if (e.type == "contextmenu") {
+ toggleSectionVisibility(dividerGroup)
+ return false
+ }
+
+ if ($(this).hasClass("selectedDivider")) return deselectSection()
+
+ else {
+ selectedDivider = dividerGroup
+ if (isNaN(selectedDivider)) return selectedDivider = -1
+ displaySection()
+ }
+})
+
+$(document).on('click', '#sequence div', function () {
+ if (ctrlHeld) return
+ cancel()
+ if (shiftHeld || altHeld) {
+ let copy = $(this).clone()
+ if (!settings.noAnimations) copy.addClass('placed')
+ copy.insertAfter($(this))
+ playSound($(this).attr("sound"), { pitch: getPitch($(this)), volume: getVolume($(this)), stopPrevious: true })
+ }
+ else $(this).remove()
+ if ($(this).attr("action") == "divider") {
+ deselectSection()
+ syncSections()
+ }
+})
+
+$(document).on('contextmenu', '#sequence div', function () {
+ if (ctrlHeld || active) return false
+
+ let snd = $(this).attr("sound")
+ let acn = $(this).attr("action")
+ if (shiftHeld || altHeld) { // clone and append to end
+ let copy = $(this).clone()
+ if (!settings.noAnimations) copy.addClass('placed')
+ addToSequence(copy, true, Number($(this).parent().attr("group")))
+ playSound(snd, { pitch: getPitch($(this)), volume: getVolume($(this)), stopPrevious: true})
+ return false
+ }
+
+ else if ($(this).hasClass("action") && acn) {
+ let foundAction = actions.find(x => x.name == acn)
+ if (!foundAction || !foundAction.amount) return false
+ replaceAction = $(this)
+ let actionBtn = $(`#actions div[action="${acn}"]`)
+ if (!actionBtn.length) return
+ actionBtn.trigger("click")
+ return false
+ }
+
+ else if (!active && snd) {
+ if (!settings.noAnimations) $(this).runAnimation('placed')
+ playSound(snd, { pitch: getPitch($(this)), volume: getVolume($(this)), stopPrevious: true})
+ return false
+ }
+})
+
+// hotbar tabs
+$(document).on('click', '.hotbarTab:not(.selectedTab)', function () {
+ $('.selectedTab').removeClass('selectedTab')
+ $(this).addClass('selectedTab')
+ buildHotbar($(this).attr("tab"))
+})
+
+$("#everything").scroll(function(){
+ if (settings.dontFadeProBar || mobile) return
+ let normal = 30
+ let top = 200 / 1.5
+ let dist = Math.min(normal, ($(this).scrollTop() - 200) / 1.5)
+ let percent = Math.max(0, ((dist + top) / (normal + top)) * 100)
+
+ $("#proHotbar").css("bottom", dist + "px")
+ .css("opacity", percent + "%")
+ .css("visibility", percent < 2 ? "hidden" : "visible")
+});
+
+// no idea what this is for but probably some sorting bug
+function whatthefuck(el, index) {
+ $('#sequence').sortable('cancel')
+ el.remove().insertAfter('#sequence div')[index]
+}
+
+let lastY = null
+let mobileCooldown = false
+$(document).on('wheel touchmove', '#sequence div', function(event) {
+ let el = $(this)
+ if (event.type == "touchmove") {
+ if (mobileCooldown || $('.ui-sortable-helper').length) return
+ let clientY = event.originalEvent.touches[0].clientY;
+ let sensitivity = 50
+ if (clientY > (lastY + sensitivity)) event.arrowDelta = 21
+ else if (clientY < (lastY - sensitivity)) event.arrowDelta = -21
+ else return
+
+ lastY = clientY;
+ mobileCooldown = true
+ setTimeout(() => { mobileCooldown = false; $('#sequence div').scrollTop(200) }, 25);
+ $('#sequence div').scrollTop(200)
+ }
+ if (active || $(this).hasClass('ui-sortable-helper')) return
+ let isVolume = (ctrlHeld && el.attr("sound"))
+ let downward = (event.arrowDelta || event.originalEvent.deltaY) > 0
+ let foundAction = actions.find(x => x.name == el.attr("action"))
+ let foundText = el.attr("amount") || el.attr("pitch") || el.find("p").text()
+ let shift = Number(foundText) || 0
+ if (isVolume) {
+ shift = Number(el.attr("vol"))
+ if (isNaN(shift) || shift < 0) shift = 100
+ }
+
+ if (el.attr("sound") && !el.attr("str").startsWith("_")) {
+ let shiftChange = ((downward ? -1 : 1) * (shiftHeld ? (isVolume ? 10 : 6) : altHeld ? 0.2 : 1))
+
+ if (!isVolume) {
+ shift += shiftChange
+ shift = Number(clamp(shift, -60, 60).toFixed(2))
+ let prefix = shift > 0 ? "+" : ""
+ if (foundText && shift == 0) el.find("p").remove()
+ else if (!el.find("p").length) el.append(`${prefix + shift}
`)
+ else el.find("p").text(prefix + shift)
+ el.attr("pitch", shift)
+ playSound(el.attr("sound"), { pitch: semitonesToPercent(shift), volume: getVolume(el), stopPrevious: true })
+ }
+
+ else {
+ if (shiftChange == 1 || shiftChange == -1) shiftChange *= 2
+ shift += shiftChange
+ shift = Number(clamp(shift, 0, 400).toFixed(2))
+ if (shift == 100) el.find("vol").remove()
+ else if (!el.find("vol").length) el.append(`${shift}% `)
+ else el.find("vol").text(shift + "%")
+ el.attr("vol", shift)
+ playSound(el.attr("sound"), { pitch: getPitch(el), volume: shift / 100 / 2, stopPrevious: true })
+ }
+ }
+ else if (el.attr("action") && el.attr("amount")) {
+ let bounds = foundAction[el.attr("num") || "set"]
+ let step = bounds[2] || 1
+ if (shiftHeld) step *= 10
+ else if (altHeld) step /= 10
+ shift += downward ? step * -1 : step
+ shift = Number(shift.toFixed(4))
+ shift = clamp(shift, bounds[0], bounds[1] || 999)
+ el.attr("amount", shift)
+ el.find("p").text(getPrefix(el.attr("num"), shift) + shift + (bounds[3] || ""))
+ }
+ else if (foundAction && el.attr("advanced")) {
+ let scrollInfo = foundAction.scroll
+ let valStr = scrollInfo[0] == 0 ? "val1" : "val2"
+ let scrollVal = +el.attr(valStr)
+ let twoBounds = foundAction.twoValues[scrollInfo[0]]
+ let step = +scrollInfo[1] || 1
+ if (shiftHeld) step *= 10
+ else if (altHeld) step /= 10
+ scrollVal += downward ? step * -1 : step
+ scrollVal = clamp(scrollVal.toFixed(4), twoBounds[0], twoBounds[1])
+ el.attr(valStr, scrollVal)
+ if (foundAction.colorMode) el.find("p").children().last().text(el.attr("val2"))
+ else el.find("p").text(`${el.attr("val1")}, ${el.attr("val2")}`)
+ }
+})
+
+// prevent ctrl+zoom
+$('.iconbox, #proHotbar').bind('mousewheel DOMMouseScroll', function(e) { if (e.ctrlKey) e.preventDefault(); });
+
+let intro = 0
+let lecture = null
+let cachedIntros = []
+let mainNode = new GainNode(soundcloud)
+
+$('#caption').click(function() {
+ intro++
+ if (intro >= intros.length) intro = 0
+ $('#caption').text(intros[intro].name).runAnimation('placed')
+ stopIntro()
+ loadIntro()
+ cancel()
+})
+
+function loadIntro() {
+ let introPath = intros[intro].path
+ if (cachedIntros[introPath]) lecture = cachedIntros[introPath]
+ else {
+ fetch(introPath)
+ .then(res => res.arrayBuffer())
+ .then(buffer => soundcloud.decodeAudioData(buffer))
+ .then(data => {
+ cachedIntros[introPath] = data
+ lecture = data
+ })
+ }
+}
+loadIntro()
+
+let activeIntro = null
+function playIntro() {
+ stopIntro()
+ let introSound = new AudioBufferSourceNode(soundcloud, { buffer: lecture })
+ mainNode.connect(soundcloud.destination)
+ introSound.connect(mainNode)
+ introSound.start()
+ activeIntro = introSound
+ introSound.addEventListener("ended", () => {
+ if (introSound.dead) return
+ beginSequence()
+ stopIntro()
+ })
+}
+
+function stopIntro() {
+ if (!activeIntro) return
+ activeIntro.dead = true
+ activeIntro.disconnect()
+ activeIntro = null
+}
+
+document.addEventListener('scroll', function (event) { if ($(event.target).is("#sequence div")) $(event.target).scrollTop(200) }, true);
+$('#sequence').on('DOMSubtreeModified', function(event) { $('#sequence div').scrollTop(200) });
+
+// https://stackoverflow.com/a/45036752
+$.fn.runAnimation = function(className) {
+ if (settings.noAnimations) return
+ let el = $(this)[0]
+ el.style.animation = "none"
+ el.offsetHeight
+ el.style.animation = null
+ $(this).addClass(className)
+}
+
+let stash = null
+let replaceAction = null
+let defaultTempo = 300
+let defaultVolume = 100
+
+let preloaded = null
+let active = false
+let scrubbing = false
+let ctrlHeld = false
+let shiftHeld = false
+let altHeld = false
+let onCooldown = false
+let selectedDivider = -1
+
+let volume = 0
+updateTempo(defaultTempo)
+setVolume(defaultVolume)
+
+function clamp(num, min, max) { return Math.min(Math.max(num , min), max) }
+function percentToSemitones(percent) { return Math.log(percent, 2) * 12 }
+function semitonesToPercent(semitones) { return Math.pow(2, Number(semitones) / 12) }
+function getPitch(element) { return semitonesToPercent(element.find('p').text() || "0") }
+function getVolume(element) { return Number(element.find('vol').text().slice(0, -1) || 100) / 200 }
+
+function cancel(cancelOptions={}) {
+ if ((!cancelOptions.keepAnimations && active) || cancelOptions.stopSounds) stopSounds()
+ active = false
+ preloaded = null
+ updateTempo(defaultTempo)
+ setVolume(100)
+ if (!cancelOptions.keepAnimations) {
+ $('.bounce').removeClass('bounce')
+ $('.pulse').removeClass('pulse')
+ }
+ $('.playInfo').show()
+ $('.stopInfo').hide()
+ $('.pinnedHidden').removeClass("pinnedHidden")
+ $('#proHotbar').removeClass("playing")
+ $('.triggered').removeClass('triggered')
+ $('#sequence p[triggeredCountdown]').each(function() { resetAmount($(this)) })
+ $('html').removeAttr("style")
+ stopIntro()
+}
+
+function resetAmount(el) {
+ let parent = el.parent()
+ el.text(getPrefix(parent.attr('num'), +parent.attr('amount')) + parent.attr('amount') + (parent.attr('suffix') || ""))
+ el.removeAttr("triggeredcountdown")
+}
+
+// on play button
+function startSequence(instant=false) {
+ if (onCooldown || active || $('#sequence div').length < 1) return
+ onCooldown = true
+ setTimeout(() => { onCooldown = false }, 250);
+ stopSounds()
+ cancel()
+ active = true
+ $('#sectionSettings.pinnedSettings').addClass("pinnedHidden")
+ $('#proHotbar').addClass("playing")
+ $('.playInfo').hide()
+ $('.stopInfo').show()
+
+ preloaded = preloadSequence()
+
+ if (!instant && selectedDivider < 0) playIntro()
+ else beginSequence()
+}
+
+// after "don't you lecture me"
+function beginSequence() {
+ if (!preloaded) return
+ $('.placed').removeClass('placed')
+ playSequence(preloaded)
+}
+
+function updateTempo(BPM) {
+ $('#BPM').text(+BPM.toFixed(4))
+}
+
+function setVolume(percent) {
+ volume = Number(clamp(percent / 200, 0, 3).toFixed(4))
+ $('#volume').text(+(volume * 200).toFixed(4))
+}
+
+// currently playing sounds are stored here
+let activeSounds = [];
+
+// remove any finished sounds from the active list
+function clearPlayedSounds() {
+ activeSounds = activeSounds.filter(x => !x.sound.finished)
+}
+
+// destroy sound
+function killSound(snd, vol, clearList=true) {
+ snd.finished = true
+ snd.disconnect()
+ vol.disconnect()
+ if (clearList) clearPlayedSounds()
+}
+
+// stop all sounds
+function stopSounds() {
+ activeSounds.forEach(x => killSound(x.sound, x.gainNode, false))
+ nextSoundToQueue = playingSequence.length;
+ clearPlayedSounds()
+}
+
+// fetches and prepares sound
+let currentlyFetching = {} // prevent earrape when trying to load the same sound multiple times
+async function fetchSound(name) {
+ if (!sounds[name] && name != "sounds/pause.wav") {
+ currentlyFetching[name] = true
+ let newSound = await fetch(name).then(res => res.arrayBuffer()).then(buffer => soundcloud.decodeAudioData(buffer))
+ sounds[name] = newSound
+ delete currentlyFetching[name]
+ }
+}
+
+async function playSound(name, soundSettings={}) {
+ if (!name || name == "sounds/_pause.wav") return
+ if (currentlyFetching[name] && !soundSettings.playAt) return
+ if (!sounds[name]) await fetchSound(name)
+ let snd = new AudioBufferSourceNode(soundcloud, { buffer: sounds[name], playbackRate: soundSettings.pitch || 1 })
+ let vol = new GainNode(soundcloud, { gain: !isNaN(soundSettings.volume) ? soundSettings.volume : 0.5 })
+ vol.connect(soundcloud.destination)
+ snd.connect(vol)
+
+ if (soundSettings.stopPrevious) { // clear all sounds with the same name
+ let foundSameSounds = activeSounds.filter(x => x.name == name)
+ foundSameSounds.forEach(x => killSound(x.sound, x.gainNode, false))
+ clearPlayedSounds()
+ }
+
+ let start = soundSettings.playAt || 0;
+ activeSounds.push({sound: snd, gainNode: vol, index: soundSettings.index || 0, name, pitch: soundSettings.pitch || 1, volume, cut: false, start})
+ snd.start(start)
+
+ snd.addEventListener("ended", () => {
+ killSound(snd, vol, !active)
+ })
+}
+
+function cutSounds(time) {
+ activeSounds.forEach(x => {
+ if (!x.cut && x.start <= time) {
+ x.cut = true;
+ x.sound.stop(time);
+ }
+ })
+}
+
+$('.skippableAction').each(function() {
+ $(this).html('(right click to skip this popup)')
+ $(this).attr("mobile", "(hold to skip this popup)")
+})
+
+$('#clearsounds').click(function() {
+ cancel({ stopSounds: true });
+ $('#sequence').html('');
+ $('#saveName').val('');
+ $('#sectionSettings').hide()
+ $('.popup').hide();
+ filename = "sequence"
+ saveLocation = null
+})
+
+$(document).on('keydown', function(e) {
+ if (e.originalEvent.repeat || e.target.nodeName == "INPUT" || mobile) return
+ let popupVisible = $('.popup').is(":visible")
+
+ if (e.which == 191) { // slash key (toggle menus)
+ if (shiftHeld && !$('#shortcutMenu').is(":visible")) $('#settingsMenu').toggle()
+ else if (ctrlHeld && !$('#settingsMenu').is(":visible")) $('#shortcutMenu').toggle()
+ }
+
+ else if (!popupVisible) {
+ if ([13, 32].includes(e.which)) { // enter, space
+ if (!active) $('#playBtn').triggerHandler('contextmenu')
+ else $('#stopBtn').click()
+ e.preventDefault()
+ }
+
+ else if ([38, 40].includes(e.which)) { // up, down
+
+ if (ctrlHeld) {
+ let change = e.which == 40 ? 1 : -1
+ changeSection(change, true)
+ }
+
+ else {
+ $('#sequence div:hover').first().trigger({type: "wheel", arrowDelta: e.which == 40 ? 69 : -69})
+ e.preventDefault()
+ }
+
+ }
+
+ else if (settings.proMode && e.which >= 48 && e.which <= 57) { // number keys
+ let num = e.which - 48
+ if (num <= 0) return
+ $('.hotbarTab').eq(num - 1).trigger('click')
+ }
+
+ else if (e.which == 83 && e.ctrlKey) { // ctrl + s
+ $((sexySaving && !e.shiftKey) ? '#saveBtn' : '#downloadBtn').trigger('click')
+ e.preventDefault()
+ }
+
+ else if (e.which == 79 && e.ctrlKey) { // ctrl + o
+ $("#loadBtn").trigger('click')
+ e.preventDefault()
+ }
+
+ else if (e.which == 68 && e.ctrlKey) { // ctrl + d
+ deselectSection()
+ e.preventDefault()
+ }
+
+ else if (e.which == 80 && e.ctrlKey) {
+ $('#toggleProMode').trigger('click')
+ e.preventDefault()
+ }
+
+ else if (!ctrlHeld && !altHeld && !settings.noActionShortcuts) { // actions
+ let foundAction = actions.find(x => x.shortcut == e.key.toLowerCase())
+ if (foundAction) $(`#actions .action[action="${foundAction.name}"]`).trigger("click")
+ }
+ }
+
+ // popups
+ else {
+ if (e.which == 27) { // esc
+ $('.popup:not(.importantPopup)').hide()
+ }
+
+ else if (e.which == 13) { // enter
+ $('button[actionConfirm=true]:visible').first().click()
+ }
+ }
+
+});
+
+function updateKeys(e) {
+ if (e.repeat || e.ctrlKey === undefined) return
+ if (e.key === 'Alt') { e.preventDefault() }
+ shiftHeld = e.shiftKey;
+ altHeld = e.altKey;
+ ctrlHeld = e.ctrlKey;
+ $('#sequence div:hover').trigger((shiftHeld || altHeld) ? 'mouseover' : 'mouseleave')
+ $('#sequence section:not(.ctrlHeld):hover').trigger(ctrlHeld ? 'mouseover' : 'mouseleave')
+}
+
+$(document).on('keyup keydown click wheel touchmove', updateKeys)
+$(window).on('blur focus', updateKeys)
+
+$(document).on('click', '.popup:not(.importantPopup)', function(e) {
+ if ($(e.target).is('.popup')) {
+ $('.popup').hide();
+ stash = null
+ replaceAction = null
+ }
+});
+
+$('.colorPreview').click(function() {
+ $(`.colorSelector[colorgroup=${$(this).attr("colorgroup")}`).trigger('click')
+})
+
+$('.colorSelector').on('input', function() {
+ $(`.colorPreview[colorgroup=${$(this).attr("colorgroup")}`).css("background-color", $(this).val())
+ $(`.colorTextbox[colorgroup=${$(this).attr("colorgroup")}`).val($(this).val().slice(1))
+})
+
+$('.colorTextbox').on('input', function() {
+ let cleanVal = $(this).val().toLowerCase().replace(/[^a-f0-9]/g, "").slice(0, 6)
+ $(this).val(cleanVal)
+ let colorVal = "#" + cleanVal
+ if (!colorVal.match(colorRegex)) return
+ else $('.colorSelector').val(colorVal).trigger('input')
+})
+
+// settings
+
+let settings = {}
+try {
+ settings = localStorage["🗿"] ? JSON.parse(localStorage["🗿"]) : {}
+ $('.settingBox[setting]').each(function() {
+ let setting = $(this).attr('setting')
+ let foundSetting = settings[setting]
+ if ($(this).attr('inverted')) foundSetting = !foundSetting
+ if (foundSetting) $(this).prop('checked', foundSetting)
+ })
+}
+catch(e) { console.error(e) }
+
+if (settings.pinSectionButtons) $('#sectionSettings').addClass("pinnedSettings")
+if (!settings.dontFadeProBar && settings.proMode) $('#everything').trigger('scroll')
+
+$(document).on('change click', '.settingBox', function() {
+ let settingName = $(this).attr('setting')
+ let val = $(this).prop('checked')
+ if ($(this).attr('inverted')) val = !val
+ if (!val) delete settings[settingName]
+ else settings[settingName] = val
+ localStorage["🗿"] = JSON.stringify(settings)
+
+ if (settingName == "oldSaving") {
+ if (val) disableNewSaving()
+ else enableNewSaving()
+ }
+
+ else if (settingName == "pinSectionButtons") {
+ if (settings.pinSectionButtons) {
+ if (active) $('#sectionSettings').addClass("pinnedHidden")
+ $('#sectionSettings').addClass("pinnedSettings")
+ }
+ else $('#sectionSettings').removeClass("pinnedSettings")
+ }
+
+ else if (settingName == "proMode") {
+ if (settings.proMode) {
+ $('.hotbarTab').first().trigger('click')
+ $('#proHotbar').show()
+ $('#extraPadding').show()
+ let pageHeight = $('#everything').prop("scrollHeight")
+ if (!ctrlHeld) $('#everything').animate({ scrollTop: pageHeight + 1000 })
+ }
+ else {
+ $('#proHotbar').hide()
+ $('#extraPadding').hide()
+ }
+ }
+});
+
+$('.extraSetting').hover(function() {
+ $('#settingInfo').text($(this).attr("title"))
+ $('#settingInfo').show()
+ $('#settingHelp').hide()
+}, function() {
+ $('#settingInfo').hide()
+ $('#settingHelp').show()
+})
+
+$('.extraSetting').click(function(e) {
+ if (mobile || e.isTrigger || e.target.nodeName == "INPUT") return
+ $(this).find('input').trigger('click')
+})
diff --git a/transfer.html b/transfer.html
index 1b055c76..bd0d61cb 100644
--- a/transfer.html
+++ b/transfer.html
@@ -1,81 +1,74 @@
-
-
+
-
-
-
-
-
+
-
+
- Selenite
+ Settings | Selenite
-
+
-
-
+
+
-
-
-
-
+
+
-
Welcome!
+
+ Transfer
Thank you for considering Selenite! Scroll down to view how to transfer game data from some of your favorite websites!
3kh0
Use the "Download Save" tool available on 3kh0, and click on the button below to import your data.
Import Save
- byvolp
- Download your data by visiting the Doge Miner game, clicking Settings, and importing this save (make sure to Export Save on Doge Miner if you have any data first), then go to Stats and click Refresh. This will download a file, which you can then import using the Selenite Import Utility or clicking Upload Save on the main page of Selenite.
- Video Tutorial
+ byvolp / any website with Doge Miner
+ Download your data by visiting the Doge Miner game, clicking Settings, and importing this save (make sure to Export Save on Doge Miner if you have any data first), then go to Stats and click Refresh. This will download a file, which you can then import using the Selenite Import Utility or clicking Upload Save on the main page of Selenite.
+ Video Tutorial
Other Websites
- Use our Download Save Utility to download your save from any website, as long as you can use bookmarklets!
-
-
+ Use our Download Save Utility to download your save from any website, as long as you can use bookmarklets!
+
+
+
-
+
\ No newline at end of file
diff --git a/hardestgame/hardestgame.swf b/worldshardestgame/hardestgame.swf
similarity index 100%
rename from hardestgame/hardestgame.swf
rename to worldshardestgame/hardestgame.swf
diff --git a/hardestgame/icon.png b/worldshardestgame/icon.png
similarity index 100%
rename from hardestgame/icon.png
rename to worldshardestgame/icon.png
diff --git a/hardestgame/index.html b/worldshardestgame/index.html
similarity index 100%
rename from hardestgame/index.html
rename to worldshardestgame/index.html