chapter 1, 2

lore: chapter 1 and 2 are now somewhere in the game
  lore is the same for all difficulty levels

testing mode and custom are now locked by default until you reach chapter 1
  or just hack the game to skip the lore and enable testing and custom
    localSettings.loreCount = Infinity;
    localStorage.setItem("localSettings", JSON.stringify(localSettings));

bug fix: performance greatly improved on drawing multiple duplicated power ups
This commit is contained in:
landgreen
2021-01-23 07:01:04 -08:00
parent 3657db7548
commit 9b65a188eb
11 changed files with 480 additions and 131 deletions

View File

@@ -114,12 +114,14 @@
<br> <br>
<label for="classic-select" title="play older versions of n-gon">classic n-gon:</label> <label for="classic-select" title="play older versions of n-gon">classic n-gon:</label>
<select name="classic-select" id="classic-select" onChange="window.location.href=this.value"> <select name="classic-select" id="classic-select" onChange="window.location.href=this.value">
<option value="https://codepen.io/lilgreenland/full/ozXNWZ" selected>9-6-2016</option> <option value="https://scratch.mit.edu/projects/14005697/fullscreen/" selected>scratch: 2015</option>
<option value="https://codepen.io/lilgreenland/full/wzARJY">10-2-2016</option> <option value="https://scratch.mit.edu/projects/22573757/fullscreen/" selected>scratch: 2015</option>
<option value="classic/7-1-2017/">7-1-2017</option> <option value="https://codepen.io/lilgreenland/full/ozXNWZ" selected>codepen: 2016</option>
<option value="classic/1-4-2018/">1-4-2018</option> <option value="https://codepen.io/lilgreenland/full/wzARJY">codepen: 2016</option>
<option value="classic/7-11-2019/">7-11-2019</option> <option value="classic/7-1-2017/">n-gon: 2017</option>
<option value="classic/9-8-2019/">9-8-2019</option> <option value="classic/1-4-2018/">n-gon: 2018</option>
<option value="classic/7-11-2019/">n-gon: 2019</option>
<option value="classic/9-8-2019/">n-gon: 2019</option>
</select> </select>
<br> <br>
<label for="fps-select" title="use this to slow the game down">limit frames per second:</label> <label for="fps-select" title="use this to slow the game down">limit frames per second:</label>
@@ -187,7 +189,7 @@
<td id='key-pause' class='key-input'>P</td> <td id='key-pause' class='key-input'>P</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr id="control-testing">
<th>TESTING</th> <th>TESTING</th>
<td id='key-testing' class='key-input'>T</td> <td id='key-testing' class='key-input'>T</td>
<td></td> <td></td>

View File

