diff --git a/js/bullets.js b/js/bullets.js index 9a94e9e..d8e61a4 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -150,7 +150,8 @@ const b = { } }, { - name: "fluoroantimonic acid", + name: "fluoroantimonic acid", + nameInfo: "", description: "each bullet does instant acid damage
active when you are above 80% base health", maxCount: 1, count: 0, @@ -169,7 +170,8 @@ const b = { } }, { - name: "negative feedback", + name: "negative feedback", + nameInfo: "", description: "do extra damage at low health
up to 50% increase when near death", maxCount: 1, count: 0, @@ -576,7 +578,8 @@ const b = { } }, { - name: "entanglement ", + name: "entanglement", + nameInfo: "", description: "16% less harm for each gun in your inventory
while your first gun is equipped", maxCount: 1, count: 0, diff --git a/js/game.js b/js/game.js index eddafd9..0c50b94 100644 --- a/js/game.js +++ b/js/game.js @@ -61,14 +61,19 @@ const game = { game.isTimeSkipping = true; for (let i = 0; i < cycles; i++) { game.cycle++; - // mech.cycle++; + mech.cycle++; game.gravity(); Engine.update(engine, game.delta); level.checkZones(); level.checkQuery(); mech.move(); + game.checks(); mobs.loop(); + // mech.draw(); + mech.walk_cycle += mech.flipLegs * mech.Vx; + mech.hold(); + b.fire(); b.bulletActions(); } game.isTimeSkipping = false; @@ -106,6 +111,7 @@ const game = { accelScale: null, //set in levels.setDifficulty CDScale: null, //set in levels.setDifficulty lookFreqScale: null, //set in levels.setDifficulty + mouseDown: false, // dropFPS(cap = 40, time = 15) { // game.fpsCap = cap // game.fpsInterval = 1000 / game.fpsCap; @@ -202,6 +208,7 @@ const game = { if (b.mods[i].count > 0) { if (text) text += "
" //add a new line, but not on the first line text += b.mods[i].name + if (b.mods[i].nameInfo) text += b.mods[i].nameInfo if (b.mods[i].count > 1) text += ` (${b.mods[i].count}x)` } } diff --git a/js/index.js b/js/index.js index 85681cc..d0ddb82 100644 --- a/js/index.js +++ b/js/index.js @@ -12,6 +12,38 @@ const cat = { mobShield: 0x10000000, } +//example https://landgreen.github.io/sidescroller/index.html? +// &gun1=minigun&gun2=laser +// &mod1=laser-bot&mod2=mass%20driver&mod3=overcharge&mod4=laser-bot&mod5=laser-bot&field=phase%20decoherence%20field&difficulty=2 +//add ? to end of url then for each power up add +// &gun1=name&gun2=name +// &mod1=laser-bot&mod2=mass%20driver&mod3=overcharge&mod4=laser-bot&mod5=laser-bot +// &field=phase%20decoherence%20field +// &difficulty=2 +//use %20 for spaces +//difficulty is 0 easy, 1 normal, 2 hard, 4 why +function onLoadPowerUps() { + function getUrlVars() { + let vars = {}; + window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, k, v) { + vars[k] = v; + }); + return vars; + } + const set = getUrlVars() + for (const property in set) { + // console.log(`${property}: ${give[property]}`); + set[property] = set[property].replace(/%20/g, " ") + if (property.substring(0, 3) === "gun") b.giveGuns(set[property]) + if (property.substring(0, 3) === "mod") b.giveMod(set[property]) + if (property === "field") mech.setField(set[property]) + if (property === "difficulty") { + game.difficultyMode = Number(set[property]) + document.getElementById("difficulty-select").value = Number(set[property]) + } + } +} + //build build grid display const build = { pauseGrid() { @@ -148,11 +180,16 @@ const build = { start - - - reset + + + reset + + + share + +
starting level:
@@ -207,7 +244,63 @@ const build = { document.getElementById("field-0").classList.add("build-field-selected"); document.getElementById("build-grid").style.display = "grid" }, + shareURL() { + // 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 = build.generateURL(); + + // 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 + } finally { + // Remove the textarea + document.body.removeChild(textAreaEle); + } + alert('n-gon build URL copied to clip board.\nPaste it into your browser address bar.') + }, + generateURL() { + let url = "https://landgreen.github.io/sidescroller/index.html?" + let count = 0; + for (let i = 0; i < b.guns.length; i++) { + if (b.guns[i].have) { + url += `&gun${count}=${encodeURIComponent(b.guns[i].name.trim())}` + count++ + } + } + count = 0; + for (let i = 0; i < b.mods.length; i++) { + for (let j = 0; j < b.mods[i].count; j++) { + url += `&mod${count}=${encodeURIComponent(b.mods[i].name.trim())}` + count++ + } + } + url += `&field=${encodeURIComponent(mech.fieldUpgrades[mech.fieldMode].name.trim())}` + url += `&difficulty=${game.difficultyMode}` + console.log(url) + return url + }, startBuildRun() { build.isCustomSelection = false; b.modOnHealthChange() diff --git a/js/level.js b/js/level.js index a039f51..eb41ed6 100644 --- a/js/level.js +++ b/js/level.js @@ -15,13 +15,14 @@ const level = { if (level.levelsCleared === 0) { // level.difficultyIncrease(9) // b.giveGuns("vacuum bomb") - // mech.setField("time dilation field") + // mech.setField("phase decoherence field") // mech.energy = 0.1; - // b.giveMod("ground state"); + // b.giveMod("negative feedback"); // b.giveMod("photovoltaics"); + onLoadPowerUps(); - // level.intro(); //starting level - level.testingMap(); + level.intro(); //starting level + // level.testing(); // level.stronghold() // level.bosses(); // level.satellite(); @@ -75,8 +76,7 @@ const level = { if (game.difficulty < 1) game.difficulty = 0; game.healScale = 1 / (1 + game.difficulty * 0.09) }, - difficultyText() { - let mode = document.getElementById("difficulty-select").value + difficultyText(mode = document.getElementById("difficulty-select").value) { if (mode === "0") { return "easy" } else if (mode === "1") { @@ -97,7 +97,7 @@ const level = { //****************************************************************************************************************** //****************************************************************************************************************** - testingMap() { + testing() { // level.difficultyIncrease(9) //level 7 on normal, level 4 on hard, level 1.2 on why? spawn.setSpawnList(); level.defaultZoom = 1500 @@ -137,14 +137,15 @@ const level = { spawn.mapRect(2500, -1200, 200, 750); //right wall blockDoor(2585, -210) spawn.mapRect(2500, -200, 200, 300); //right wall - spawn.mapRect(4500, -1200, 200, 750); //right wall - blockDoor(4585, -210) - spawn.mapRect(4500, -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 spawn.timeSkipBoss(2900, -500) + spawn.randomMob(3200, -500) }, bosses() { @@ -193,23 +194,16 @@ const level = { spawn.mapRect(-250, -1200, 1000, 250); // shelf roof powerUps.spawnStartingPowerUps(600, -800); - 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); - } - } - blockDoor(710, -710); + spawn.blockDoor(710, -710); spawn[spawn.pickList[0]](1500, -200, 150 + Math.random() * 30); spawn.mapRect(2500, -1200, 200, 750); //right wall - blockDoor(2585, -210) + spawn.blockDoor(2585, -210) spawn.mapRect(2500, -200, 200, 300); //right wall spawn.nodeBoss(3500, -200, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); spawn.mapRect(4500, -1200, 200, 750); //right wall - blockDoor(4585, -210) + spawn.blockDoor(4585, -210) spawn.mapRect(4500, -200, 200, 300); //right wall spawn.lineBoss(5000, -200, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); diff --git a/js/player.js b/js/player.js index ac06994..730bf9f 100644 --- a/js/player.js +++ b/js/player.js @@ -1584,7 +1584,7 @@ const mech = { zeroG(powerUp, this.fieldDrawRadius); zeroG(body, this.fieldDrawRadius); } - if (mech.energy < 0) { + if (mech.energy < 0.001) { mech.fieldCDcycle = mech.cycle + 120; mech.energy = 0; } @@ -1761,57 +1761,66 @@ const mech = { mech.grabPowerUp(); mech.lookForPickUp(); - const DRAIN = 0.0001 + 0.00017 * player.speed + const DRAIN = 0.00004 + 0.00009 * player.speed if (mech.energy > DRAIN) { mech.energy -= DRAIN; - if (mech.energy < 0) { + if (mech.energy < 0.001) { mech.fieldCDcycle = mech.cycle + 120; mech.energy = 0; } + + mech.isStealth = true //isStealth disables most uses of foundPlayer() player.collisionFilter.mask = cat.map - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, mech.fieldRange, 0, 2 * Math.PI); - ctx.globalCompositeOperation = "destination-in"; //in or atop - ctx.fillStyle = `rgba(255,255,255,${mech.energy*0.5})`; - ctx.fill(); - ctx.globalCompositeOperation = "source-over"; - ctx.strokeStyle = "#000" - ctx.lineWidth = 2; - ctx.stroke(); + if (!game.isTimeSkipping) { + // game.timeSkip(1) + const drawRadius = 125 + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, drawRadius, 0, 2 * Math.PI); + ctx.fillStyle = `rgba(255,255,255,${mech.energy*0.5})`; + ctx.globalCompositeOperation = "destination-in"; //in or atop + ctx.fill(); + ctx.globalCompositeOperation = "source-over"; + ctx.strokeStyle = "#000" + ctx.lineWidth = 2; + ctx.stroke(); + ctx.beginPath(); + ctx.arc(mech.pos.x, mech.pos.y, drawRadius, 0, 2 * Math.PI); + ctx.clip(); - let inPlayer = Matter.Query.region(mob, player.bounds) - if (inPlayer.length > 0) { - for (let i = 0; i < inPlayer.length; i++) { - if (inPlayer[i].shield) { - mech.energy -= 0.005; //shields drain player energy - //draw outline of shield - ctx.fillStyle = `rgba(0, 204, 255,0.6)` - ctx.fill() - } else if (b.isModPhaseFieldDamage && mech.energy > 0.006 && inPlayer[i].dropPowerUp && !inPlayer[i].isShielded) { - inPlayer[i].damage(0.4 * b.dmgScale); //damage mobs inside the player - mech.energy -= 0.002; - - //draw outline of mob in a few random locations to show blurriness - const vertices = inPlayer[i].vertices; - const off = 30 - for (let k = 0; k < 3; k++) { - const xOff = off * (Math.random() - 0.5) - const yOff = off * (Math.random() - 0.5) - ctx.beginPath(); - ctx.moveTo(xOff + vertices[0].x, yOff + vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) { - ctx.lineTo(xOff + vertices[j].x, yOff + vertices[j].y); - } - ctx.lineTo(xOff + vertices[0].x, yOff + vertices[0].y); - // ctx.strokeStyle = "#000" - // ctx.lineWidth = 1 - // ctx.stroke() - ctx.fillStyle = "rgba(0,0,0,0.3)" + let inPlayer = Matter.Query.region(mob, player.bounds) + if (inPlayer.length > 0) { + for (let i = 0; i < inPlayer.length; i++) { + if (inPlayer[i].shield) { + mech.energy -= 0.005; //shields drain player energy + //draw outline of shield + ctx.fillStyle = `rgba(0, 204, 255,0.6)` ctx.fill() + } else if (b.isModPhaseFieldDamage && mech.energy > 0.006 && inPlayer[i].dropPowerUp && !inPlayer[i].isShielded) { + inPlayer[i].damage(0.4 * b.dmgScale); //damage mobs inside the player + mech.energy -= 0.002; + + //draw outline of mob in a few random locations to show blurriness + const vertices = inPlayer[i].vertices; + const off = 30 + for (let k = 0; k < 3; k++) { + const xOff = off * (Math.random() - 0.5) + const yOff = off * (Math.random() - 0.5) + ctx.beginPath(); + ctx.moveTo(xOff + vertices[0].x, yOff + vertices[0].y); + for (let j = 1, len = vertices.length; j < len; ++j) { + ctx.lineTo(xOff + vertices[j].x, yOff + vertices[j].y); + } + ctx.lineTo(xOff + vertices[0].x, yOff + vertices[0].y); + // ctx.strokeStyle = "#000" + // ctx.lineWidth = 1 + // ctx.stroke() + ctx.fillStyle = "rgba(0,0,0,0.3)" + ctx.fill() + } + break; } - break; } } } diff --git a/js/spawn.js b/js/spawn.js index d011008..455ae5e 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -641,52 +641,68 @@ const spawn = { let me = mob[mob.length - 1]; // me.stroke = "transparent"; //used for drawSneaker me.timeSkipLastCycle = 0 - me.eventHorizon = 1600; //required for black hole + me.eventHorizon = 1300; //required for black hole me.seeAtDistance2 = (me.eventHorizon + 1000) * (me.eventHorizon + 1000); //vision limit is event horizon - me.accelMag = 0.0001 * game.accelScale; + me.accelMag = 0.00013 * game.accelScale; // me.collisionFilter.mask = cat.player | cat.bullet // 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.018); //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) }; me.do = function () { //keep it slow, to stop issues from explosion knock backs - this.seePlayerByDistOrLOS(); + this.seePlayerCheck(); + this.attraction() + if (!game.isTimeSkipping) { + const compress = 3 + if (this.timeSkipLastCycle < game.cycle - compress && + Vector.magnitude(Vector.sub(this.position, player.position)) < this.eventHorizon) { + this.timeSkipLastCycle = game.cycle + game.timeSkip(compress) - 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; - - if (!game.isTimeSkipping) { this.fill = `rgba(0,0,0,${0.1+0.1*Math.random()})` - const compress = 3 - if (this.timeSkipLastCycle < game.cycle - compress && - Vector.magnitude(Vector.sub(this.position, player.position)) < this.eventHorizon) { - this.timeSkipLastCycle = game.cycle - game.timeSkip(compress) + this.stroke = "#000" + this.isShielded = false; + this.dropPowerUp = true; + ctx.beginPath(); + ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); + ctx.fillStyle = `rgba(255,255,255,${mech.energy*0.5})`; + 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, this.eventHorizon, 0, 2 * Math.PI); - ctx.fillStyle = `rgba(0,0,0,${0.05*Math.random()})`; - ctx.fill(); - ctx.strokeStyle = "#000"; - ctx.stroke(); - } else { - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); - ctx.fillStyle = this.fill; - ctx.fill(); - } + // 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.dropPowerUp = false; + this.seePlayer.recall = false + this.fill = "transparent" + this.stroke = "transparent" + ctx.beginPath(); + ctx.arc(this.position.x, this.position.y, this.eventHorizon, 0, 2 * Math.PI); + ctx.fillStyle = `rgba(0,0,0,${0.1*Math.random()})`; + ctx.fill(); } } + this.checkStatus(); } }, @@ -1857,6 +1873,13 @@ const spawn = { color: "#f0f0f3" }); }, + 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); + } + }, debris(x, y, width, number = Math.floor(2 + Math.random() * 9)) { for (let i = 0; i < number; ++i) { if (Math.random() < 0.15) { diff --git a/todo.txt b/todo.txt index cec10ef..e48cba6 100644 --- a/todo.txt +++ b/todo.txt @@ -2,6 +2,9 @@ mod - electromagnetic pulse - vacuum bomb removes shields and does 20% extra dam ************** TODO - n-gon ************** + +mod - spores with no target hang out about player + mod - status effects last 1 second longer cryonics : a mod that increases the freezing time of mobs. wait until you have more status effects written