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>
<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">
<option value="https://codepen.io/lilgreenland/full/ozXNWZ" selected>9-6-2016</option>
<option value="https://codepen.io/lilgreenland/full/wzARJY">10-2-2016</option>
<option value="classic/7-1-2017/">7-1-2017</option>
<option value="classic/1-4-2018/">1-4-2018</option>
<option value="classic/7-11-2019/">7-11-2019</option>
<option value="classic/9-8-2019/">9-8-2019</option>
<option value="https://scratch.mit.edu/projects/14005697/fullscreen/" selected>scratch: 2015</option>
<option value="https://scratch.mit.edu/projects/22573757/fullscreen/" selected>scratch: 2015</option>
<option value="https://codepen.io/lilgreenland/full/ozXNWZ" selected>codepen: 2016</option>
<option value="https://codepen.io/lilgreenland/full/wzARJY">codepen: 2016</option>
<option value="classic/7-1-2017/">n-gon: 2017</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>
<br>
<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></td>
</tr>
<tr>
<tr id="control-testing">
<th>TESTING</th>
<td id='key-testing' class='key-input'>T</td>
<td></td>

View File

@@ -2300,7 +2300,7 @@ const b = {
angle: mech.angle,
friction: 0,
frictionStatic: 0,
frictionAir: 0.055,
frictionAir: 0.04,
restitution: 0.7,
dmg: 0, // 0.14 //damage done in addition to the damage from momentum
minDmgSpeed: 2,
@@ -2331,6 +2331,7 @@ const b = {
const angle = Vector.angle(this.position, mob[i].position)
Matter.Body.setAngle(this, angle)
// 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)
b.missile(this.position, angle, -8, 0.7 * (tech.missileSize ? 1.5 : 1))
break;
@@ -3070,7 +3071,7 @@ const b = {
const me = bullet.length;
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));
Matter.Body.setDensity(bullet[me], 0.003);
Matter.Body.setDensity(bullet[me], 0.004);
World.add(engine.world, bullet[me]); //add bullet to world
const SPEED = (mech.crouch ? 52 : 43) + Math.random() * 7
Matter.Body.setVelocity(bullet[me], {
@@ -3135,7 +3136,7 @@ const b = {
y: speed * Math.sin(dirOff)
});
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() {
this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion

View File

@@ -182,12 +182,13 @@ const build = {
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>`
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)}%
<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 class='color-dup'>duplication</strong> chance: ${(Math.min(1,tech.duplicationChance())*100).toFixed(0)}%
<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>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)}
@@ -216,7 +217,6 @@ const build = {
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].count > 0) {
const isCount = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : "";
if (tech.tech[i].isFieldTech) {
text += `<div class="pause-grid-module"><div class="grid-title">
<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>
</span>
&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 {
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();
}
simulation.isCheating = true;
tech.removeLoreTechFromPool();
document.body.style.cursor = "none";
document.body.style.overflow = "hidden"
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-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)
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]
@@ -697,6 +700,7 @@ window.addEventListener("keydown", function(event) {
input.down = true
break;
case input.key.field:
event.preventDefault();
input.field = true
break
case input.key.nextGun:
@@ -725,20 +729,63 @@ window.addEventListener("keydown", function(event) {
}
break
case input.key.testing:
if (mech.alive) {
if (mech.alive && localSettings.loreCount > 0) {
if (simulation.testing) {
simulation.testing = false;
simulation.loop = simulation.normalLoop
if (simulation.isConstructionMode) {
document.getElementById("construct").style.display = 'none'
}
if (simulation.isConstructionMode) document.getElementById("construct").style.display = 'none'
simulation.makeTextLog(`<em>exiting testing mode</em>`);
} else { //if (keys[191])
simulation.testing = true;
simulation.isCheating = true;
if (simulation.isConstructionMode) {
document.getElementById("construct").style.display = 'inline'
}
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
@@ -825,6 +872,7 @@ window.addEventListener("keydown", function(event) {
}
break
case "u":
simulation.clearTimeouts();
level.nextLevel();
break
}
@@ -922,6 +970,7 @@ if (localSettings) {
fpsCapDefault: 'max',
runCount: 0,
levelsClearedLastGame: 0,
loreCount: 0,
key: undefined
};
input.setDefault()
@@ -931,6 +980,9 @@ if (localSettings) {
document.getElementById("difficulty-select").value = localSettings.difficultyMode
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()
//**********************************************************************
@@ -962,10 +1014,7 @@ document.getElementById("difficulty-select").addEventListener("input", () => {
});
document.getElementById("updates").addEventListener("toggle", function() {
function loadJSON(path, success, error) { //generic function to get JSON
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {

View File

@@ -19,12 +19,11 @@ const level = {
// mech.setField("plasma torch")
// b.giveGuns("grenades")
// tech.isExplodeRadio = true
// tech.giveTech("boom-bot")
// tech.giveTech("needle gun")
// tech.giveTech("supercritical fission")
// tech.giveTech("irradiated nails")
// tech.giveTech("4s half-life")
// tech.giveTech("CPT gun")
// tech.giveTech("cardinality")
// tech.giveTech("Bayesian statistics")
// tech.isMineSentry = true
// for (let i = 0; i < 60; i++) tech.giveTech("rivet diameter")
@@ -34,7 +33,6 @@ const level = {
level.intro(); //starting level
// level.testing(); //not in rotation
// level.null() //after the final boss, ending
// level.final() //final boss level
// level.gauntlet(); //before final boss level
// level.testChamber() //less mobs, more puzzle
@@ -51,6 +49,15 @@ const level = {
// level.detours() //fan level
// level.basement(); //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 {
spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
// spawn.pickList = ["focuser", "focuser"]
@@ -104,39 +111,86 @@ const level = {
//******************************************************************************************************************
//******************************************************************************************************************
null() {
const hazardSlime = level.hazard(-1775, 150, 3575, 650, 0.01, "hsla(160, 100%, 35%,0.75)")
// const hazardLaser1 = level.hazard(-475, -800, 1, 800, 0.4, "#50f", true) //laser
// const hazardLaser2 = level.hazard(475, -800, 1, 800, 0.4, "#50f", true) //laser
level.levels.pop(); //remove lore level from rotation
//start a conversation based on the number of conversations seen
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.playerExitCheck();
hazardSlime.query();
// hazardLaser1.query();
// hazardLaser2.query();
// hazard.level(true)
//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;
//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 = () => {
hazardSlime.drawTides();
// hazardLaser1.draw();
// hazardLaser2.draw();
//draw wires
//draw center circle lines
ctx.beginPath();
ctx.moveTo(-525, -800);
ctx.quadraticCurveTo(-800, -100, -1775, -375);
ctx.moveTo(-600, -800);
ctx.quadraticCurveTo(-800, -200, -1775, -325);
// ctx.moveTo(-525, -800);
// ctx.quadraticCurveTo(-800, -100, -1825, -450);
ctx.lineWidth = 1;
ctx.strokeStyle = "#234";
const step = Math.PI / 20
const horizontalStep = 85
if (simulation.isCheating) phase += 0.003 //(mech.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 * (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)
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();
//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 + 20, 100, 20);
spawn.mapRect(level.enter.x, level.enter.y + 25, 100, 10);
level.exit.x = 0;
level.exit.y = 200;
level.defaultZoom = 1000
@@ -159,17 +213,20 @@ const level = {
// 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(-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(475, -25, 25, 50); //edge shelf
// spawn.mapRect(-500, -820, 50, 25); //edge shelf ceiling
// spawn.mapRect(450, -820, 50, 25); //edge shelf ceiling
// spawn.bodyRect(1540, -1110, 300, 25, 0.9);
// spawn.mapRect(-50, -500, 100, 100); //center square
// 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.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;
},
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.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;
simulation.healScale = 1 / (1 + simulation.difficulty * 0.06)
},
@@ -3906,10 +3963,12 @@ const level = {
}
},
levelAnnounce() {
if (level.levelsCleared === 0) {
document.title = "n-gon: (" + level.difficultyText() + ")";
} 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(`

View File

@@ -1,36 +1,162 @@
const lore = {
alfie: {
color: "#e06",
techCount: 0,
talkingColor: "#dff", //set color of graphic on level.null
anand: {
color: "#e0c",
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);
lore.talkingColor = this.color
if (isSpeech) this.speech(say)
},
speech: function(say) {
var utterance = new SpeechSynthesisUtterance(say);
utterance.lang = "en-GB";
utterance.lang = "en-IN";
utterance.volume = 0.2; // 0 to 1
speechSynthesis.speak(utterance);
}
},
zoe: {
color: "#f50",
miriam: {
color: "#f20",
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);
lore.talkingColor = this.color
if (isSpeech) this.speech(say)
},
speech: function(say) {
var utterance = new SpeechSynthesisUtterance(say);
utterance.lang = "en-AU";
utterance.volume = 0.2; // 0 to 1
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: [
``,
``,
],
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) {
@@ -46,3 +172,16 @@ const lore = {
// utterance.lang = "en-GB";
// 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>
</span>
&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 {
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,
boldActiveGunHUD() {
if (b.inventory.length > 0) {
for (let i = 0, len = b.inventory.length; i < len; ++i) {
// document.getElementById(b.inventory[i]).style.fontSize = "25px";
document.getElementById(b.inventory[i]).style.opacity = "0.3";
}
for (let i = 0, len = b.inventory.length; i < len; ++i) document.getElementById(b.inventory[i]).style.opacity = "0.3";
// document.getElementById(b.activeGun).style.fontSize = "30px";
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 (b.inventory[0] === b.activeGun) {
let lessDamage = 1
for (let i = 0, len = b.inventory.length; i < len; i++) {
lessDamage *= 0.87 // 1 - 0.13
}
for (let i = 0, len = b.inventory.length; i < len; i++) lessDamage *= 0.87 // 1 - 0.13
document.getElementById("tech-entanglement").innerHTML = " " + ((1 - lessDamage) * 100).toFixed(0) + "%"
} else {
document.getElementById("tech-entanglement").innerHTML = " 0%"
@@ -465,6 +460,7 @@ const simulation = {
},
firstRun: true,
splashReturn() {
simulation.clearTimeouts();
simulation.onTitlePage = true;
document.getElementById("splash").onclick = function() {
simulation.startGame();
@@ -496,7 +492,6 @@ const simulation = {
document.getElementById("splash").style.display = "none"; //hides the element that spawned the function
document.getElementById("dmg").style.display = "inline";
document.getElementById("health-bg").style.display = "inline";
mech.spawn(); //spawns the player
level.levels = level.playableLevels.slice(0) //copy array, not by just by assignment
@@ -529,13 +524,17 @@ const simulation = {
b.setFireMethod()
b.setFireCD();
simulation.updateTechHUD();
// simulation.updateTechHUD();
powerUps.totalPowerUps = 0;
powerUps.research.count = 0;
mech.setFillColors();
// mech.maxHealth = 1
// mech.maxEnergy = 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
simulation.paused = false;
engine.timing.timeScale = 1;
@@ -620,6 +619,12 @@ const simulation = {
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() {
if (tech.isMineAmmoBack) {
@@ -706,6 +711,7 @@ const simulation = {
mech.holdingTarget = body[len];
mech.holdingTarget.collisionFilter.category = 0;
mech.holdingTarget.collisionFilter.mask = 0;
mech.definePlayerMass(mech.defaultMass + mech.holdingTarget.mass * mech.holdingMassScale)
}
//set fps back to default
simulation.fpsCap = simulation.fpsCapDefault
@@ -837,27 +843,6 @@ const simulation = {
},
testingOutput() {
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.fillText(`(${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)})`, simulation.mouse.x, simulation.mouse.y - 20);
},
@@ -883,7 +868,6 @@ const simulation = {
ctx.globalAlpha = 1;
},
powerUpBonus() { //draws crackle effect for bonus power ups
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();
@@ -892,7 +876,7 @@ const simulation = {
ctx.fill();
}
ctx.globalAlpha = 1;
for (let i = 0, len = powerUp.length; i < len; ++i) {
if (powerUp[i].isBonus && Math.random() < 0.1) {
//draw electricity
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
// spawn.shield(me, x, y, 1);
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.y = -330;
//ramp up damage

View File

@@ -6,6 +6,9 @@ const tech = {
tech.tech[i].isLost = false
tech.tech[i].count = 0
}
lore.techCount = 0;
tech.removeLoreTechFromPool();
tech.addLoreTechToPool();
// tech.nailBotCount = 0;
// tech.foamBotCount = 0;
// tech.boomBotCount = 0;
@@ -21,12 +24,24 @@ const tech = {
tech.tech[index].count = 0;
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') {
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())
options.push(i);
if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) options.push(i);
}
// give a random tech from the tech I don't have
if (options.length > 0) {
@@ -98,7 +113,7 @@ const tech = {
return dmg * tech.slowFire * tech.aimDamage
},
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() {
return tech.foamBotCount + tech.nailBotCount + tech.laserBotCount + tech.boomBotCount + tech.orbitBotCount + tech.plasmaBotCount + tech.missileBotCount
@@ -1746,7 +1761,7 @@ const tech = {
},
{
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,
count: 0,
allowed() {
@@ -1760,7 +1775,7 @@ const tech = {
},
remove() {
tech.isCancelDuplication = false
tech.cancelCount = 0
// tech.cancelCount = 0
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
tech.setupAllTech(); // remove all tech
tech.addLoreTechToPool();
for (let i = 0; i < count; i++) { // spawn new tech power ups
powerUps.spawn(mech.pos.x, mech.pos.y, "tech");
}
@@ -2394,9 +2410,9 @@ const tech = {
maxCount: 1,
count: 0,
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() {
tech.isNailCrit = true
},
@@ -2530,7 +2546,7 @@ const tech = {
},
{
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,
maxCount: 1,
count: 0,
@@ -3882,6 +3898,10 @@ const tech = {
tech.isWormBullets = false
}
},
//**************************************************
//************************************************** spawn power up
//************************************************** tech
//**************************************************
{
name: "heals",
description: "spawn <strong>6</strong> <strong class='color-h'>heals</strong>",
@@ -3972,8 +3992,37 @@ const tech = {
this.count--
},
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
fireRate: null,
bulletSize: null,

View File

@@ -146,6 +146,7 @@ summary {
left: 50%;
transform: translate(-50%, -50%);
padding: 10px;
grid-gap: 10px;
margin: 0px;
border-radius: 8px;
z-index: 12;
@@ -153,7 +154,6 @@ summary {
display: none;
grid-template-columns: repeat(auto-fit, minmax(310px, 1fr));
grid-auto-rows: minmax(auto, auto);
grid-gap: 10px;
font-size: 1.3em;
/* box-shadow: 0px 0px 40px 20px rgba(255, 255, 255, 0.25); */
}
@@ -664,6 +664,56 @@ summary {
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 {
padding: 3px 8px 3px 8px;
border: 2px solid #444;

View File

@@ -1,17 +1,21 @@
******************************************************** NEXT PATCH ********************************************************
various bug fixes
Laser+slow light prop+crouch= all but one laser stays in original position
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
lore: chapter 1 and 2 are now somewhere in the game
lore is the same for all difficulty levels
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 ********************************************************
(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) 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 ********************************************************
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
set your duplication chance to zero
requires 5 rerolls and 20% duplication chance
@@ -58,13 +73,6 @@ in game console
mech, tech, level are all highlighted
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
position, velocity, and health
no energy cost
@@ -360,7 +368,7 @@ n-gon outreach ideas
******************************************************** LORE ********************************************************
cool names for tech
strange loop
strange loop, ansatz
lore - a robot (the player) gains self awareness
each tech gun/field is a new tech
@@ -424,7 +432,9 @@ scientist console text:
Are those shapes supposed to be us?
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
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)