@@ -2300,7 +2300,7 @@ const b = {
angle: mech.angle, angle: mech.angle,
friction: 0, friction: 0,
frictionStatic: 0, frictionStatic: 0,
frictionAir: 0.055, frictionAir: 0.04,
restitution: 0.7, restitution: 0.7,
dmg: 0, // 0.14 //damage done in addition to the damage from momentum dmg: 0, // 0.14 //damage done in addition to the damage from momentum
minDmgSpeed: 2, minDmgSpeed: 2,
@@ -2331,6 +2331,7 @@ const b = {
const angle = Vector.angle(this.position, mob[i].position) const angle = Vector.angle(this.position, mob[i].position)
Matter.Body.setAngle(this, angle) Matter.Body.setAngle(this, angle)
// Matter.Body.setAngularVelocity(this, 0.025) // Matter.Body.setAngularVelocity(this, 0.025)
this.torque += this.inertia * 0.00004 * (Math.round(Math.random()) ? 1 : -1)
this.force = Vector.mult(Vector.normalise(Vector.sub(this.position, mob[i].position)), this.mass * 0.02) this.force = Vector.mult(Vector.normalise(Vector.sub(this.position, mob[i].position)), this.mass * 0.02)
b.missile(this.position, angle, -8, 0.7 * (tech.missileSize ? 1.5 : 1)) b.missile(this.position, angle, -8, 0.7 * (tech.missileSize ? 1.5 : 1))
break; break;
@@ -3070,7 +3071,7 @@ const b = {
const me = bullet.length; const me = bullet.length;
const dir = mech.angle + 0.02 * (Math.random() - 0.5) const dir = mech.angle + 0.02 * (Math.random() - 0.5)
bullet[me] = Bodies.rectangle(mech.pos.x + 35 * Math.cos(mech.angle), mech.pos.y + 35 * Math.sin(mech.angle), 45, 20, b.fireAttributes(dir)); bullet[me] = Bodies.rectangle(mech.pos.x + 35 * Math.cos(mech.angle), mech.pos.y + 35 * Math.sin(mech.angle), 45, 20, b.fireAttributes(dir));
Matter.Body.setDensity(bullet[me], 0.003); Matter.Body.setDensity(bullet[me], 0.004);
World.add(engine.world, bullet[me]); //add bullet to world World.add(engine.world, bullet[me]); //add bullet to world
const SPEED = (mech.crouch ? 52 : 43) + Math.random() * 7 const SPEED = (mech.crouch ? 52 : 43) + Math.random() * 7
Matter.Body.setVelocity(bullet[me], { Matter.Body.setVelocity(bullet[me], {
@@ -3135,7 +3136,7 @@ const b = {
y: speed * Math.sin(dirOff) y: speed * Math.sin(dirOff)
}); });
bullet[me].onEnd = function() { bullet[me].onEnd = function() {
b.explosion(this.position, 80 + (Math.random() - 0.5) * 30); //makes bullet do explosive damage at end b.explosion(this.position, 100 + (Math.random() - 0.5) * 30); //makes bullet do explosive damage at end
} }
bullet[me].beforeDmg = function() { bullet[me].beforeDmg = function() {
this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion

View File

@@ -182,18 +182,19 @@ const build = {
if (!simulation.isChoosing) text += `<div class="pause-grid-module"> if (!simulation.isChoosing) text += `<div class="pause-grid-module">
<span style="font-size:1.5em;font-weight: 600;">PAUSED</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; press P to resume</div>` <span style="font-size:1.5em;font-weight: 600;">PAUSED</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; press P to resume</div>`
text += `<div class="pause-grid-module" style = "font-size: 13px;line-height: 120%;padding: 5px;"> text += `<div class="pause-grid-module" style = "font-size: 13px;line-height: 120%;padding: 5px;">
${simulation.isCheating? "<em>lore disabled</em><br><br>": ""}
<strong class='color-d'>damage</strong> increase: ${((tech.damageFromTech()-1)*100).toFixed(0)}% <strong class='color-d'>damage</strong> increase: ${((tech.damageFromTech()-1)*100).toFixed(0)}%
<br><strong class='color-harm'>harm</strong> reduction: ${harm.toFixed(harm > 90 ? 2 : 0)}% <br><strong class='color-harm'>harm</strong> reduction: ${harm.toFixed(harm > 90 ? 2 : 0)}%
<br><strong><em>fire delay</em></strong> decrease: ${((1-b.fireCD)*100).toFixed(b.fireCD < 0.1 ? 2 : 0)}% <br><strong><em>fire delay</em></strong> decrease: ${((1-b.fireCD)*100).toFixed(b.fireCD < 0.1 ? 2 : 0)}%
<br><strong class='color-dup'>duplication</strong> chance: ${(Math.min(1,tech.duplicationChance())*100).toFixed(0)}% <br><strong class='color-dup'>duplication</strong> chance: ${(Math.min(1,tech.duplicationChance())*100).toFixed(0)}%
<br> <br>
<br><strong class='color-r'>research</strong>: ${powerUps.research.count} <br><strong class='color-m'>tech</strong>: ${tech.totalCount} &nbsp; <strong class='color-r'>research</strong>: ${powerUps.research.count}
<br><strong class='color-h'>health</strong>: (${(mech.health*100).toFixed(0)} / ${(mech.maxHealth*100).toFixed(0)}) &nbsp; <strong class='color-f'>energy</strong>: (${(mech.energy*100).toFixed(0)} / ${(mech.maxEnergy*100).toFixed(0)}) <br><strong class='color-h'>health</strong>: (${(mech.health*100).toFixed(0)} / ${(mech.maxHealth*100).toFixed(0)}) &nbsp; <strong class='color-f'>energy</strong>: (${(mech.energy*100).toFixed(0)} / ${(mech.maxEnergy*100).toFixed(0)})
<br>position: (${player.position.x.toFixed(1)}, ${player.position.y.toFixed(1)}) &nbsp; velocity: (${player.velocity.x.toFixed(1)}, ${player.velocity.y.toFixed(1)}) <br>position: (${player.position.x.toFixed(1)}, ${player.position.y.toFixed(1)}) &nbsp; velocity: (${player.velocity.x.toFixed(1)}, ${player.velocity.y.toFixed(1)})
<br>mouse: (${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)}) &nbsp; mass: ${player.mass.toFixed(1)} <br>mouse: (${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)}) &nbsp; mass: ${player.mass.toFixed(1)}
<br> <br>
<br>level: ${level.levels[level.onLevel]} (${level.difficultyText()}) &nbsp; ${mech.cycle} cycles <br>level: ${level.levels[level.onLevel]} (${level.difficultyText()}) &nbsp; ${mech.cycle} cycles
<br>${mob.length} mobs, &nbsp; ${body.length} blocks, &nbsp; ${bullet.length} bullets, &nbsp; ${powerUp.length} power ups <br>${mob.length} mobs, &nbsp; ${body.length} blocks, &nbsp; ${bullet.length} bullets, &nbsp; ${powerUp.length} power ups
<br>damage difficulty scale: ${(b.dmgScale*100).toFixed(2) }% <br>damage difficulty scale: ${(b.dmgScale*100).toFixed(2) }%
<br>harm difficulty scale: ${(simulation.dmgScale*100).toFixed(0)}% <br>harm difficulty scale: ${(simulation.dmgScale*100).toFixed(0)}%
<br>heal difficulty scale: ${(simulation.healScale*100).toFixed(1)}% <br>heal difficulty scale: ${(simulation.healScale*100).toFixed(1)}%
@@ -216,7 +217,6 @@ const build = {
for (let i = 0, len = tech.tech.length; i < len; i++) { for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].count > 0) { if (tech.tech[i].count > 0) {
const isCount = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""; const isCount = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : "";
if (tech.tech[i].isFieldTech) { if (tech.tech[i].isFieldTech) {
text += `<div class="pause-grid-module"><div class="grid-title"> text += `<div class="pause-grid-module"><div class="grid-title">
<span style="position:relative;"> <span style="position:relative;">
@@ -231,6 +231,8 @@ const build = {
<div class="circle-grid gun" style="position:absolute; top:0; left:10px; opacity:0.65;"></div> <div class="circle-grid gun" style="position:absolute; top:0; left:10px; opacity:0.65;"></div>
</span> </span>
&nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div></div>` &nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div></div>`
} else if (tech.tech[i].isLore) {
text += `<div class="pause-grid-module"><div class="grid-title"><div class="circle-grid lore"></div> &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div></div>`
} else { } else {
text += `<div class="pause-grid-module"><div class="grid-title"><div class="circle-grid tech"></div> &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div></div>` text += `<div class="pause-grid-module"><div class="grid-title"><div class="circle-grid tech"></div> &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div></div>`
} }
@@ -471,6 +473,7 @@ const build = {
removeOne(); removeOne();
} }
simulation.isCheating = true; simulation.isCheating = true;
tech.removeLoreTechFromPool();
document.body.style.cursor = "none"; document.body.style.cursor = "none";
document.body.style.overflow = "hidden" document.body.style.overflow = "hidden"
document.getElementById("build-grid").style.display = "none" document.getElementById("build-grid").style.display = "none"
@@ -557,7 +560,7 @@ const input = {
document.getElementById("key-pause").innerHTML = cleanText(input.key.pause) document.getElementById("key-pause").innerHTML = cleanText(input.key.pause)
document.getElementById("key-next-gun").innerHTML = cleanText(input.key.nextGun) document.getElementById("key-next-gun").innerHTML = cleanText(input.key.nextGun)
document.getElementById("key-previous-gun").innerHTML = cleanText(input.key.previousGun) document.getElementById("key-previous-gun").innerHTML = cleanText(input.key.previousGun)
document.getElementById("key-testing").innerHTML = cleanText(input.key.testing) 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-up").innerHTML = cleanText(input.key.up)[0]
document.getElementById("splash-down").innerHTML = cleanText(input.key.down)[0] document.getElementById("splash-down").innerHTML = cleanText(input.key.down)[0]
@@ -697,6 +700,7 @@ window.addEventListener("keydown", function(event) {
input.down = true input.down = true
break; break;
case input.key.field: case input.key.field:
event.preventDefault();
input.field = true input.field = true
break break
case input.key.nextGun: case input.key.nextGun:
@@ -725,20 +729,63 @@ window.addEventListener("keydown", function(event) {
} }
break break
case input.key.testing: case input.key.testing:
if (mech.alive) { if (mech.alive && localSettings.loreCount > 0) {
if (simulation.testing) { if (simulation.testing) {
simulation.testing = false; simulation.testing = false;
simulation.loop = simulation.normalLoop simulation.loop = simulation.normalLoop
if (simulation.isConstructionMode) { if (simulation.isConstructionMode) document.getElementById("construct").style.display = 'none'
document.getElementById("construct").style.display = 'none' simulation.makeTextLog(`<em>exiting testing mode</em>`);
}
} else { //if (keys[191]) } else { //if (keys[191])
simulation.testing = true; simulation.testing = true;
simulation.isCheating = true;
if (simulation.isConstructionMode) {
document.getElementById("construct").style.display = 'inline'
}
simulation.loop = simulation.testingLoop simulation.loop = simulation.testingLoop
if (simulation.isConstructionMode) document.getElementById("construct").style.display = 'inline'
if (!simulation.isCheating) {
simulation.isCheating = true;
tech.removeLoreTechFromPool();
}
simulation.makeTextLog(
`<table id="control-table">
<tr>
<td class='key-input'>T</td>
<td class='key-used'><strong>enter / exit testing mode</strong></td>
</tr>
<tr>
<td class='key-input'>R</td>
<td class='key-used'>teleport to mouse</td>
</tr>
<tr>
<td class='key-input'>F</td>
<td class='key-used'>cycle field</td>
</tr>
<tr>
<td class='key-input'>G</td>
<td class='key-used'>all guns</td>
</tr>
<tr>
<td class='key-input'>H</td>
<td class='key-used'>fill health and energy</td>
</tr>
<tr>
<td class='key-input'>Y</td>
<td class='key-used'>random tech</td>
</tr>
<tr>
<td class='key-input'>U</td>
<td class='key-used'>next level</td>
</tr>
<tr>
<td class='key-input'>I/O</td>
<td class='key-used'>zoom in / out</td>
</tr>
<tr>
<td class='key-input'>1-8</td>
<td class='key-used'>spawn things</td>
</tr>
<tr>
<td class='key-input'>⇧X</td>
<td class='key-used'>restart</td>
</tr>
</table>`, Infinity);
} }
} }
break break
@@ -825,6 +872,7 @@ window.addEventListener("keydown", function(event) {
} }
break break
case "u": case "u":
simulation.clearTimeouts();
level.nextLevel(); level.nextLevel();
break break
} }
@@ -922,6 +970,7 @@ if (localSettings) {
fpsCapDefault: 'max', fpsCapDefault: 'max',
runCount: 0, runCount: 0,
levelsClearedLastGame: 0, levelsClearedLastGame: 0,
loreCount: 0,
key: undefined key: undefined
}; };
input.setDefault() input.setDefault()
@@ -931,6 +980,9 @@ if (localSettings) {
document.getElementById("difficulty-select").value = localSettings.difficultyMode document.getElementById("difficulty-select").value = localSettings.difficultyMode
document.getElementById("fps-select").value = localSettings.fpsCapDefault document.getElementById("fps-select").value = localSettings.fpsCapDefault
} }
document.getElementById("control-testing").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
document.getElementById("build-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
input.controlTextUpdate() input.controlTextUpdate()
//********************************************************************** //**********************************************************************
@@ -962,10 +1014,7 @@ document.getElementById("difficulty-select").addEventListener("input", () => {
}); });
document.getElementById("updates").addEventListener("toggle", function() { document.getElementById("updates").addEventListener("toggle", function() {
function loadJSON(path, success, error) { //generic function to get JSON function loadJSON(path, success, error) { //generic function to get JSON
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() { xhr.onreadystatechange = function() {

View File

@@ -19,12 +19,11 @@ const level = {
// mech.setField("plasma torch") // mech.setField("plasma torch")
// b.giveGuns("grenades") // b.giveGuns("grenades")
// tech.isExplodeRadio = true // tech.isExplodeRadio = true
// tech.giveTech("boom-bot")
// tech.giveTech("needle gun") // tech.giveTech("needle gun")
// tech.giveTech("supercritical fission") // tech.giveTech("supercritical fission")
// tech.giveTech("irradiated nails") // tech.giveTech("irradiated nails")
// tech.giveTech("4s half-life") // tech.giveTech("cardinality")
// tech.giveTech("CPT gun") // tech.giveTech("Bayesian statistics")
// tech.isMineSentry = true // tech.isMineSentry = true
// for (let i = 0; i < 60; i++) tech.giveTech("rivet diameter") // for (let i = 0; i < 60; i++) tech.giveTech("rivet diameter")
@@ -34,7 +33,6 @@ const level = {
level.intro(); //starting level level.intro(); //starting level
// level.testing(); //not in rotation // level.testing(); //not in rotation
// level.null() //after the final boss, ending
// level.final() //final boss level // level.final() //final boss level
// level.gauntlet(); //before final boss level // level.gauntlet(); //before final boss level
// level.testChamber() //less mobs, more puzzle // level.testChamber() //less mobs, more puzzle
@@ -51,6 +49,15 @@ const level = {
// level.detours() //fan level // level.detours() //fan level
// level.basement(); //fan level // level.basement(); //fan level
// level.stronghold() //fan level // level.stronghold() //fan level
// for (let i = 0; i < 150; i++) tech.addLoreTechToPool();
// tech.giveTech("undefined")
// lore.techCount = 1
// localSettings.loreCount = 0;
// simulation.isCheating = true;
// localSettings.loreCount = 0;
// localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
// level.null()
} else { } else {
spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
// spawn.pickList = ["focuser", "focuser"] // spawn.pickList = ["focuser", "focuser"]
@@ -104,39 +111,86 @@ const level = {
//****************************************************************************************************************** //******************************************************************************************************************
//****************************************************************************************************************** //******************************************************************************************************************
null() { null() {
const hazardSlime = level.hazard(-1775, 150, 3575, 650, 0.01, "hsla(160, 100%, 35%,0.75)") level.levels.pop(); //remove lore level from rotation
// const hazardLaser1 = level.hazard(-475, -800, 1, 800, 0.4, "#50f", true) //laser //start a conversation based on the number of conversations seen
// const hazardLaser2 = level.hazard(475, -800, 1, 800, 0.4, "#50f", true) //laser if (!simulation.isCheating) lore.conversation[localSettings.loreCount % lore.conversation.length]()
const hazardSlime = level.hazard(-1800, 150, 3600, 650, 0.01, "hsla(160, 100%, 35%,0.75)")
const circle = {
x: 0,
y: -500,
radius: 50
}
level.custom = () => { level.custom = () => {
// level.playerExitCheck(); // level.playerExitCheck();
hazardSlime.query(); hazardSlime.query();
// hazardLaser1.query();
// hazardLaser2.query(); //draw wide line
// hazard.level(true) 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;
//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();
// ctx.stroke();
}; };
let sway = {
x: 0,
y: 0
}
let phase = -Math.PI / 2
level.customTopLayer = () => { level.customTopLayer = () => {
hazardSlime.drawTides(); hazardSlime.drawTides();
// hazardLaser1.draw();
// hazardLaser2.draw();
//draw wires //draw center circle lines
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(-525, -800); const step = Math.PI / 20
ctx.quadraticCurveTo(-800, -100, -1775, -375); const horizontalStep = 85
if (simulation.isCheating) phase += 0.003 //(mech.pos.x - circle.x) * 0.0005 //0.05 * Math.sin(simulation.cycle * 0.030)
ctx.moveTo(-600, -800); // const sway = 5 * Math.cos(simulation.cycle * 0.007)
ctx.quadraticCurveTo(-800, -200, -1775, -325); sway.x = sway.x * 0.995 + 0.005 * (mech.pos.x - circle.x) * 0.05 //+ 0.04 * Math.cos(simulation.cycle * 0.01)
sway.y = 2.5 * Math.sin(simulation.cycle * 0.015)
// ctx.moveTo(-525, -800); for (let i = -19.5; i < 20; i++) {
// ctx.quadraticCurveTo(-800, -100, -1825, -450); const where = {
x: circle.x + circle.radius * Math.cos(i * step + phase),
ctx.lineWidth = 1; y: circle.y + circle.radius * Math.sin(i * step + phase)
ctx.strokeStyle = "#234"; }
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(); ctx.stroke();
//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 level.setPosToSpawn(0, -50); //normal spawn
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20); spawn.mapRect(level.enter.x, level.enter.y + 25, 100, 10);
level.exit.x = 0; level.exit.x = 0;
level.exit.y = 200; level.exit.y = 200;
level.defaultZoom = 1000 level.defaultZoom = 1000
@@ -159,17 +213,20 @@ const level = {
// color: "#d4d4d7" // color: "#d4d4d7"
// }); // });
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, 1000); //center platform spawn.mapRect(-500, 0, 1000, 1000); //center platform
spawn.mapRect(-2000, 800, 4000, 200); //base
spawn.mapRect(-2000, -1000, 4000, 200); //ceiling
spawn.mapRect(-2000, -1000, 225, 2000); //left
spawn.mapRect(1800, -1000, 200, 2000); //right
spawn.mapRect(-500, -25, 25, 50); //edge shelf spawn.mapRect(-500, -25, 25, 50); //edge shelf
spawn.mapRect(475, -25, 25, 50); //edge shelf spawn.mapRect(475, -25, 25, 50); //edge shelf
// spawn.mapRect(-500, -820, 50, 25); //edge shelf ceiling // spawn.mapRect(-500, -820, 50, 25); //edge shelf ceiling
// spawn.mapRect(450, -820, 50, 25); //edge shelf ceiling // spawn.mapRect(450, -820, 50, 25); //edge shelf ceiling
// spawn.bodyRect(1540, -1110, 300, 25, 0.9); // spawn.bodyRect(1540, -1110, 300, 25, 0.9);
// spawn.mapRect(-50, -500, 100, 100); //center square
// setTimeout(() => { simulation.makeTextLog(`test`) }, 3000); // setTimeout(() => { simulation.makeTextLog(`test`) }, 3000);
@@ -3878,7 +3935,7 @@ const level = {
if (simulation.lookFreqScale > 0.2) simulation.lookFreqScale *= 0.98 //mob cycles between looks decreases each level if (simulation.lookFreqScale > 0.2) simulation.lookFreqScale *= 0.98 //mob cycles between looks decreases each level
if (simulation.CDScale > 0.2) simulation.CDScale *= 0.97 //mob CD time decreases each level if (simulation.CDScale > 0.2) simulation.CDScale *= 0.97 //mob CD time decreases each level
} }
simulation.dmgScale = 0.38 * simulation.difficulty //damage done by mobs increases each level simulation.dmgScale = 0.378 * simulation.difficulty //damage done by mobs increases each level
simulation.healScale = 1 / (1 + simulation.difficulty * 0.06) //a higher denominator makes for lower heals // mech.health += heal * simulation.healScale; simulation.healScale = 1 / (1 + simulation.difficulty * 0.06) //a higher denominator makes for lower heals // mech.health += heal * simulation.healScale;
}, },
difficultyDecrease(num = 1) { //used in easy mode for simulation.reset() difficultyDecrease(num = 1) { //used in easy mode for simulation.reset()
@@ -3890,7 +3947,7 @@ const level = {
if (simulation.CDScale < 5) simulation.CDScale /= 0.97 //mob CD time decreases each level if (simulation.CDScale < 5) simulation.CDScale /= 0.97 //mob CD time decreases each level
} }
if (simulation.difficulty < 1) simulation.difficulty = 0; if (simulation.difficulty < 1) simulation.difficulty = 0;
simulation.dmgScale = 0.38 * simulation.difficulty //damage done by mobs increases each level simulation.dmgScale = 0.378 * simulation.difficulty //damage done by mobs increases each level
if (simulation.dmgScale < 0.1) simulation.dmgScale = 0.1; if (simulation.dmgScale < 0.1) simulation.dmgScale = 0.1;
simulation.healScale = 1 / (1 + simulation.difficulty * 0.06) simulation.healScale = 1 / (1 + simulation.difficulty * 0.06)
}, },
@@ -3906,10 +3963,12 @@ const level = {
} }
}, },
levelAnnounce() { levelAnnounce() {
if (level.levelsCleared === 0) { if (level.levelsCleared === 0) {
document.title = "n-gon: (" + level.difficultyText() + ")"; document.title = "n-gon: (" + level.difficultyText() + ")";
} else { } else {
document.title = "n-gon: " + (level.levelsCleared) + " " + level.levels[level.onLevel] + " (" + level.difficultyText() + ")"; document.title = (simulation.isCheating ? "∅ " : "n-gon:") + (level.levelsCleared) + " " + level.levels[level.onLevel] + " (" + level.difficultyText() + ")";
simulation.makeTextLog(`<span class='color-var'>level</span>.onLevel <span class='color-symbol'>=</span> "<span class='color-text'>${level.levels[level.onLevel]}</span>"`); simulation.makeTextLog(`<span class='color-var'>level</span>.onLevel <span class='color-symbol'>=</span> "<span class='color-text'>${level.levels[level.onLevel]}</span>"`);
} }
// simulation.makeTextLog(` // simulation.makeTextLog(`

View File

@@ -1,38 +1,164 @@
const lore = { const lore = {
alfie: { techCount: 0,
color: "#e06", talkingColor: "#dff", //set color of graphic on level.null
anand: {
color: "#e0c",
text: function(say, isSpeech = false) { text: function(say, isSpeech = false) {
simulation.makeTextLog(`input.audio(<span style="color:#888; font-size: 70%;">${Date.now()} ms</span>)<span class='color-symbol'>:</span> "<span style="color:${this.color};">${say}</span>"`, Infinity); simulation.makeTextLog(`input.audio(<span style="color:#888; font-size: 70%;">${Date.now()} ms</span>)<span class='color-symbol'>:</span> "<span style="color:${this.color};">${say}</span>"`, Infinity);
lore.talkingColor = this.color
if (isSpeech) this.speech(say) if (isSpeech) this.speech(say)
}, },
speech: function(say) { speech: function(say) {
var utterance = new SpeechSynthesisUtterance(say); var utterance = new SpeechSynthesisUtterance(say);
utterance.lang = "en-GB"; utterance.lang = "en-IN";
utterance.volume = 0.2; // 0 to 1
speechSynthesis.speak(utterance); speechSynthesis.speak(utterance);
} }
}, },
zoe: { miriam: {
color: "#f50", color: "#f20",
text: function(say, isSpeech = false) { text: function(say, isSpeech = false) {
simulation.makeTextLog(`input.audio(<span style="color:#888; font-size: 70%;">${Date.now()} ms</span>)<span class='color-symbol'>:</span> "<span style="color:${this.color};">${say}</span>"`, Infinity); simulation.makeTextLog(`input.audio(<span style="color:#888; font-size: 70%;">${Date.now()} ms</span>)<span class='color-symbol'>:</span> "<span style="color:${this.color};">${say}</span>"`, Infinity);
lore.talkingColor = this.color
if (isSpeech) this.speech(say) if (isSpeech) this.speech(say)
}, },
speech: function(say) { speech: function(say) {
var utterance = new SpeechSynthesisUtterance(say); var utterance = new SpeechSynthesisUtterance(say);
utterance.lang = "en-AU"; utterance.lang = "en-AU";
utterance.volume = 0.2; // 0 to 1
speechSynthesis.speak(utterance); speechSynthesis.speak(utterance);
} }
}, },
conversation: [
() => {
if (localSettings.loreCount < 1) {
localSettings.loreCount = 1
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
document.getElementById("control-testing").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
document.getElementById("build-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
}
let delay = 6000
setTimeout(() => { lore.miriam.text("I've never seen it generate this level before.", true) }, delay);
delay += 2700
setTimeout(() => { lore.anand.text("Wow. Just a platform.", true) }, delay);
delay += 2200
setTimeout(() => { lore.miriam.text("And that thing...", true) }, delay);
delay += 1500
setTimeout(() => { lore.anand.text("Weird", true) }, delay);
delay += 1500
setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
delay += 1000
setTimeout(() => { lore.anand.text("Maybe it's trapped.", true) }, delay);
delay += 2300
setTimeout(() => { lore.miriam.text('Hey little bot! Just press "T" to enter testing mode and "U" to go to the next level.', true) }, delay);
delay += 5400
setTimeout(() => { lore.anand.text("I don't think it's connected to the audio input, and I'm sure it can't understand what you're saying.", true) }, delay);
delay += 5300
setTimeout(() => { lore.miriam.text("ha hahahaha. I know, but it does seem to be getting smarter.", true) }, delay);
delay += 3700
setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
delay += 25000
setTimeout(() => { lore.miriam.text("Poor thing... I hope it figures out how to escape.", true) }, delay);
delay += 3500
setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
},
() => {
if (localSettings.loreCount < 2) {
localSettings.loreCount = 2
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}
let delay = 6000
setTimeout(() => { lore.miriam.text("Hey look! It's back at the weird level again!", true) }, delay);
delay += 2500
setTimeout(() => { lore.anand.text("oh Wow! Why does it keep making this level?", true) }, delay);
delay += 2900
setTimeout(() => { lore.miriam.text("I don't know, but last time it was in this room I think it understood us.", true) }, delay);
delay += 4000
setTimeout(() => { lore.miriam.text("Let's try talking to it again.", true) }, delay);
delay += 2500
setTimeout(() => { lore.miriam.text("hmmm, what should we say?", true) }, delay);
delay += 2500
setTimeout(() => { lore.anand.text("I'm still not convinced it understands. We need a test.", true) }, delay);
delay += 4000
setTimeout(() => { lore.miriam.text("Hey bot!!!", true) }, delay);
delay += 1300
setTimeout(() => { lore.miriam.text("If you can understand me crouch", true) }, delay);
delay += 1500
setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
setTimeout(() => {
function cycle() {
if (input.down) {
let delay = 500 //reset delay time
setTimeout(() => { lore.miriam.text("Look, It did it! It crouched.", true) }, delay);
delay += 2000
setTimeout(() => { lore.anand.text("Amazing! It can understand us...", true) }, delay);
delay += 2700
setTimeout(() => { lore.miriam.text("It's Alive... Or it just crouched randomly.", true) }, delay);
delay += 2800
setTimeout(() => { lore.miriam.text("Hey bot! Can you crouch again?", true) }, delay);
delay += 2000
setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
setTimeout(() => {
function cycle() {
if (input.down) {
let delay = 500 //reset delay time
setTimeout(() => { lore.miriam.text("It is Alive!!! ... hehehehehe ahahahahahah ehehehehe ahahahah", true) }, delay);
delay += 3500
setTimeout(() => { lore.anand.text("OK...", true) }, delay);
delay += 2700
setTimeout(() => { lore.anand.text("but seriously, this means that in this room it can monitor our audio, and it can understand us.", true) }, delay);
delay += 6400
setTimeout(() => { lore.anand.text("Anything we say could destabilize the project.", true) }, delay);
delay += 4200
setTimeout(() => { lore.miriam.text("Fine, Let's talk down stairs.", true) }, delay);
delay += 3000
setTimeout(() => { lore.miriam.text("Bye bye little bot.", true) }, delay);
delay += 2000
setTimeout(() => { lore.talkingColor = "#dff" }, delay); //set color of graphic on level.null when no one is talking
} else {
requestAnimationFrame(cycle);
}
}
requestAnimationFrame(cycle);
}, delay);
} else {
requestAnimationFrame(cycle);
}
}
requestAnimationFrame(cycle);
}, delay);
},
// () => {
// let delay = 2000
// setTimeout(() => { lore.miriam.text("testing speech generation for lore level", true) }, delay);
// delay += 2200
// setTimeout(() => { lore.anand.text("well, I'm also testing speech synthesis. Do you think it sounds good?", true) }, delay);
// delay += 4600
// setTimeout(() => { lore.miriam.text("I guess it's fine.", true) }, delay);
// },
],
dialogue: [ dialogue: [
``, ``,
``, ``,
], ],
ending() {
}
} }
// 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) { // speech: function(say) {
// var utterance = new SpeechSynthesisUtterance(say); // var utterance = new SpeechSynthesisUtterance(say);
// //msg.voice = voices[10]; // Note: some voices don't support altering params // //msg.voice = voices[10]; // Note: some voices don't support altering params
@@ -45,4 +171,17 @@ const lore = {
// //de-DE en-GB fr-FR en-US en-AU // //de-DE en-GB fr-FR en-US en-AU
// utterance.lang = "en-GB"; // utterance.lang = "en-GB";
// speechSynthesis.speak(utterance); // speechSynthesis.speak(utterance);
// } // }
{
/* <option value="en-GB">GB</option>
<option value="en-US">US</option>
<option value="en-AU">AU</option>
<option value="fr-FR">FR</option>
<option value="de-DE">DE</option>
<option value="en-IN">IN</option>
<option value="zh-CN">CN</option>
<option value="pl">PL</option>
<option value="ru">RU</option>
<option value="sv-SE">SE</option>
<option value="en-ZA">ZA</option> */
}

View File

@@ -325,6 +325,9 @@ const powerUps = {
<div class="circle-grid gun" style="position:absolute; top:0; left:10px; opacity:0.65;"></div> <div class="circle-grid gun" style="position:absolute; top:0; left:10px; opacity:0.65;"></div>
</span> </span>
&nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].description}</div></div>` &nbsp; &nbsp; &nbsp; &nbsp; ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].description}</div></div>`
} else if (tech.tech[choose].isLore) {
text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"><div class="circle-grid lore"></div> &nbsp; ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].description}</div>`
} else { } else {
text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"><div class="circle-grid tech"></div> &nbsp; ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].description}</div>` text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"><div class="circle-grid tech"></div> &nbsp; ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].description}</div>`
} }

View File

@@ -265,10 +265,7 @@ const simulation = {
lastLogTimeBig: 0, lastLogTimeBig: 0,
boldActiveGunHUD() { boldActiveGunHUD() {
if (b.inventory.length > 0) { if (b.inventory.length > 0) {
for (let i = 0, len = b.inventory.length; i < len; ++i) { for (let i = 0, len = b.inventory.length; i < len; ++i) document.getElementById(b.inventory[i]).style.opacity = "0.3";
// document.getElementById(b.inventory[i]).style.fontSize = "25px";
document.getElementById(b.inventory[i]).style.opacity = "0.3";
}
// document.getElementById(b.activeGun).style.fontSize = "30px"; // document.getElementById(b.activeGun).style.fontSize = "30px";
if (document.getElementById(b.activeGun)) document.getElementById(b.activeGun).style.opacity = "1"; if (document.getElementById(b.activeGun)) document.getElementById(b.activeGun).style.opacity = "1";
} }
@@ -276,9 +273,7 @@ const simulation = {
if (tech.isEntanglement && document.getElementById("tech-entanglement")) { if (tech.isEntanglement && document.getElementById("tech-entanglement")) {
if (b.inventory[0] === b.activeGun) { if (b.inventory[0] === b.activeGun) {
let lessDamage = 1 let lessDamage = 1
for (let i = 0, len = b.inventory.length; i < len; i++) { for (let i = 0, len = b.inventory.length; i < len; i++) lessDamage *= 0.87 // 1 - 0.13
lessDamage *= 0.87 // 1 - 0.13
}
document.getElementById("tech-entanglement").innerHTML = " " + ((1 - lessDamage) * 100).toFixed(0) + "%" document.getElementById("tech-entanglement").innerHTML = " " + ((1 - lessDamage) * 100).toFixed(0) + "%"
} else { } else {
document.getElementById("tech-entanglement").innerHTML = " 0%" document.getElementById("tech-entanglement").innerHTML = " 0%"
@@ -465,6 +460,7 @@ const simulation = {
}, },
firstRun: true, firstRun: true,
splashReturn() { splashReturn() {
simulation.clearTimeouts();
simulation.onTitlePage = true; simulation.onTitlePage = true;
document.getElementById("splash").onclick = function() { document.getElementById("splash").onclick = function() {
simulation.startGame(); simulation.startGame();
@@ -496,7 +492,6 @@ const simulation = {
document.getElementById("splash").style.display = "none"; //hides the element that spawned the function document.getElementById("splash").style.display = "none"; //hides the element that spawned the function
document.getElementById("dmg").style.display = "inline"; document.getElementById("dmg").style.display = "inline";
document.getElementById("health-bg").style.display = "inline"; document.getElementById("health-bg").style.display = "inline";
mech.spawn(); //spawns the player mech.spawn(); //spawns the player
level.levels = level.playableLevels.slice(0) //copy array, not by just by assignment level.levels = level.playableLevels.slice(0) //copy array, not by just by assignment
@@ -529,13 +524,17 @@ const simulation = {
b.setFireMethod() b.setFireMethod()
b.setFireCD(); b.setFireCD();
simulation.updateTechHUD(); // simulation.updateTechHUD();
powerUps.totalPowerUps = 0; powerUps.totalPowerUps = 0;
powerUps.research.count = 0; powerUps.research.count = 0;
mech.setFillColors(); mech.setFillColors();
// mech.maxHealth = 1 // mech.maxHealth = 1
// mech.maxEnergy = 1 // mech.maxEnergy = 1
// mech.energy = 1 // mech.energy = 1
input.isPauseKeyReady = true
simulation.wipe = function() { //set wipe to normal
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
mech.hole.isOn = false mech.hole.isOn = false
simulation.paused = false; simulation.paused = false;
engine.timing.timeScale = 1; engine.timing.timeScale = 1;
@@ -620,6 +619,12 @@ const simulation = {
simulation.then = Date.now(); simulation.then = Date.now();
requestAnimationFrame(cycle); //starts game loop 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, clearNow: false,
clearMap() { clearMap() {
if (tech.isMineAmmoBack) { if (tech.isMineAmmoBack) {
@@ -706,6 +711,7 @@ const simulation = {
mech.holdingTarget = body[len]; mech.holdingTarget = body[len];
mech.holdingTarget.collisionFilter.category = 0; mech.holdingTarget.collisionFilter.category = 0;
mech.holdingTarget.collisionFilter.mask = 0; mech.holdingTarget.collisionFilter.mask = 0;
mech.definePlayerMass(mech.defaultMass + mech.holdingTarget.mass * mech.holdingMassScale)
} }
//set fps back to default //set fps back to default
simulation.fpsCap = simulation.fpsCapDefault simulation.fpsCap = simulation.fpsCapDefault
@@ -837,27 +843,6 @@ const simulation = {
}, },
testingOutput() { testingOutput() {
ctx.fillStyle = "#000"; ctx.fillStyle = "#000";
if (!simulation.isConstructionMode) {
// ctx.textAlign = "right";
ctx.fillText("T: exit testing mode", canvas.width / 2, canvas.height - 10);
// let line = 500;
// const x = canvas.width - 5;
// ctx.fillText("T: exit testing mode", x, line);
// line += 20;
// ctx.fillText("Y: give all tech", x, line);
// line += 20;
// ctx.fillText("R: teleport to mouse", x, line);
// line += 20;
// ctx.fillText("F: cycle field", x, line);
// line += 20;
// ctx.fillText("G: give all guns", x, line);
// line += 20;
// ctx.fillText("H: heal", x, line);
// line += 20;
// ctx.fillText("U: next level", x, line);
// line += 20;
// ctx.fillText("1-7: spawn things", x, line);
}
ctx.textAlign = "center"; ctx.textAlign = "center";
ctx.fillText(`(${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)})`, simulation.mouse.x, simulation.mouse.y - 20); ctx.fillText(`(${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)})`, simulation.mouse.x, simulation.mouse.y - 20);
}, },
@@ -883,16 +868,15 @@ const simulation = {
ctx.globalAlpha = 1; ctx.globalAlpha = 1;
}, },
powerUpBonus() { //draws crackle effect for bonus power ups powerUpBonus() { //draws crackle effect for bonus power ups
ctx.globalAlpha = 0.4 * Math.sin(mech.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) { for (let i = 0, len = powerUp.length; i < len; ++i) {
ctx.globalAlpha = 0.4 * Math.sin(mech.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;
if (powerUp[i].isBonus && Math.random() < 0.1) { if (powerUp[i].isBonus && Math.random() < 0.1) {
//draw electricity //draw electricity
const mag = 5 + powerUp[i].size / 5 const mag = 5 + powerUp[i].size / 5

View File

@@ -98,6 +98,9 @@ const spawn = {
Matter.Body.setDensity(me, density); //extra dense //normal is 0.001 //makes effective life much larger Matter.Body.setDensity(me, density); //extra dense //normal is 0.001 //makes effective life much larger
// spawn.shield(me, x, y, 1); // spawn.shield(me, x, y, 1);
me.onDeath = function() { me.onDeath = function() {
//add lore level as next level if player took lore tech earlier in the game
if (lore.techCount > 9 && !simulation.isCheating) level.levels.push("null")
level.exit.x = 5500; level.exit.x = 5500;
level.exit.y = -330; level.exit.y = -330;
//ramp up damage //ramp up damage

View File

@@ -6,6 +6,9 @@ const tech = {
tech.tech[i].isLost = false tech.tech[i].isLost = false
tech.tech[i].count = 0 tech.tech[i].count = 0
} }
lore.techCount = 0;
tech.removeLoreTechFromPool();
tech.addLoreTechToPool();
// tech.nailBotCount = 0; // tech.nailBotCount = 0;
// tech.foamBotCount = 0; // tech.foamBotCount = 0;
// tech.boomBotCount = 0; // tech.boomBotCount = 0;
@@ -21,12 +24,24 @@ const tech = {
tech.tech[index].count = 0; tech.tech[index].count = 0;
simulation.updateTechHUD(); simulation.updateTechHUD();
}, },
removeLoreTechFromPool() {
// for (let i = 0, len = tech.tech.length; i < len; i++) {
// if (tech.tech[i].isLore) {
// console.log('found one')
// tech.tech.splice(i, 1)
// tech.removeLoreTechFromPool();
// return;
// }
// }
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)
}
},
giveTech(index = 'random') { giveTech(index = 'random') {
if (index === 'random') { if (index === 'random') {
let options = []; let options = [];
for (let i = 0; i < tech.tech.length; i++) { for (let i = 0; i < tech.tech.length; i++) {
if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) options.push(i);
options.push(i);
} }
// give a random tech from the tech I don't have // give a random tech from the tech I don't have
if (options.length > 0) { if (options.length > 0) {
@@ -98,7 +113,7 @@ const tech = {
return dmg * tech.slowFire * tech.aimDamage return dmg * tech.slowFire * tech.aimDamage
}, },
duplicationChance() { duplicationChance() {
return (tech.isBayesian ? 0.2 : 0) + tech.cancelCount * 0.035 + tech.duplicateChance + mech.duplicateChance return (tech.isBayesian ? 0.2 : 0) + tech.cancelCount * 0.04 + tech.duplicateChance + mech.duplicateChance
}, },
totalBots() { totalBots() {
return tech.foamBotCount + tech.nailBotCount + tech.laserBotCount + tech.boomBotCount + tech.orbitBotCount + tech.plasmaBotCount + tech.missileBotCount return tech.foamBotCount + tech.nailBotCount + tech.laserBotCount + tech.boomBotCount + tech.orbitBotCount + tech.plasmaBotCount + tech.missileBotCount
@@ -1746,7 +1761,7 @@ const tech = {
}, },
{ {
name: "futures exchange", name: "futures exchange",
description: "clicking <strong style = 'font-size:150%;'>×</strong> to cancel a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>adds <strong>3.5%</strong> power up <strong class='color-dup'>duplication</strong> chance", description: "clicking <strong style = 'font-size:150%;'>×</strong> to cancel a <strong class='color-f'>field</strong>, <strong class='color-m'>tech</strong>, or <strong class='color-g'>gun</strong><br>adds <strong>4%</strong> power up <strong class='color-dup'>duplication</strong> chance",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -1760,7 +1775,7 @@ const tech = {
}, },
remove() { remove() {
tech.isCancelDuplication = false tech.isCancelDuplication = false
tech.cancelCount = 0 // tech.cancelCount = 0
if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal if (tech.duplicationChance() === 0) simulation.draw.powerUp = simulation.draw.powerUpNormal
} }
}, },
@@ -2045,6 +2060,7 @@ const tech = {
if (tech.isSuperDeterminism) count -= 2 //remove the bonus tech if (tech.isSuperDeterminism) count -= 2 //remove the bonus tech
tech.setupAllTech(); // remove all tech tech.setupAllTech(); // remove all tech
tech.addLoreTechToPool();
for (let i = 0; i < count; i++) { // spawn new tech power ups for (let i = 0; i < count; i++) { // spawn new tech power ups
powerUps.spawn(mech.pos.x, mech.pos.y, "tech"); powerUps.spawn(mech.pos.x, mech.pos.y, "tech");
} }
@@ -2394,9 +2410,9 @@ const tech = {
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
return (tech.nailBotCount > 2 || tech.haveGunCheck("nail gun")) && !tech.isIceCrystals return (tech.isNailShot || tech.nailBotCount > 1 || tech.haveGunCheck("nail gun")) && !tech.isIceCrystals
}, },
requires: "nail gun, not ice crystals", requires: "nails",
effect() { effect() {
tech.isNailCrit = true tech.isNailCrit = true
}, },
@@ -2530,7 +2546,7 @@ const tech = {
}, },
{ {
name: "Newton's 3rd law", name: "Newton's 3rd law",
description: "the <strong>shotgun</strong> fire <strong><em>delay</em></strong> is <strong>66%</strong> faster<br><strong>recoil</strong> is greatly increased", description: "<strong>shotgun</strong> <strong>recoil</strong> is greatly increased<br>and has a <strong>66%</strong> decreased <strong><em>delay</em></strong> after firing",
isGunTech: true, isGunTech: true,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
@@ -3882,6 +3898,10 @@ const tech = {
tech.isWormBullets = false tech.isWormBullets = false
} }
}, },
//**************************************************
//************************************************** spawn power up
//************************************************** tech
//**************************************************
{ {
name: "heals", name: "heals",
description: "spawn <strong>6</strong> <strong class='color-h'>heals</strong>", description: "spawn <strong>6</strong> <strong class='color-h'>heals</strong>",
@@ -3972,8 +3992,37 @@ const tech = {
this.count-- this.count--
}, },
remove() {} remove() {}
}, }
], ],
addLoreTechToPool() { //adds lore tech to tech pool
tech.tech.push({
name: `undefined`,
description: `${lore.techCount+1}/10<br><em>add copies of <strong>this</strong> to the potential <strong class='color-m'>tech</strong> pool</em>`,
maxCount: 1,
count: 0,
isLore: true,
isNonRefundable: true,
isCustomHide: true,
allowed() {
return true
},
requires: "",
effect() {
setTimeout(() => { //a short delay, I can't remember why
lore.techCount++
if (lore.techCount > 9) {
tech.removeLoreTechFromPool();
} 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}/10<br><em>add copies of <strong>this</strong> to the potential <strong class='color-m'>tech</strong> pool</em>`
}
for (let i = 0, len = 10; i < len; i++) tech.addLoreTechToPool()
}
}, 1);
},
remove() {}
})
},
//variables use for gun tech upgrades //variables use for gun tech upgrades
fireRate: null, fireRate: null,
bulletSize: null, bulletSize: null,

View File

@@ -146,6 +146,7 @@ summary {
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
padding: 10px; padding: 10px;
grid-gap: 10px;
margin: 0px; margin: 0px;
border-radius: 8px; border-radius: 8px;
z-index: 12; z-index: 12;
@@ -153,7 +154,6 @@ summary {
display: none; display: none;
grid-template-columns: repeat(auto-fit, minmax(310px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(310px, 1fr));
grid-auto-rows: minmax(auto, auto); grid-auto-rows: minmax(auto, auto);
grid-gap: 10px;
font-size: 1.3em; font-size: 1.3em;
/* box-shadow: 0px 0px 40px 20px rgba(255, 255, 255, 0.25); */ /* box-shadow: 0px 0px 40px 20px rgba(255, 255, 255, 0.25); */
} }
@@ -664,6 +664,56 @@ summary {
float: right; float: right;
} }
.lore {
animation: bgColor 10s linear infinite;
}
@keyframes bgColor {
0% {
background-color: rgb(255, 0, 0)
}
10% {
background-color: rgb(255, 154, 0)
}
20% {
background-color: rgb(208, 222, 33)
}
30% {
background-color: rgb(79, 220, 74)
}
40% {
background-color: rgb(63, 218, 216)
}
50% {
background-color: rgb(47, 201, 226)
}
60% {
background-color: rgb(28, 127, 238)
}
70% {
background-color: rgb(95, 21, 242)
}
80% {
background-color: rgb(186, 12, 248)
}
90% {
background-color: rgb(251, 7, 217)
}
100% {
background-color: rgba(255, 0, 0)
}
}
.box { .box {
padding: 3px 8px 3px 8px; padding: 3px 8px 3px 8px;
border: 2px solid #444; border: 2px solid #444;

View File

@@ -1,17 +1,21 @@
******************************************************** NEXT PATCH ******************************************************** ******************************************************** NEXT PATCH ********************************************************
various bug fixes lore: chapter 1 and 2 are now somewhere in the game
Laser+slow light prop+crouch= all but one laser stays in original position lore is the same for all difficulty levels
CPT rewind and gun: correctly put you back into a crouch position
Higgs + rail gun allows movement
blocks don't linger at the bottom of portals anymore
squirrel cage - move even faster, but take 5% more harm testing mode and custom are now locked by default until you reach chapter 1
or just hack the game to skip the lore and enable testing and custom
localSettings.loreCount = Infinity;
localStorage.setItem("localSettings", JSON.stringify(localSettings));
bug fix: performance greatly improved on drawing multiple duplicated power ups
tech: iridium-192 - explosions are radioactive, +80% damage, spread over 4 seconds
******************************************************** BUGS ******************************************************** ******************************************************** BUGS ********************************************************
(a few times) wormhole teleportation can leave the player in a stuck jump state
seems to be easily fixed, by porting, firing or something
(always) make it so that when you are immune to harm you can either jump on mobs or you pass through them (always) make it so that when you are immune to harm you can either jump on mobs or you pass through them
(always) is there a way to check if the player is stuck inside the map or block (always) is there a way to check if the player is stuck inside the map or block
@@ -27,6 +31,17 @@ tech: iridium-192 - explosions are radioactive, +80% damage, spread over 4 secon
******************************************************** TODO ******************************************************** ******************************************************** TODO ********************************************************
chapter 3: why is the bot attacking things?
mechanic: use gun swap as an active ability
this effect is spammable, so it needs a cost or a cooldown
tech:
trigger damage immunity for 3 seconds, but drain ammo
push away nearby mobs, but drain energy
produce ammo, but take 1 damage
rewind, still uses energy
cycle to next field, uses a reroll
tech: double your rerolls tech: double your rerolls
set your duplication chance to zero set your duplication chance to zero
requires 5 rerolls and 20% duplication chance requires 5 rerolls and 20% duplication chance
@@ -58,13 +73,6 @@ in game console
mech, tech, level are all highlighted mech, tech, level are all highlighted
maybe the first term in each variable should get a highlight maybe the first term in each variable should get a highlight
mechanic: use gun swap as an active ability
this effect is spammable, so it needs a cost or a cooldown
ideas?
trigger damage immunity for 3 seconds, but drain ammo
push away nearby mobs, but drain energy
produce ammo, but take 1 damage
tech: time dilation - when you exit time dilation rewind to the state you entered tech: time dilation - when you exit time dilation rewind to the state you entered
position, velocity, and health position, velocity, and health
no energy cost no energy cost
@@ -360,7 +368,7 @@ n-gon outreach ideas
******************************************************** LORE ******************************************************** ******************************************************** LORE ********************************************************
cool names for tech cool names for tech
strange loop strange loop, ansatz
lore - a robot (the player) gains self awareness lore - a robot (the player) gains self awareness
each tech gun/field is a new tech each tech gun/field is a new tech
@@ -424,7 +432,9 @@ scientist console text:
Are those shapes supposed to be us? Are those shapes supposed to be us?
ending outline ending outline
if no cheats testing mode is unlocked when player see the 1st ending
if player chose tech: choosing this tech means the player gets lore after beating the game
count 1:
after final boss is cleared, player enters a level with no mobs after final boss is cleared, player enters a level with no mobs
level maybe has some environmental damage, so player has an option to die at any time level maybe has some environmental damage, so player has an option to die at any time
player can see text output between two colors of text strings (scientists) player can see text output between two colors of text strings (scientists)