combinatorial optimization

"cloak" and "alternate reality" now have styled text

metamaterial field damage increased to 146% (was 121%)
tech: combinatorial optimization - increase damage by 66% if a mob hasn't died in the last 5 seconds

fix bugs where some shared build URLs were crashing on some unusual tech, like lore tech and nonrefundable tech
junk tech: not a bug - crashes the game
This commit is contained in:
landgreen
2021-05-30 06:14:34 -07:00
parent dc81f05947
commit d54ca92cf7
9 changed files with 222 additions and 96 deletions

View File

@@ -101,6 +101,7 @@ window.addEventListener('load', () => {
}
}
}
if (property === "difficulty") {
simulation.difficultyMode = Number(set[property])
document.getElementById("difficulty-select-experiment").value = Number(set[property])
@@ -148,33 +149,33 @@ window.onresize = () => {
// experimental build grid display and pause
//**********************************************************************
const build = {
onLoadPowerUps() {
const set = getUrlVars()
if (Object.keys(set).length !== 0) {
for (const property in set) {
set[property] = set[property].replace(/%20/g, " ")
if (property.substring(0, 3) === "gun") b.giveGuns(set[property])
if (property.substring(0, 3) === "tech") tech.giveTech(set[property])
if (property === "field") m.setField(set[property])
if (property === "difficulty") {
simulation.difficultyMode = Number(set[property])
document.getElementById("difficulty-select").value = Number(set[property])
}
if (property === "level") {
level.levelsCleared += Number(set[property]);
level.difficultyIncrease(Number(set[property]) * simulation.difficultyMode) //increase difficulty based on modes
spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
level.onLevel++
}
}
for (let i = 0; i < bullet.length; ++i) Matter.World.remove(engine.world, bullet[i]);
bullet = []; //remove any bullets that might have spawned from tech
if (b.inventory.length > 0) {
b.activeGun = b.inventory[0] //set first gun to active gun
simulation.makeGunHUD();
}
}
},
// onLoadPowerUps() {
// const set = getUrlVars()
// if (Object.keys(set).length !== 0) {
// for (const property in set) {
// set[property] = set[property].replace(/%20/g, " ")
// if (property.substring(0, 3) === "gun") b.giveGuns(set[property])
// if (property.substring(0, 3) === "tech") tech.giveTech(set[property])
// if (property === "field") m.setField(set[property])
// if (property === "difficulty") {
// simulation.difficultyMode = Number(set[property])
// document.getElementById("difficulty-select").value = Number(set[property])
// }
// if (property === "level") {
// level.levelsCleared += Number(set[property]);
// level.difficultyIncrease(Number(set[property]) * simulation.difficultyMode) //increase difficulty based on modes
// spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns
// level.onLevel++
// }
// }
// for (let i = 0; i < bullet.length; ++i) Matter.World.remove(engine.world, bullet[i]);
// bullet = []; //remove any bullets that might have spawned from tech
// if (b.inventory.length > 0) {
// b.activeGun = b.inventory[0] //set first gun to active gun
// simulation.makeGunHUD();
// }
// }
// },
pauseGrid() {
let botText = ""
if (tech.nailBotCount) botText += `<br>nail-bots: ${tech.nailBotCount}`
@@ -296,20 +297,18 @@ const build = {
m.setField(index)
who.classList.add("build-field-selected");
}
} else if (type === "tech") { //remove tech if you have too many
} else if (type === "tech") {
if (tech.tech[index].count < tech.tech[index].maxCount) {
if (!who.classList.contains("build-tech-selected")) who.classList.add("build-tech-selected");
tech.giveTech(index)
if (!tech.tech[index].isLore && !tech.tech[index].isNonRefundable && !who.classList.contains("build-tech-selected")) who.classList.add("build-tech-selected");
} else if (!tech.tech[index].isNonRefundable) {
tech.totalCount -= tech.tech[index].count
tech.removeTech(index);
who.classList.remove("build-tech-selected");
} else {
who.classList.remove("build-tech-selected")
setTimeout(() => { //return energy
setTimeout(() => {
who.classList.add("build-tech-selected")
}, 50);
}
}
//update tech text //disable not allowed tech
@@ -321,21 +320,21 @@ const build = {
if (tech.tech[i].isFieldTech) {
techID.innerHTML = ` <div class="grid-title">
<span style="position:relative;">
<div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
<div class="circle-grid field" 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>`
<span style="position:relative;">
<div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
<div class="circle-grid field" 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 class="circle-grid gun" style="position:absolute; top:-3px; left:-3px; opacity:1; height: 33px; width:33px;"></div>
// <div class="circle-grid tech" style="position:absolute; top:5px; left:5px;opacity:1;height: 20px; width:20px;border: #fff solid 2px;"></div>
// border: #fff solid 0px;
} else if (tech.tech[i].isGunTech) {
techID.innerHTML = ` <div class="grid-title">
<span style="position:relative;">
<div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
<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>`
<span style="position:relative;">
<div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
<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>`
} else if (tech.tech[i].isJunk) {
// text += `<div class="pause-grid-module"><div class="grid-title"><div class="circle-grid junk"></div> &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div></div>`
techID.innerHTML = `<div class="grid-title"><div class="circle-grid junk"></div> &nbsp; ${tech.tech[i].name} ${isCount}</div>${tech.tech[i].description}</div>`
@@ -355,6 +354,7 @@ const build = {
// techID.innerHTML = `<div class="grid-title"> ${tech.tech[i].name}</div><span style="color:#666;">requires: ${tech.tech[i].requires}</span></div>`
// techID.innerHTML = `<div class="grid-title"> ${tech.tech[i].name}</div><span style="color:#666;">requires: ${tech.tech[i].requires}</span></div>`
techID.innerHTML = `<div class="grid-title">${tech.tech[i].name}</div>${tech.tech[i].description}</div>`
// console.log(techID)
if (!techID.classList.contains("experiment-grid-disabled")) {
techID.classList.add("experiment-grid-disabled");
techID.onclick = null

View File

@@ -9,6 +9,7 @@ const level = {
levelsCleared: 0,
playableLevels: ["skyscrapers", "rooftops", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber"],
levels: [],
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.enableConstructMode() //used to build maps in testing mode
@@ -1289,6 +1290,30 @@ const level = {
spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump
spawn.mapRect(5425, -650, 375, 450); //blocking exit
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4800, -500);
if (simulation.isHorizontalFlipped) { //flip the map horizontally
const flipX = (who) => {
for (let i = 0, len = who.length; i < len; i++) {
Matter.Body.setPosition(who[i], { x: -who[i].position.x, y: who[i].position.y })
}
}
flipX(map)
flipX(body)
flipX(mob)
flipX(powerUp)
level.setPosToSpawn(0, -250);
level.exit.x = -level.exit.x - 100 //minus the 100 because of the width of the graphic
level.custom = () => {
level.playerExitCheck();
level.exit.draw();
level.enter.draw();
};
level.customTopLayer = () => {
ctx.fillStyle = "rgba(0,255,255,0.1)"
ctx.fillRect(-5400 - 300, -550, 300, 350)
};
}
},
gauntlet() {
level.custom = () => {
@@ -1310,8 +1335,8 @@ const level = {
simulation.zoomTransition(level.defaultZoom)
document.body.style.backgroundColor = "#ddd";
spawn.mapRect(-300, -1050, 300, 200);
Matter.Body.setAngle(map[map.length - 1], -Math.PI / 4)
// spawn.mapRect(-300, -1050, 300, 200);
// Matter.Body.setAngle(map[map.length - 1], -Math.PI / 4)
spawn.mapRect(-950, 0, 8200, 800); //ground
@@ -1344,6 +1369,32 @@ const level = {
}
powerUps.addRerollToLevel() //needs to run after mobs are spawned
if (tech.isDuplicateBoss && Math.random() < 2 * tech.duplicationChance()) spawn.randomLevelBoss(4125, -350);
if (simulation.isHorizontalFlipped) { //flip the map horizontally
const flipX = (who) => {
for (let i = 0, len = who.length; i < len; i++) {
Matter.Body.setPosition(who[i], { x: -who[i].position.x, y: who[i].position.y })
}
}
flipX(map)
flipX(body)
flipX(mob)
flipX(powerUp)
level.setPosToSpawn(0, -475);
level.exit.x = -level.exit.x - 100 //minus the 100 because of the width of the graphic
level.custom = () => {
level.playerExitCheck();
level.exit.draw();
level.enter.draw();
};
level.customTopLayer = () => {
ctx.fillStyle = "rgba(0,255,255,0.1)"
ctx.fillRect(-6400 - 300, -550, 300, 350)
ctx.fillStyle = "rgba(0,0,0,0.1)"
ctx.fillRect(175 - 900, -975, 900, 575)
};
}
},
intro() {
level.custom = () => {
@@ -3627,7 +3678,7 @@ const level = {
if (simulation.difficulty > 4) spawn.nodeGroup(2330, 1850, "spawns", 8, 20, 105);
powerUps.chooseRandomPowerUp(3100, 1630);
},
detours() {
detours() { //by Francois from discord
level.setPosToSpawn(0, 0); //lower start
level.exit.y = 150;
spawn.mapRect(level.enter.x, 45, 100, 20);
@@ -3938,7 +3989,7 @@ const level = {
}
}
},
house() {
house() { //by Francois from discord
const rotor = level.rotor(4315, -315, -0.0002, 120, 20, 200);
const hazard = level.hazard(4350, -1000, 300, 110);
const doorBedroom = level.door(1152, -1150, 25, 250, 250);
@@ -4414,7 +4465,7 @@ const level = {
}
}
},
perplex() {
perplex() { //by Oranger from discord
level.setPosToSpawn(-600, 400);
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
level.exit.x = 550;

View File

@@ -1952,7 +1952,7 @@ const m = {
},
{
name: "metamaterial cloaking", //"weak photonic coupling" "electromagnetically induced transparency" "optical non-coupling" "slow light field" "electro-optic transparency"
description: "<strong class='color-cloaked'>cloak</strong> after not using your gun or field<br>while <strong class='color-cloaked'>cloaked</strong> mobs can't see you<br>increase <strong class='color-d'>damage</strong> by <strong>121%</strong>",
description: "<strong class='color-cloaked'>cloak</strong> after not using your gun or field<br>while <strong class='color-cloaked'>cloaked</strong> mobs can't see you<br>increase <strong class='color-d'>damage</strong> by <strong>146%</strong>",
effect: () => {
m.fieldFire = true;
m.fieldMeterColor = "#333";
@@ -1960,7 +1960,7 @@ const m = {
// m.eyeFillColor = '#333'
m.fieldPhase = 0;
m.isCloak = false
m.fieldDamage = 2.21 // 1 + 111/100
m.fieldDamage = 2.46 // 1 + 146/100
m.fieldDrawRadius = 0
const drawRadius = 1000
@@ -1998,7 +1998,7 @@ const m = {
}
if (tech.isCloakStun) { //stun nearby mobs after exiting cloak
let isMobsAround = false
const stunRange = m.fieldDrawRadius * 1.15
const stunRange = m.fieldDrawRadius * 1.2
const drain = 0.3 * m.energy
for (let i = 0, len = mob.length; i < len; ++i) {
if (
@@ -2006,7 +2006,7 @@ const m = {
Matter.Query.ray(map, mob[i].position, m.pos).length === 0
) {
isMobsAround = true
mobs.statusStun(mob[i], 30 + drain * 300)
mobs.statusStun(mob[i], 60 + drain * 360)
}
}
if (isMobsAround && m.energy > drain) {

View File

@@ -122,6 +122,7 @@ const simulation = {
lastTimeStamp: 0, //tracks time stamps for measuring delta
delta: 1000 / 60, //speed of game engine //looks like it has to be 16 to match player input
buttonCD: 0,
isHorizontalFlipped: false, //makes some maps flipped horizontally
levelsCleared: 0,
difficultyMode: 2, //normal difficulty is 2
difficulty: 0,

View File

@@ -376,7 +376,7 @@ const spawn = {
//push blocks and player away, since this is the end of suck, and suck causes blocks to fall on the boss and stun it
Matter.Body.scale(this, 10, 10);
Matter.Body.setDensity(me, density); //extra dense //normal is 0.001 //makes effective life much larger
if (!this.isShielded) spawn.shield(this, x, y, 1); // regen shield to also prevent stun
if (!this.isShielded) spawn.shield(this, this.position.x, this.position.y, 1); // regen shield to also prevent stun
for (let i = 0, len = body.length; i < len; ++i) { //push blocks away horizontally
if (body[i].position.x > this.position.x) {
body[i].force.x = 0.5

View File

@@ -151,6 +151,7 @@
if (tech.isFlipFlopDamage && tech.isFlipFlopOn) dmg *= 1.45
if (tech.isAnthropicDamage && tech.isDeathAvoidedThisLevel) dmg *= 2.3703599
if (tech.isDamageAfterKill) dmg *= (m.lastKillCycle + 300 > m.cycle) ? 1.5 : 0.85
if (tech.isSneakAttack && m.cycle > m.lastKillCycle + 300) dmg *= 1.66
if (tech.isTechDamage) dmg *= 1.9
if (tech.isDupDamage) dmg *= 1 + Math.min(1, tech.duplicationChance())
if (tech.isLowEnergyDamage) dmg *= 1 + Math.max(0, 1 - m.energy) * 0.5
@@ -169,6 +170,7 @@
if (tech.isNoFireDamage && m.cycle > m.fireCDcycle + 120) dmg *= 1.9
if (tech.isSpeedDamage) dmg *= 1 + Math.min(0.43, player.speed * 0.015)
if (tech.isBotDamage) dmg *= 1 + 0.05 * b.totalBots()
return dmg * tech.slowFire * tech.aimDamage
},
duplicationChance() {
@@ -2540,7 +2542,7 @@
},
{
name: "quantum immortality",
description: "after <strong>dying</strong>, continue in an <strong>alternate reality</strong><br>reduce <strong class='color-harm'>harm</strong> by <strong>23%</strong>", //spawn <strong>4</strong> <strong class='color-r'>research</strong>
description: "after <strong>dying</strong>, continue in an <strong class='alt'>alternate reality</strong><br>reduce <strong class='color-harm'>harm</strong> by <strong>23%</strong>", //spawn <strong>4</strong> <strong class='color-r'>research</strong>
maxCount: 1,
count: 0,
frequency: 4,
@@ -2558,7 +2560,7 @@
},
{
name: "many-worlds",
description: "each <strong>level</strong> is an <strong>alternate reality</strong>, where you<br>find a <strong class='color-m'>tech</strong> at the start of each level",
description: "each <strong>level</strong> is an <strong class='alt'>alternate reality</strong>, where you<br>find a <strong class='color-m'>tech</strong> at the start of each level",
maxCount: 1,
count: 0,
frequency: 1,
@@ -2576,7 +2578,7 @@
},
{
name: "non-unitary operator",
description: "reduce combat <strong>difficulty</strong> by <strong>2 levels</strong><br>after a <strong>collision</strong> enter an <strong>alternate reality</strong>",
description: "reduce combat <strong>difficulty</strong> by <strong>2 levels</strong><br>after a <strong>collision</strong> enter an <strong class='alt'>alternate reality</strong>",
maxCount: 1,
count: 0,
frequency: 1,
@@ -2598,7 +2600,7 @@
},
{
name: "Ψ(t) collapse",
description: "enter an <strong>alternate reality</strong> after you <strong class='color-r'>research</strong><br>spawn <strong>12</strong> <strong class='color-r'>research</strong>",
description: "enter an <strong class='alt'>alternate reality</strong> after you <strong class='color-r'>research</strong><br>spawn <strong>12</strong> <strong class='color-r'>research</strong>",
maxCount: 1,
count: 0,
frequency: 1,
@@ -4881,9 +4883,9 @@
count: 0,
frequency: 2,
allowed() {
return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass field") && !tech.isEnergyHealth
return (m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass field") && !tech.isEnergyHealth
},
requires: "negative mass field, not mass-energy",
requires: "field: perfect, negative mass, pilot wave, plasma, not mass-energy",
effect() {
tech.isHarmReduce = true
},
@@ -5032,7 +5034,7 @@
count: 0,
frequency: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "time dilation field" // || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
return m.fieldUpgrades[m.fieldMode].name === "time dilation field"
},
requires: "time dilation field",
effect() {
@@ -5056,7 +5058,7 @@
count: 0,
frequency: 2,
allowed() {
return (m.fieldUpgrades[m.fieldMode].name === "time dilation field") && tech.energyRegen !== 0; //|| m.fieldUpgrades[m.fieldMode].name === "pilot wave"
return (m.fieldUpgrades[m.fieldMode].name === "time dilation field") && tech.energyRegen !== 0
},
requires: "time dilation field, not ground state",
effect: () => {
@@ -5104,6 +5106,24 @@
tech.isCloakStun = false;
}
},
{
name: "combinatorial optimization",
description: "increase <strong class='color-d'>damage</strong> by <strong>66%</strong><br>if a mob has <strong>not died</strong> in the last <strong>5 seconds</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,
frequency: 2,
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking"
},
requires: "metamaterial cloaking or pilot wave",
effect() {
tech.isSneakAttack = true;
},
remove() {
tech.isSneakAttack = false;
}
},
{
name: "discrete optimization",
description: "increase <strong class='color-d'>damage</strong> by <strong>50%</strong><br><strong>50%</strong> increased <strong><em>delay</em></strong> after firing",
@@ -5114,7 +5134,7 @@
allowed() {
return m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "pilot wave"
},
requires: "metamaterial cloaking",
requires: "metamaterial cloaking or pilot wave",
effect() {
tech.aimDamage = 1.5
b.setFireCD();
@@ -5240,7 +5260,7 @@
},
{
name: "-quantum leap-",
description: "<strong style='color: #f55;'>experiment:</strong> every 20 seconds<br>become an alternate version of yourself",
description: "<strong style='color: #f55;'>experiment:</strong> every 20 seconds<br>become an <strong class='alt'>alternate</strong> version of yourself",
maxCount: 1,
count: 0,
frequency: 0,
@@ -5410,6 +5430,33 @@
// tech.wimpExperiment = 0
// }
// },
{
name: "not a bug",
description: "initiate a totally safe game crash for 5 seconds",
maxCount: 1,
count: 0,
frequency: 0,
isNonRefundable: true,
isExperimentHide: true,
isJunk: true,
allowed() {
return true
},
requires: "",
effect() {
const savedfunction = simulation.drawCircle
simulation.drawCircle = () => {
const a = mob[Infinity].position //crashed the game in a visually interesting way, because of the ctx.translate command is never reverted in the main game loop
}
setTimeout(() => {
simulation.drawCircle = savedfunction
canvas.width = canvas.width //clears the canvas // works on chrome at least
}, 5000);
// for (;;) {} //freezes the tab
},
remove() {}
},
{
name: "posture",
description: "stand a bit taller",
@@ -5676,7 +5723,7 @@
},
{
name: "quantum leap",
description: "become an alternate version of yourself<br>every <strong>20</strong> seconds",
description: "become an <strong class='alt'>alternate</strong> version of yourself<br>every <strong>20</strong> seconds",
maxCount: 1,
count: 0,
frequency: 0,
@@ -6781,5 +6828,6 @@
isBlockBullets: null,
isAddBlockMass: null,
isMACHO: null,
isHarmMACHO: null
isHarmMACHO: null,
isSneakAttack: null
}