gravityObservatory

new level: gravityObservatory

level: testChamber2 renamed gravityInterferometer
  it has been added to the levels that are extra hard and only show up late game
  it also got a bit hard with the addition of 1 more laser

deflected mob bullets are converted into small blocks
ablative drones is now a gun tech for drones
  it makes ~33% more drones
1.033->1.05x sneak attack damage per coupling for cloaking field

bug fixes
  extended vertical flip to edge cases:
    trail left by snakeBoss
    laser array from boss and mobs
    springer,spiderBoss,mantisBoss constraints
  subway: dark matter no longer removed if it gets too far from the player
  training: fixed potential lock out from running out of ammo
  training: fixed accidental difficulty increase
This commit is contained in:
landgreen
2024-10-05 17:11:06 -07:00
parent cea1c64c6e
commit a47ef97dbc
9 changed files with 628 additions and 187 deletions

View File

@@ -474,13 +474,14 @@ const build = {
// <strong class='color-g'>${b.activeGun === null || b.activeGun === undefined ? "undefined" : b.guns[b.activeGun].name}</strong> (${b.activeGun === null || b.activeGun === undefined ? "0" : b.guns[b.activeGun].ammo})
// <br>
// <input onclick="build.showImages('pause')" type="checkbox" id="hide-images-pause" name="hide-images-pause" ${localSettings.isHideImages ? "checked" : ""}>
// <label for="hide-images-pause" title="hide images for fields, guns, and tech" style="font-size:1.15em;" >hide images</label>
let text = `<div class="pause-grid-module" style="padding: 8px;">
<span style="font-size:1.4em;font-weight: 600; float: left;">PAUSED</span>
<em style="float: right;color:#ccc;">press ${input.key.pause} to resume</em>
<br>
<input onclick="build.showImages('pause')" type="checkbox" id="hide-images-pause" name="hide-images-pause" ${localSettings.isHideImages ? "checked" : ""}>
<label for="hide-images-pause" title="hide images for fields, guns, and tech" style="font-size:1.15em;" >hide images</label>
<br>
<button onclick="build.shareURL(false)" class='sort-button' style="font-size:1em;float: right;">copy build URL</button>
<input onclick="build.hideHUD('settings')" type="checkbox" id="hide-hud" name="hide-hud" ${localSettings.isHideHUD ? "checked" : ""}>
<label for="hide-hud" title="hide: tech, damage taken, damage, in game console" style="font-size:1.15em;">minimal HUD</label>

View File

@@ -8,8 +8,8 @@ const level = {
defaultZoom: 1400,
onLevel: -1,
levelsCleared: 0,
//see level.populateLevels: (initial, ... , reservoir or factory, reactor, ... , subway, final) added later
playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock", "towers", "flocculation", "testChamber2"],
//see level.populateLevels: (initial, ... , (reservoir, factory, or gravityInterferometer), reactor, ... , subway, final) added later
playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock", "towers", "flocculation", "gravityObservatory"],
communityLevels: ["gauntlet", "stronghold", "basement", "crossfire", "vats", "run", "ngon", "house", "perplex", "coliseum", "tunnel", "islands", "temple", "dripp", "biohazard", "stereoMadness", "yingYang", "staircase", "fortress", "commandeer", "clock", "buttonbutton", "downpour", "superNgonBros", "underpass", "cantilever", "tlinat", "ruins", "ace", "crimsonTowers", "LaunchSite", "shipwreck", "unchartedCave", "dojo", "arena", "soft", "flappyGon", "rings", "trial"],
trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon"],
levels: [],
@@ -30,14 +30,14 @@ const level = {
// tech.tech[297].frequency = 100
// tech.addJunkTechToPool(0.5)
// m.couplingChange(10)
// m.setField("time dilation") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
// m.setField("standing wave") //1 standing wave 2 perfect diamagnetism 3 negative mass 4 molecular assembler 5 plasma torch 6 time dilation 7 metamaterial cloaking 8 pilot wave 9 wormhole 10 grappling hook
// m.energy = 0
// powerUps.research.count = 3
// tech.isHookWire = true
// m.energy = 0
// simulation.molecularMode = 2
// m.damage(0.1);
// b.giveGuns("super balls") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.giveGuns("nail gun") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.giveGuns("spores") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.giveGuns("laser") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// tech.laserColor = "#fff"
@@ -45,9 +45,9 @@ const level = {
// b.guns[8].ammo = 100000000
// requestAnimationFrame(() => { tech.giveTech("stimulated emission") });
// tech.giveTech("mass-energy equivalence")
// tech.giveTech("dark matter")
// tech.addJunkTechToPool(0.5)
// for (let i = 0; i < 1; ++i) tech.giveTech("the upside down")
// for (let i = 0; i < 1; ++i) tech.giveTech("entropic gravity")
// for (let i = 0; i < 1; ++i) tech.giveTech("nitinol")
// m.skin.egg();
@@ -59,13 +59,13 @@ const level = {
// for (let i = 0; i < 4; i++) powerUps.directSpawn(450, -50, "tech");
// for (let i = 0; i < 7; i++) powerUps.directSpawn(m.pos.x + 200, m.pos.y - 250, "research", false);
// spawn.bodyRect(575, -700, 150, 150); //block mob line of site on testing
// level.testChamber2();
// level.gravityInterferometer();
level[simulation.isTraining ? "walk" : "initial"]() //normal starting level **************************************************
// for (let i = 0; i < 1; ++i) spawn.revolutionBoss(1900, -500)
// for (let i = 0; i < 1; i++) spawn.starter(1900, -500, 20)
// for (let i = 0; i < 1; ++i) spawn.snakeBoss(1900, -500)
// for (let i = 0; i < 1; i++) spawn.mantisBoss(1900, -500)
// for (let i = 0; i < 1; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "entanglement");
// for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 450, m.pos.y + 50 * Math.random(), "boost");
@@ -137,7 +137,7 @@ const level = {
}
level.newLevelOrPhase()
if (simulation.isTraining) {
simulation.difficultyMode = 2
simulation.difficultyMode = 1
} else {
simulation.inGameConsole(`<span class='color-var'>level</span>.onLevel <span class='color-symbol'>=</span> "<span class='color-text'>${level.levels[level.onLevel]}</span>"`);
document.title = "n-gon: " + level.levelAnnounce();
@@ -256,13 +256,19 @@ const level = {
customTopLayer() { },
updateDifficulty() {
simulation.difficulty = level.levelsCleared * simulation.difficultyMode
if (simulation.isTraining) simulation.difficulty = 1
const scale = simulation.difficultyMode > 3 ? 2 : 1
m.dmgScale = Math.pow(0.85, level.levelsCleared * scale)
simulation.dmgScale = Math.max(0.1, 0.25 * level.levelsCleared * scale) //damage done by mobs scales with total levels //a bigger number means the player takes more damage
if (simulation.difficultyMode > 5) {
m.dmgScale *= 0.5
simulation.dmgScale *= 2
if (simulation.isTraining) {
simulation.difficulty = 1
simulation.difficultyMode = 1
m.dmgScale = 1
simulation.dmgScale = 1//Math.max(0.1, 0.25 * level.levelsCleared * scale) //damage done by mobs scales with total levels //a bigger number means the player takes more damage
} else {
const scale = simulation.difficultyMode > 3 ? 2 : 1
m.dmgScale = Math.pow(0.85, level.levelsCleared * scale)
simulation.dmgScale = Math.max(0.1, 0.25 * level.levelsCleared * scale) //damage done by mobs scales with total levels //a bigger number means the player takes more damage
if (simulation.difficultyMode > 5) {
m.dmgScale *= 0.5
simulation.dmgScale *= 2
}
}
simulation.healScale = 1 / (1 + simulation.difficulty * 0.043) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale;
if (simulation.difficultyMode === 1) {
@@ -772,7 +778,8 @@ const level = {
}
level.levels = shuffle(level.levels); //shuffles order of maps with seeded random
level.levels.length = 9 //remove any extra levels past 9
level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.6, level.levels.length)), 0, Math.random() < 0.5 ? "factory" : "reservoir"); //add level to the back half of the randomized levels list
pick = ["gravityInterferometer", "factory", "reservoir"]
level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.6, level.levels.length)), 0, pick[Math.floor(Math.random() * pick.length)]); //add level to the back half of the randomized levels list
level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.6, level.levels.length)), 0, "reactor"); //add level to the back half of the randomized levels list
if (!build.isExperimentSelection || (build.hasExperimentalMode && !simulation.isCheating)) { //experimental mode is endless, unless you only have an experiment Tech
level.levels.unshift("initial"); //add level to the start of the randomized levels list
@@ -1548,7 +1555,7 @@ const level = {
},
}
},
button(x, y, width = 126, isSpawnBase = true, isInvertedVertical = false) {
button(x, y, width = 126, isSpawnBase = true, isInvertedVertical = false, color = "hsl(0, 100%, 70%)") {
if (isSpawnBase) {
if (isInvertedVertical) {
spawn.mapVertex(x + 65, y - 3, "100 -10 -100 -10 -70 10 70 10");
@@ -1594,18 +1601,19 @@ const level = {
this.isUp = false;
}
},
query() {
queryRemove() {
if (Matter.Query.region(body, this).length === 0 && Matter.Query.region([player], this).length === 0) {
this.isUp = true;
} else {
if (this.isUp === true) {
const list = Matter.Query.region(body, this) //are any blocks colliding with this
if (list.length > 0) {
if (list[0].bounds.max.x - list[0].bounds.min.x < 150 && list[0].bounds.max.y - list[0].bounds.min.y < 150) { //not too big of a block
Matter.Body.setPosition(list[0], { //teleport block to the center of the button
x: this.min.x + width / 2,
y: list[0].position.y
})
Matter.Composite.remove(engine.world, list[0]);
for (let i = 0; i < body.length; i++) {
if (body[i] === list[0]) {
body.splice(i, 1);
break
}
}
Matter.Body.setVelocity(list[0], { x: 0, y: 0 });
}
@@ -1613,8 +1621,15 @@ const level = {
this.isUp = false;
}
},
queryPlayer() {
if (Matter.Query.region([player], this).length === 0) {
this.isUp = true;
} else {
this.isUp = false;
}
},
draw() {
ctx.fillStyle = "hsl(0, 100%, 70%)"
ctx.fillStyle = color
if (this.isUp) {
ctx.fillRect(this.min.x, this.min.y, this.width, 20)
} else {
@@ -1654,18 +1669,20 @@ const level = {
this.isUp = false;
}
},
query() {
queryRemove() {
if (Matter.Query.region(body, this).length === 0 && Matter.Query.region([player], this).length === 0) {
this.isUp = true;
} else {
if (this.isUp === true) {
const list = Matter.Query.region(body, this) //are any blocks colliding with this
if (list.length > 0) {
if (list[0].bounds.max.x - list[0].bounds.min.x < 150 && list[0].bounds.max.y - list[0].bounds.min.y < 150) { //not too big of a block
Matter.Body.setPosition(list[0], { //teleport block to the center of the button
x: this.min.x + width / 2,
y: list[0].position.y
})
//delete triggering block
Matter.Composite.remove(engine.world, list[0]);
for (let i = 0; i < body.length; i++) {
if (body[i] === list[0]) {
body.splice(i, 1);
break
}
}
Matter.Body.setVelocity(list[0], { x: 0, y: 0 });
}
@@ -1673,8 +1690,15 @@ const level = {
this.isUp = false;
}
},
queryPlayer() {
if (Matter.Query.region([player], this).length === 0) {
this.isUp = true;
} else {
this.isUp = false;
}
},
draw() {
ctx.fillStyle = "hsl(0, 100%, 70%)"
ctx.fillStyle = color
if (this.isUp) {
ctx.fillRect(this.min.x, this.min.y - 10, this.width, 20)
} else {
@@ -3376,7 +3400,7 @@ const level = {
}
//remove any mob that is too far from player
for (let i = 0; i < mob.length; ++i) {
if (Vector.magnitudeSquared(Vector.sub(player.position, mob[i].position)) > 4000000) { //remove any mob farther then 2000 pixels from player
if (Vector.magnitudeSquared(Vector.sub(player.position, mob[i].position)) > 4000000 && !mob[i].isDarkMatter) { //remove any mob farther then 2000 pixels from player
mob[i].removeConsBB()
mob[i].removeCons()
mob[i].leaveBody = false
@@ -7025,7 +7049,8 @@ const level = {
}
},
testChamber2() {
gravityInterferometer() {
level.isVerticalFLipLevel = true
mobs.maxMobBody = 20 //normally 40, but set to 10 to avoid too much clutter
simulation.fallHeight = 4000
level.announceMobTypes()
@@ -7133,13 +7158,13 @@ const level = {
spawn.mapRect(-4000, 2000, 8000, 3000); //floor
}
let buildNormalMap = function () {
buttons.push(level.button(-1895, -1600))
buttons.push(level.button(-1895, -1600, 126, true, false, "hsl(330, 100%, 50%)"))
buttons[buttons.length - 1].isUp = false
spawn.mapRect(-1675, -2025, 50, 250);
simulation.ephemera.push({
name: "buttons up",
count: flipAnimationCycles,
count: flipAnimationCycles + 30,
do() {
this.count--
if (this.count < 0) {
@@ -7161,6 +7186,10 @@ const level = {
balance.push(level.rotor(-750, 1700, 400, 25, 0.01, Math.PI / 2, 0.5))
balance.push(level.rotor(-275, 1650, 550, 32, 0.01, 0, 0.5))
lasers.push(level.laser({ x: -1625, y: -850 }, { x: 1980, y: -850 })) ////x, y, width, height, damage = 0.002)
spawn.mapRect(1980, -862, 25, 25); //laser entrance
balance.push(level.rotor(1000, -910, 550, 32, 0.01, 0, 0.5))
//left side
//level entrance
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
@@ -7214,13 +7243,13 @@ const level = {
}
let buildVerticalFLippedMap = function () { // flip Y with this -> spawn.mapRect(x, -y - h, w, h);
buttons.push(level.button(-1895, 1600, 126, true, true))
buttons.push(level.button(-1895, 1600, 126, true, true, "hsl(330, 100%, 50%)"))
buttons[buttons.length - 1].isUp = false
spawn.mapRect(-1675, 2025 - 250, 50, 250);
simulation.ephemera.push({
name: "buttons up",
count: flipAnimationCycles,
count: flipAnimationCycles + 30,
do() {
this.count--
if (this.count < 0) {
@@ -7242,6 +7271,11 @@ const level = {
balance.push(level.rotor(-750, -1700 - 25, 400, 25, 0.01, Math.PI / 2, 0.5))
balance.push(level.rotor(-250, -1650 - 32, 500, 32, 0.01, 0, 0.5))
lasers.push(level.laser({ x: -1625, y: 850 }, { x: 1980, y: 850 })) ////x, y, width, height, damage = 0.002)
spawn.mapRect(1980, 862 - 25, 25, 25); //laser entrance
balance.push(level.rotor(1000, 910 - 32, 550, 32, 0.01, 0, 0.5))
//left side
//level entrance
spawn.mapRect(level.enter.x, level.enter.y - 20 - 20, 100, 20);
@@ -7329,8 +7363,24 @@ const level = {
m.history[i].angle *= -1
m.history[i].velocity.y *= -1
}
//stun to wipe history of all mobs, so they don't get confused about player position vertical swap
for (let i = 0; i < mob.length; i++) mobs.statusStun(mob[i], 1)
for (let i = 0; i < mob.length; i++) {
//stun to wipe history of all mobs, so they don't get confused about player position vertical swap
mobs.statusStun(mob[i], 1)
//edge cases
if (mob[i].history) {
for (let j = 0; j < mob[i].history.length; j++) mob[i].history[j].y *= -1
}
if (mob[i].laserArray) {
for (let j = 0; j < mob[i].laserArray.length; j++) {
mob[i].laserArray[j].a.y *= -1
mob[i].laserArray[j].b.y *= -1
}
}
if (mob[i].springTarget2) {
mob[i].springTarget.y *= -1
mob[i].springTarget2.y *= -1
}
}
}
buildMapOutline()
buildNormalMap()
@@ -7339,7 +7389,8 @@ const level = {
for (let i = 0; i < buttons.length; i++) {
buttons[i].draw()
if (buttons[i].isUp && !isFlipping) {
buttons[i].query();
// buttons[i].query();
buttons[i].queryPlayer();
if (!buttons[i].isUp) {
isFlipping = true
if (isFlipped) {
@@ -7444,7 +7495,7 @@ const level = {
}
}
ctx.fill();
ctx.fillStyle = `rgba(255,255,255,${0 + 0.3 * Math.random()})` //balances center dot
ctx.fillStyle = `rgba(255,255,255,${0 + 0.3 * Math.random()})`
if (isFlipped) {
ctx.fillRect(-2025, 2025 - 450, 400, 450);
//shadows
@@ -7518,6 +7569,351 @@ const level = {
spawn.randomLevelBoss(-875, -200);
powerUps.addResearchToLevel() //needs to run after mobs are spawned
},
gravityObservatory() {
mobs.maxMobBody = 25 //normally 40, but set lower to avoid too much clutter
level.isVerticalFLipLevel = true
simulation.fallHeight = 4000
level.announceMobTypes()
level.setPosToSpawn(-2375, 950);
level.exit.x = 3750
level.exit.y = 165
level.defaultZoom = 2600
simulation.zoomTransition(level.defaultZoom)
document.body.style.backgroundColor = "#c3d6e1";
color.map = "#444"
let buttons = []
let isFlipped = false;
let isFlipping = false;
const flipAnimationCycles = 60
let buildMapOutline = function () {
//boxes center on zero,zero with deep walls to hide background
spawn.mapRect(4000, -2000, 2000, 4000); //right map wall
spawn.mapRect(-6000, -2000, 2000, 4000); //left map wall
spawn.mapRect(-6000, -4000, 12000, 3000); //map ceiling
spawn.mapRect(-6000, 1000, 12000, 3000); //floor
}
let buildNormalMap = function () {
buttons.push(level.button(-3350, 985, 126, true, false, "hsl(330, 100%, 50%)"))
buttons.push(level.button(-3350, -985, 126, true, true, "hsl(330, 100%, 50%)"))
buttons.push(level.button(150, 985, 126, true, false, "hsl(330, 100%, 50%)"))
buttons.push(level.button(150, -985, 126, true, true, "hsl(330, 100%, 50%)"))
buttons.push(level.button(3725, 985, 126, true, false, "hsl(330, 100%, 50%)"))
buttons.push(level.button(3725, -985, 126, true, true, "hsl(330, 100%, 50%)"))
for (let i = 0; i < buttons.length; i++) buttons[i].isUp = false
simulation.ephemera.push({
name: "buttons up",
count: flipAnimationCycles,
do() {
this.count--
if (this.count < 0) {
for (let i = 0; i < buttons.length; i++) buttons[i].isUp = true
simulation.removeEphemera(this.name);
isFlipping = false
}
},
})
//far left zone
spawn.mapRect(-2575, 987, 375, 100);
spawn.mapRect(-2575, -600, 600, 1325);
spawn.mapRect(-2200, 650, 225, 475);
spawn.mapRect(-2575, 700, 35, 125);
spawn.mapRect(-3500, -1050, 425, 63);
spawn.mapRect(-3500, 987, 425, 50);
spawn.mapVertex(-2275, -1000, "-400 0 -300 150 300 150 400 0");
spawn.mapVertex(-3287, 0, "-213 -500 0 -550 213 -500 213 500 0 550 -213 500");
spawn.mapVertex(-3750, -100, "-100 -200 -50 -250 50 -250 100 -200 100 200 50 250 -50 250 -100 200");
spawn.mapVertex(-2825, 0, "-100 -400 -50 -450 50 -450 100 -400 100 400 50 450 -50 450 -100 400");
//dense center left zone
spawn.mapVertex(-1150, -750, "400 -75 425 0 400 75 -400 75 -425 0 -400 -75");
spawn.mapVertex(-550, -450, "400 -75 425 0 400 75 -400 75 -425 0 -400 -75");
spawn.mapVertex(-1685, 153, "-150 -500 0 -550 150 -500 150 750 -150 450");
spawn.mapVertex(-1106, 707, "500 -150 550 0 500 150 -500 150 -800 -150");
spawn.mapRect(-1645, 470, 200, 200);
Matter.Body.setAngle(map[map.length - 1], Math.PI / 4)
spawn.mapRect(-2085, 910, 200, 200);
Matter.Body.setAngle(map[map.length - 1], Math.PI / 4)
//open center right area with both bosses
// spawn.mapRect(0, -450, 425, 1100);
spawn.mapVertex(213, 0, "-213 -700 0 -650 213 -600 213 700 0 650 -213 600");
spawn.mapRect(0, -1050, 425, 63);
spawn.mapRect(0, 987, 425, 50);
spawn.mapVertex(1700, -1000, "-600 0 -400 400 400 400 600 0");
spawn.mapVertex(2800, -1000, "-500 0 -400 150 400 150 500 0");
spawn.mapVertex(1700, 700, "-400 -100 -450 0 -400 100 400 100 450 0 400 -100");
spawn.mapVertex(2800, 375, "-400 -100 -450 0 -400 100 400 100 450 0 400 -100");
//far right exit structure
spawn.mapRect(3575, -1050, 425, 63);
spawn.mapRect(3575, 987, 425, 50);
spawn.mapVertex(3840, 450, "-250 -300 250 -300 250 300 -250 100");
spawn.mapVertex(3840, -450, "-250 300 250 300 250 -300 -250 -100");
spawn.mapRect(3750, 185, 100, 25);
}
let buildVerticalFLippedMap = function () { // flip Y with this -> spawn.mapRect(x, -y - h, w, h);
buttons.push(level.button(-3350, 985, 126, true, false, "hsl(330, 100%, 50%)"))
buttons.push(level.button(-3350, -985, 126, true, true, "hsl(330, 100%, 50%)"))
buttons.push(level.button(150, 985, 126, true, false, "hsl(330, 100%, 50%)"))
buttons.push(level.button(150, -985, 126, true, true, "hsl(330, 100%, 50%)"))
buttons.push(level.button(3725, 985, 126, true, false, "hsl(330, 100%, 50%)"))
buttons.push(level.button(3725, -985, 126, true, true, "hsl(330, 100%, 50%)"))
for (let i = 0; i < buttons.length; i++) buttons[i].isUp = false
simulation.ephemera.push({
name: "buttons up",
count: flipAnimationCycles,
do() {
this.count--
if (this.count < 0) {
for (let i = 0; i < buttons.length; i++) buttons[i].isUp = true
simulation.removeEphemera(this.name);
isFlipping = false
}
},
})
//far left zone
spawn.mapRect(-2575, -1087, 375, 100);
spawn.mapRect(-2575, 600 - 1325, 600, 1325);
spawn.mapRect(-2200, -650 - 475, 225, 475);
spawn.mapRect(-2575, -700 - 125, 35, 125);
spawn.mapRect(-3500, 1050 - 63, 425, 63);
spawn.mapRect(-3500, -987 - 50, 425, 50);
spawn.mapVertex(-2275, 1000, "-300 0 -400 150 400 150 300 0");
spawn.mapVertex(-3287, 0, "-213 -500 0 -550 213 -500 213 500 0 550 -213 500");
spawn.mapVertex(-3750, 100, "-100 -200 -50 -250 50 -250 100 -200 100 200 50 250 -50 250 -100 200");
spawn.mapVertex(-2825, 0, "-100 -400 -50 -450 50 -450 100 -400 100 400 50 450 -50 450 -100 400");
//dense center left zone
spawn.mapVertex(-1150, 750, "400 -75 425 0 400 75 -400 75 -425 0 -400 -75");
spawn.mapVertex(-550, 450, "400 -75 425 0 400 75 -400 75 -425 0 -400 -75");
spawn.mapVertex(-1685, -153, "-150 500 0 550 150 500 150 -750 -150 -450");
spawn.mapVertex(-1106, -707, "500 150 550 0 500 -150 -500 -150 -800 150");
spawn.mapRect(-1645, -470 - 200, 200, 200);
Matter.Body.setAngle(map[map.length - 1], Math.PI / 4)
spawn.mapRect(-2085, -910 - 200, 200, 200);
Matter.Body.setAngle(map[map.length - 1], Math.PI / 4)
//open center right area with both bosses
spawn.mapVertex(213, 0, "-213 -600 0 -650 213 -700 213 600 0 650 -213 700");
spawn.mapRect(0, 1050 - 63, 425, 63);
spawn.mapRect(0, -987 - 50, 425, 50);
spawn.mapVertex(1700, 1000, "-400 0 -600 400 600 400 400 0");
spawn.mapVertex(2800, 1000, "-400 0 -500 150 500 150 400 0");
spawn.mapVertex(1700, -700, "-400 -100 -450 0 -400 100 400 100 450 0 400 -100");
spawn.mapVertex(2800, -375, "-400 -100 -450 0 -400 100 400 100 450 0 400 -100");
//far right building like exit structure
spawn.mapRect(3575, 1050 - 63, 425, 63);
spawn.mapRect(3575, -987 - 50, 425, 50);
spawn.mapVertex(3840, 450, "-250 -300 250 -300 250 300 -250 100");
spawn.mapVertex(3840, -450, "-250 300 250 300 250 -300 -250 -100");
spawn.mapRect(3750, -210, 100, 25);
}
let flipAndRemove = function () {
simulation.translatePlayerAndCamera({ x: player.position.x, y: -player.position.y })
level.enter.y = -level.enter.y
level.exit.y = -level.exit.y
for (let i = body.length - 1; i > -1; i--) {
if (body[i].isRotor) body.splice(i, 1);
}
function removeAll(array) {
for (let i = 0; i < array.length; ++i) Matter.Composite.remove(engine.world, array[i]);
}
removeAll(map);
map = [];
removeAll(buttons);
buttons = []
function invertVertical(array) {
for (let i = 0; i < array.length; ++i) {
Matter.Body.setPosition(array[i], { x: array[i].position.x, y: -array[i].position.y })
}
}
invertVertical(body);
invertVertical(powerUp);
invertVertical(bullet);
invertVertical(mob);
//fields
if (m.fieldMode === 9 && m.hole.isOn) {
m.hole.pos1.y *= -1
m.hole.pos2.y *= -1
} else if (m.fieldMode === 2) {
m.fieldPosition.y *= -1
m.fieldAngle *= -1
}
//history
for (let i = 0; i < m.history.length; i++) {
m.history[i].position.y *= -1
m.history[i].angle *= -1
m.history[i].velocity.y *= -1
}
for (let i = 0; i < mob.length; i++) {
//stun to wipe history of all mobs, so they don't get confused about player position vertical swap
mobs.statusStun(mob[i], 1)
//edge cases
if (mob[i].history) {
for (let j = 0; j < mob[i].history.length; j++) mob[i].history[j].y *= -1
}
if (mob[i].laserArray) {
for (let j = 0; j < mob[i].laserArray.length; j++) {
mob[i].laserArray[j].a.y *= -1
mob[i].laserArray[j].b.y *= -1
}
}
if (mob[i].springTarget2) {
mob[i].springTarget.y *= -1
mob[i].springTarget2.y *= -1
}
}
}
buildMapOutline()
buildNormalMap()
level.custom = () => {
//stuff floats near buttons
if ((player.position.x > -3505 && player.position.x < -3075) ||
(player.position.x > 0 && player.position.x < 425) ||
(player.position.x > 3575)) {
if (player.position.y > 0) {
player.force.y -= 0.8 * simulation.g * player.mass
}
}
for (let i = 0; i < body.length; i++) {
if ((body[i].position.x > -3505 && body[i].position.x < -3075) ||
(body[i].position.x > 0 && body[i].position.x < 425) ||
(body[i].position.x > 3575)
) {
if (body[i].position.y > 0) {
body[i].force.y -= 1.04 * simulation.g * body[i].mass
} else {
body[i].force.y += 1.04 * simulation.g * body[i].mass
}
}
}
for (let i = 0; i < powerUp.length; i++) {
if ((powerUp[i].position.x > -3505 && powerUp[i].position.x < -3075) ||
(powerUp[i].position.x > 0 && powerUp[i].position.x < 425) ||
(powerUp[i].position.x > 3575)
) {
if (powerUp[i].position.y > 0) {
powerUp[i].force.y -= 1.04 * simulation.g * powerUp[i].mass
} else {
powerUp[i].force.y += 1.04 * simulation.g * powerUp[i].mass
}
}
}
for (let i = 0; i < buttons.length; i++) {
buttons[i].draw()
if (buttons[i].isUp && !isFlipping) {
// buttons[i].query();
buttons[i].queryPlayer();
if (!buttons[i].isUp) {
isFlipping = true
if (isFlipped) {
const normalMap = function () {
isFlipped = false
flipAndRemove()
buildMapOutline()
buildNormalMap(); //rewrite flipped version of map
simulation.draw.setPaths() //update map graphics
level.addToWorld()
}
simulation.unFlipCameraVertical(flipAnimationCycles, normalMap)
} else {
const flipMap = function () {
isFlipped = true
flipAndRemove()
buildMapOutline()
buildVerticalFLippedMap(); //rewrite flipped version of map
simulation.draw.setPaths() //update map graphics
level.addToWorld()
}
simulation.flipCameraVertical(flipAnimationCycles, flipMap)
}
break
}
}
}
ctx.fillStyle = "#d4f4f4"
ctx.fillRect(3575, -300, 475, 575);
if (isFlipped) {
//draw flipped entrance
ctx.beginPath();
ctx.moveTo(level.enter.x, level.enter.y - 30);
ctx.lineTo(level.enter.x, level.enter.y + 80);
ctx.bezierCurveTo(level.enter.x, level.enter.y + 170, level.enter.x + 100, level.enter.y + 170, level.enter.x + 100, level.enter.y + 80);
ctx.lineTo(level.enter.x + 100, level.enter.y - 30);
ctx.lineTo(level.enter.x, level.enter.y - 30);
ctx.fillStyle = "#ccc";
ctx.fill();
//draw flipped exit
ctx.fillStyle = "#d4f4f4"
// ctx.fillRect(-2000, 1325, 375, 350)
ctx.beginPath();
ctx.moveTo(level.exit.x, level.exit.y - 30);
ctx.lineTo(level.exit.x, level.exit.y + 80);
ctx.bezierCurveTo(level.exit.x, level.exit.y + 170, level.exit.x + 100, level.exit.y + 170, level.exit.x + 100, level.exit.y + 80);
ctx.lineTo(level.exit.x + 100, level.exit.y - 30);
ctx.lineTo(level.exit.x, level.exit.y - 30);
ctx.fillStyle = "#0ff";
ctx.fill();
} else {
level.exit.drawAndCheck();
level.enter.draw();
}
};
level.customTopLayer = () => {
ctx.fillStyle = `rgba(255,255,255,${0 + 0.3 * Math.random()})`
ctx.fillRect(-3500, -1075, 425, 2100);
ctx.fillRect(0, -1075, 425, 2100);
ctx.fillRect(3575, -1075, 425, 2100);
ctx.fillStyle = "rgba(0,0,0,0.08)"
ctx.fillRect(-2575, -1025, 600, 2050);
ctx.fillRect(1300, -1050, 800, 2100);
ctx.fillRect(2400, -1050, 800, 2100);
};
// spawn.bodyRect(1900, 1875, 100, 125, 0.5);
spawn.bodyRect(-2569, 825, 25, 165);
spawn.randomMob(-3750, -400, 0.2);
spawn.randomMob(-3425, -600, 0.2);
spawn.randomMob(-3225, -625, 0.3);
spawn.randomMob(-2850, -500, 0.3);
spawn.randomMob(-2450, -675, 0.3);
spawn.randomMob(-2150, -650, 0.4);
spawn.randomMob(-1650, -500, 0.4);
spawn.randomMob(-1325, 275, 0.4);
spawn.randomMob(-825, 425, 0.5);
spawn.randomMob(-400, -575, 0.5);
spawn.randomMob(-1275, -900, 0.5);
spawn.randomMob(-675, -775, 0.6);
spawn.randomMob(150, -725, 0.6);
spawn.randomMob(475, 925, 0.7);
spawn.randomMob(1500, 550, 0.7);
spawn.randomMob(1850, 500, 0.7);
spawn.randomMob(2025, 925, 0.8);
spawn.randomMob(1575, 875, 0.8);
spawn.randomMob(2650, 650, 0.9);
spawn.randomMob(3100, 700, 0.9);
spawn.randomMob(3050, 100, 1);
spawn.randomMob(2350, 100, 1);
spawn.randomMob(3400, 875, 1);
spawn.randomMob(3375, -725, 1);
spawn.randomMob(3925, 100, 1);
powerUps.spawnStartingPowerUps(-825, -600);
spawn.randomLevelBoss(1550, 200);
spawn.secondaryBossChance(2675, -125)
powerUps.addResearchToLevel() //needs to run after mobs are spawned
},
lock() {
level.announceMobTypes()
level.setPosToSpawn(0, -65); //lower start
@@ -18624,7 +19020,7 @@ const level = {
const door3 = level.door(20238, -781.4, 88, 452, 412)
const hazard2 = level.hazard(2550, -150, 10, 0.4) //y=-1485
simulation.enableConstructMode()
// simulation.enableConstructMode()
level.setPosToSpawn(0, -50); //normal spawn
level.exit.x = 15316;
level.exit.y = -30;
@@ -21089,7 +21485,7 @@ const level = {
ctx.fillRect(1675, -2325, 250, 75);
ctx.fillRect(2700, -2525, 25, 150);
};
simulation.enableConstructMode()
// simulation.enableConstructMode()
level.setPosToSpawn(0, -50); //normal spawn
level.exit.x = 23885;
level.exit.y = 800;
@@ -21221,7 +21617,7 @@ const level = {
const slime2 = level.hazard(2400, -2100, 200, 2100);
const slime3 = level.hazard(2600, -2100, 3600, 200);
const slime4 = level.hazard(6400, -2100, 3600, 200);
simulation.enableConstructMode()
// simulation.enableConstructMode()
level.setPosToSpawn(0, -50); //normal spawn
level.exit.x = 13130.3;
let rainCount = 1
@@ -24060,7 +24456,7 @@ const level = {
}
}
};
simulation.enableConstructMode() //landgreen if you see this can you remove im probably gonna forget
// simulation.enableConstructMode() //landgreen if you see this can you remove im probably gonna forget
for (let i = 0; i < spawn.bossTypeSpawnOrder.length * Math.random(); i++) {
spawn.bossTypeSpawnOrder.splice(i * Math.floor(Math.random() * spawn.bossTypeSpawnOrder.length), 1, "restoreBoss") //meh good enough
}
@@ -24212,7 +24608,7 @@ const level = {
}
Composite.add(engine.world, me.constraint);
}
simulation.enableConstructMode()
// simulation.enableConstructMode()
let firstMobsSpawned = 1
let secondMobsSpawned = 0
let thirdMobsSpawned = 0
@@ -27153,7 +27549,7 @@ const level = {
const door3 = level.door(20238, -781.4, 88, 452, 412)
//y=-1485
simulation.enableConstructMode()
// simulation.enableConstructMode()
level.setPosToSpawn(0, -50); //normal spawn
level.exit.x = 15316;
level.exit.y = -84;
@@ -36285,10 +36681,9 @@ const level = {
}
for (let i = 0; i < 2; i++) {
spawn.spinner(1300 + i, -3000 - 200 * i, 25 + 5 * i)
Matter.Body.setVelocity(mob[mob.length - 1], {
x: 0,
y: 62
});
const who = mob[mob.length - 1]
Matter.Body.setVelocity(who, { x: 0, y: 62 });
who.isDropPowerUp = false
}
spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
@@ -36373,6 +36768,7 @@ const level = {
}
for (let i = 0; i < 3; i++) {
spawn.hopper(1300 + i, -3000 - 2000 * i, 25 + 5 * i)
mob[mob.length - 1].isDropPowerUp = false
// Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 });
}
spawn.mapRect(-2750, -2800, 2600, 4600); //left wall
@@ -36455,6 +36851,7 @@ const level = {
}
for (let i = 0; i < 6; i++) {
spawn.spawner(i * 230, -800)
mob[mob.length - 1].isDropPowerUp = false
// Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 });
}
spawn.mapVertex(510, -430, "725 0 725 80 -650 80 -650 -80 650 -80"); //upper room with mobs
@@ -36538,6 +36935,7 @@ const level = {
}
for (let i = 0; i < 6; i++) {
spawn.springer(i * 200, -800)
mob[mob.length - 1].isDropPowerUp = false
// Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 });
}
spawn.springer(1825, -330, 20);
@@ -36627,6 +37025,7 @@ const level = {
}
for (let i = 0; i < 10; i++) {
spawn.springer(2100 + i * 100, -250)
mob[mob.length - 1].isDropPowerUp = false
// Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 0 });
}

View File

@@ -658,29 +658,6 @@ const mobs = {
this.cons.length = 100 + 1.5 * this.radius;
this.cons2.length = 100 + 1.5 * this.radius;
}
// if (!(simulation.cycle % (this.seePlayerFreq * 2))) {
// const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position))
// const goal = Vector.add(this.position, Vector.mult(unit, stepRange))
// this.springTarget.x = goal.x;
// this.springTarget.y = goal.y;
// // this.springTarget.x = this.seePlayer.position.x;
// // this.springTarget.y = this.seePlayer.position.y;
// this.cons.length = -200;
// this.cons2.length = 100 + 1.5 * this.radius;
// } else if (!(simulation.cycle % this.seePlayerFreq)) {
// const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position))
// const goal = Vector.add(this.position, Vector.mult(unit, stepRange))
// this.springTarget2.x = goal.x;
// this.springTarget2.y = goal.y;
// // this.springTarget2.x = this.seePlayer.position.x;
// // this.springTarget2.y = this.seePlayer.position.y;
// this.cons.length = 100 + 1.5 * this.radius;
// this.cons2.length = -200;
// }
}
}
}

View File

@@ -691,8 +691,8 @@ const m = {
return
}
m.lastHarmCycle = m.cycle
if (tech.isDroneOnDamage && bullet.length < 150) { //chance to build a drone on damage from tech
const len = Math.min((dmg - 0.06 * Math.random()) * 80, 60) / tech.droneEnergyReduction * (tech.isEnergyHealth ? 0.5 : 1)
if (tech.isDroneOnDamage && bullet.length < 180) { //chance to build a drone on damage from tech
const len = Math.min((dmg - 0.045 * Math.random()) * 95, 65) / tech.droneEnergyReduction * (tech.isEnergyHealth ? 0.5 : 1)
for (let i = 0; i < len; i++) {
if (Math.random() < 0.5) b.drone({
x: m.pos.x + 30 * Math.cos(m.angle) + 100 * (Math.random() - 0.5),
@@ -3074,6 +3074,51 @@ const m = {
}
},
minEnergyToDeflect: 0.05,
bulletsToBlocks(who) {
if (who.isMobBullet && !who.isInvulnerable && who.mass < 10 && body.length < mobs.maxMobBody) {
// spawn block
body[body.length] = Matter.Bodies.polygon(who.position.x, who.position.y, who.vertices.length, who.radius, {
friction: 0.05,
frictionAir: 0.001,
collisionFilter: {
category: cat.bullet,
mask: cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield
},
classType: "body",
isPrinted: true,
radius: 10, //used to grow and warp the shape of the block
density: 0.002, //double density for 2x damage
});
const block = body[body.length - 1]
Composite.add(engine.world, block); //add to world
//reverse velocity and make sure it's above 40
const unit = Vector.mult(Vector.normalise(who.velocity), -Math.max(40, who.speed))
Matter.Body.setVelocity(block, unit);
simulation.ephemera.push({
name: "remove block",
count: 120, //cycles before it self removes
do() {
this.count--
if (this.count < 0) {
simulation.removeEphemera(this.name)
Matter.Composite.remove(engine.world, block);
//find block
for (let i = 0; i < body.length; i++) {
if (body[i] === block) {
body.splice(i, 1);
break
}
}
}
},
})
//remove mob bullet
Matter.Composite.remove(engine.world, who); //remove from physics early to avoid collisions with block
who.alive = false
}
},
pushMass(who, fieldBlockCost = (0.025 + Math.sqrt(who.mass) * Vector.magnitude(Vector.sub(who.velocity, player.velocity)) * 0.002) * m.fieldShieldingScale) {
if (m.energy > m.minEnergyToDeflect) { //shield needs at least some of the cost to block
if (who.isShielded) fieldBlockCost *= 2; //shielded mobs take more energy to block
@@ -3108,6 +3153,7 @@ const m = {
}
}
}
m.bulletsToBlocks(who)
const unit = Vector.normalise(Vector.sub(player.position, who.position))
if (tech.blockDmg) {
Matter.Body.setVelocity(who, { x: 0.5 * who.velocity.x, y: 0.5 * who.velocity.y });
@@ -3282,7 +3328,8 @@ const m = {
case 6: //time dilation
return `<strong>+${(1 + 0.05 * couple).toFixed(2)}x</strong> longer <strong style='letter-spacing: 2px;'>stopped time</strong>` //<strong>movement</strong>, <strong>jumping</strong>, and
case 7: //cloaking
return `<strong>${(1 + 3.3 * couple).toFixed(3)}x</strong> ambush <strong class='color-d'>damage</strong>`
// return `<strong>${(1 + 3.3 * couple).toFixed(3)}x</strong> ambush <strong class='color-d'>damage</strong>`
return `<strong>${(1 + 0.05 * couple).toFixed(3)}x</strong> ambush <strong class='color-d'>damage</strong>`
case 8: //pilot wave
return `<strong>${(1 + 0.05 * couple).toFixed(2)}x</strong> <strong class='color-block'>block</strong> collision <strong class='color-d'>damage</strong>`
case 9: //wormhole
@@ -3577,6 +3624,7 @@ const m = {
ctx.stroke();
}
}
m.bulletsToBlocks(mob[i])
if (tech.isStunField) mobs.statusStun(mob[i], tech.isStunField)
//mob knock backs
const massRoot = Math.sqrt(Math.max(1, mob[i].mass));
@@ -4809,7 +4857,7 @@ const m = {
}
this.drawRegenEnergyCloaking()
if (m.isSneakAttack && m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) > m.cycle) { //show sneak attack status
m.fieldDamage = 4.5 * (1 + 0.033 * m.coupling)
m.fieldDamage = 4.5 * (1 + 0.05 * m.coupling)
const timeLeft = (m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) - m.cycle) * 0.5
ctx.beginPath();
ctx.arc(m.pos.x, m.pos.y, 32, 0, 2 * Math.PI);

View File

@@ -351,9 +351,10 @@ const powerUps = {
name: "instructions",
color: "rgba(100,125,140,0.35)",
size() {
return 150
return 130
},
effect() {
Matter.Body.setVelocity(player, { x: 0, y: 0 });//power up is so big it launches the player, this stops that
requestAnimationFrame(() => { //add a background behind the power up menu
ctx.fillStyle = `rgba(150,150,150,0.9)`;
ctx.fillRect(0, 0, canvas.width, canvas.height);
@@ -372,7 +373,7 @@ const powerUps = {
document.getElementById("choose-grid").classList.remove('choose-grid');
document.getElementById("choose-grid").style.gridTemplateColumns = "800px"//adjust this to increase the width of the whole menu, but mostly the center column
let lore = localSettings.loreCount > 0 ? "lore.unlockTesting() //press T to enter testing" : ""
let text = `<div class="grid-container"><pre> <strong>//console commands</strong>
let text = `<div class="grid-container" style = "font-size:1rem;"><pre> <strong>//console commands</strong>
powerUps.instructions.effect() //reproduce this message
tech.giveTech("name") //replace "name" with tech name
m.setField("name") //standing wave perfect diamagnetism negative mass molecular assembler plasma torch time dilation metamaterial cloaking pilot wave wormhole grappling hook
@@ -382,17 +383,13 @@ const powerUps = {
m.energy = 0 //set energy
m.health = 1 //set health
m.maxHealth = 1 //set max health
m.energy = 1 //set energy
m.maxEnergy = 1 //set max energy
simulation.enableConstructMode() //press T to build with mouse
${lore}
//tech gun field heal ammo research coupling boost instructions entanglement
powerUps.spawn(m.pos.x, m.pos.y, "name")
powerUps.spawn(m.pos.x, m.pos.y, "name") //tech gun field heal ammo research coupling boost instructions entanglement
Matter.Body.setPosition(player, simulation.mouseInGame);
spawn.bodyRect(simulation.mouseInGame.x, simulation.mouseInGame.y, 50, 50)
spawn.randomLevelBoss(simulation.mouseInGame.x, simulation.mouseInGame.y)
<strong>chrome</strong> <strong>firefox</strong>
<strong>Win/Linux:</strong> Ctrl + Shift + J Ctrl + Shift + J
<strong>Mac:</strong> Cmd + Option + J Cmd + Shift + J</pre></div>

View File

@@ -935,6 +935,7 @@ const simulation = {
m.onGround = false
m.lastOnGroundCycle = 0
m.health = 0;
level.isNoHeal = false
m.addHealth(0.25)
m.drop();
m.holdingTarget = null
@@ -1185,6 +1186,7 @@ const simulation = {
},
clearNow: false,
clearMap() {
level.isVerticalFLipLevel = false
level.isProcedural = false;
level.fallMode = "";
simulation.unFlipCameraVertical()
@@ -1957,6 +1959,7 @@ const simulation = {
},
enableConstructMode() {
level.isProcedural = false //this is set to be true in levels like labs that need x+ and y+ in front of positions
level.isVerticalFLipLevel = false
simulation.isConstructionMode = true;
simulation.isHorizontalFlipped = false;
simulation.isAutoZoom = false;
@@ -1983,8 +1986,17 @@ const simulation = {
simulation.outputMapString(`${Math.floor(simulation.constructMouseDownPosition.x)}, ${Math.floor(simulation.constructMouseDownPosition.y)}`);
} else if (simulation.mouseInGame.x > simulation.constructMouseDownPosition.x && simulation.mouseInGame.y > simulation.constructMouseDownPosition.y) { //make sure that the width and height are positive
if (e.button === 0) { //add map
// if (level.isProcedural) {
// simulation.outputMapString(`spawn.mapRect(x+${x}, ${y}, ${dx}, ${dy});\n`);
// } else {
// simulation.outputMapString(`spawn.mapRect(${x}, ${y}, ${dx}, ${dy});\n`);
// }
if (level.isProcedural) {
simulation.outputMapString(`spawn.mapRect(x+${x}, ${y}, ${dx}, ${dy});\n`);
} else if (level.isVerticalFLipLevel) {
console.log('hi')
simulation.outputMapString(`spawn.mapRect(${x}, ${y}, ${dx}, ${dy});\n`);
simulation.outputMapString(`//spawn.mapRect(${x}, ${-y - dy}, ${dx}, ${dy});\n`);
} else {
simulation.outputMapString(`spawn.mapRect(${x}, ${y}, ${dx}, ${dy});\n`);
}

View File

@@ -2559,10 +2559,7 @@ const spawn = {
const springStiffness = 0.00014;
const springDampening = 0.0005;
me.springTarget = {
x: me.position.x,
y: me.position.y
};
me.springTarget = { x: me.position.x, y: me.position.y };
const len = cons.length;
cons[len] = Constraint.create({
pointA: me.springTarget,
@@ -4322,7 +4319,7 @@ const spawn = {
me.accelMag = 0.0002 * simulation.accelScale;
spawn.shield(me, x, y);
me.lasers = [] //keeps track of static laser beams
me.laserArray = [] //keeps track of static laser beams
me.laserLimit = simulation.difficultyMode < 3 ? 1 : 2
me.fireDelay = Math.max(75, 140 - simulation.difficulty * 0.5)
me.cycle = 0
@@ -4354,14 +4351,14 @@ const spawn = {
best2.y = save1Y
}
this.lasers.push({ a: { x: best1.x, y: best1.y }, b: { x: best2.x, y: best2.y }, fade: 0 })
this.laserArray.push({ a: { x: best1.x, y: best1.y }, b: { x: best2.x, y: best2.y }, fade: 0 })
//friction to animate the mob dropping something
Matter.Body.setVelocity(this, Vector.mult(this.velocity, 0.05));
Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.05)
// simulation.drawList.push({ x: best1.x, y: best1.y, radius: 10, color: "rgba(255,0,100,0.3)", time: simulation.drawTime * 2 });
// simulation.drawList.push({ x: best2.x, y: best2.y, radius: 10, color: "rgba(255,0,100,0.3)", time: simulation.drawTime * 2 });
if (this.lasers.length > this.laserLimit) this.lasers.shift() //cap total lasers
if (this.laserArray.length > this.laserLimit) this.laserArray.shift() //cap total laserArray
if (!this.seePlayer.recall && (Vector.magnitude(Vector.sub(this.position, this.driftGoal)) < 200 || 0.3 > Math.random())) {
//used in drift when can't find player
const radius = Math.random() * 1000;
@@ -4371,9 +4368,9 @@ const spawn = {
}
}
me.fireLaser = function () {
for (let i = 0; i < this.lasers.length; i++) { //fire all lasers in the array
let best = vertexCollision(this.lasers[i].a, this.lasers[i].b, m.isCloak ? [body] : [body, [playerBody, playerHead]]); //not checking map to fix not hitting player bug, this might make some lasers look strange when the map changes
if (this.lasers[i].fade > 0.99) {
for (let i = 0; i < this.laserArray.length; i++) { //fire all lasers in the array
let best = vertexCollision(this.laserArray[i].a, this.laserArray[i].b, m.isCloak ? [body] : [body, [playerBody, playerHead]]); //not checking map to fix not hitting player bug, this might make some lasers look strange when the map changes
if (this.laserArray[i].fade > 0.99) {
if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { // hitting player
m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage after getting hit
const dmg = 0.03 * simulation.dmgScale;
@@ -4385,7 +4382,7 @@ const spawn = {
color: "rgba(255,0,100,0.5)",
time: 20
});
this.lasers.splice(i, 1) //remove this laser node
this.laserArray.splice(i, 1) //remove this laser node
if (this.distanceToPlayer < 1000) { //mob jumps away from player
const forceMag = 0.03 * this.mass;
const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
@@ -4395,7 +4392,7 @@ const spawn = {
} else if (best.who && best.who.classType === "body") { //hitting block
ctx.beginPath();
ctx.moveTo(best.x, best.y);
ctx.lineTo(this.lasers[i].a.x, this.lasers[i].a.y);
ctx.lineTo(this.laserArray[i].a.x, this.laserArray[i].a.y);
ctx.strokeStyle = `rgb(255,0,100)`;
ctx.lineWidth = 2;
ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
@@ -4403,8 +4400,8 @@ const spawn = {
ctx.setLineDash([]);
} else { //hitting nothing
ctx.beginPath();
ctx.moveTo(this.lasers[i].b.x, this.lasers[i].b.y);
ctx.lineTo(this.lasers[i].a.x, this.lasers[i].a.y);
ctx.moveTo(this.laserArray[i].b.x, this.laserArray[i].b.y);
ctx.lineTo(this.laserArray[i].a.x, this.laserArray[i].a.y);
ctx.strokeStyle = `rgb(255,0,100)`;
ctx.lineWidth = 2;
ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
@@ -4412,12 +4409,12 @@ const spawn = {
ctx.setLineDash([]);
}
} else {//fade in warning
this.lasers[i].fade += 0.01
this.laserArray[i].fade += 0.01
ctx.beginPath();
ctx.moveTo(this.lasers[i].a.x, this.lasers[i].a.y);
ctx.lineTo(this.lasers[i].b.x, this.lasers[i].b.y);
ctx.lineWidth = 2 + 40 - 40 * this.lasers[i].fade;
ctx.strokeStyle = `rgba(255,0,100,${0.02 + 0.1 * this.lasers[i].fade})`;
ctx.moveTo(this.laserArray[i].a.x, this.laserArray[i].a.y);
ctx.lineTo(this.laserArray[i].b.x, this.laserArray[i].b.y);
ctx.lineWidth = 2 + 40 - 40 * this.laserArray[i].fade;
ctx.strokeStyle = `rgba(255,0,100,${0.02 + 0.1 * this.laserArray[i].fade})`;
ctx.stroke();
}
}
@@ -4486,7 +4483,7 @@ const spawn = {
this.laserDelay = 130
}
};
me.lasers = [] //keeps track of static laser beams
me.laserArray = [] //keeps track of static laser beams
me.laserLimit = 2 + (simulation.difficultyMode > 2) + (simulation.difficultyMode > 4)
me.fireDelay = Math.max(75, 140 - simulation.difficulty * 0.5)
me.cycle = 0
@@ -4517,7 +4514,7 @@ const spawn = {
best2.x = save1X
best2.y = save1Y
}
this.lasers.push({ a: { x: best1.x, y: best1.y }, b: { x: best2.x, y: best2.y }, fade: 0 })
this.laserArray.push({ a: { x: best1.x, y: best1.y }, b: { x: best2.x, y: best2.y }, fade: 0 })
}
// add(m.pos, m.angle)
add(m.pos, this.angle + Math.PI / 4 + Math.PI / 2)
@@ -4534,9 +4531,9 @@ const spawn = {
}
}
me.fireLaser = function () {
for (let i = 0; i < this.lasers.length; i++) { //fire all lasers in the array
let best = vertexCollision(this.lasers[i].a, this.lasers[i].b, m.isCloak ? [body] : [body, [playerBody, playerHead]]); //not checking map to fix not hitting player bug, this might make some lasers look strange when the map changes
if (this.lasers[i].fade > 0.99) {
for (let i = 0; i < this.laserArray.length; i++) { //fire all laserArray in the array
let best = vertexCollision(this.laserArray[i].a, this.laserArray[i].b, m.isCloak ? [body] : [body, [playerBody, playerHead]]); //not checking map to fix not hitting player bug, this might make some lasers look strange when the map changes
if (this.laserArray[i].fade > 0.99) {
if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) { // hitting player
m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage after getting hit
const dmg = 0.03 * simulation.dmgScale;
@@ -4548,7 +4545,7 @@ const spawn = {
color: "rgba(255,0,100,0.5)",
time: 20
});
this.lasers.splice(i, 1) //remove this laser node
this.laserArray.splice(i, 1) //remove this laser node
if (this.distanceToPlayer < 1000) { //mob jumps away from player
const forceMag = 0.03 * this.mass;
const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
@@ -4558,7 +4555,7 @@ const spawn = {
} else if (best.who && best.who.classType === "body") { //hitting block
ctx.beginPath();
ctx.moveTo(best.x, best.y);
ctx.lineTo(this.lasers[i].a.x, this.lasers[i].a.y);
ctx.lineTo(this.laserArray[i].a.x, this.laserArray[i].a.y);
ctx.strokeStyle = `rgb(255,0,100)`;
ctx.lineWidth = 2;
ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
@@ -4566,8 +4563,8 @@ const spawn = {
ctx.setLineDash([]);
} else { //hitting nothing
ctx.beginPath();
ctx.moveTo(this.lasers[i].b.x, this.lasers[i].b.y);
ctx.lineTo(this.lasers[i].a.x, this.lasers[i].a.y);
ctx.moveTo(this.laserArray[i].b.x, this.laserArray[i].b.y);
ctx.lineTo(this.laserArray[i].a.x, this.laserArray[i].a.y);
ctx.strokeStyle = `rgb(255,0,100)`;
ctx.lineWidth = 2;
ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]);
@@ -4575,16 +4572,16 @@ const spawn = {
ctx.setLineDash([]);
}
} else {//fade in warning
this.lasers[i].fade += 0.007
this.laserArray[i].fade += 0.007
ctx.beginPath();
ctx.moveTo(this.lasers[i].a.x, this.lasers[i].a.y);
ctx.lineTo(this.lasers[i].b.x, this.lasers[i].b.y);
ctx.lineWidth = 2 + 40 - 40 * this.lasers[i].fade;
ctx.strokeStyle = `rgba(255,0,100,${0.02 + 0.1 * this.lasers[i].fade})`;
ctx.moveTo(this.laserArray[i].a.x, this.laserArray[i].a.y);
ctx.lineTo(this.laserArray[i].b.x, this.laserArray[i].b.y);
ctx.lineWidth = 2 + 40 - 40 * this.laserArray[i].fade;
ctx.strokeStyle = `rgba(255,0,100,${0.02 + 0.1 * this.laserArray[i].fade})`;
ctx.stroke();
if (this.lasers[i].fade > 0.99) {
this.lasers[i].fade = 1;
if (this.lasers.length > this.laserLimit) this.lasers.shift() //cap total lasers
if (this.laserArray[i].fade > 0.99) {
this.laserArray[i].fade = 1;
if (this.laserArray.length > this.laserLimit) this.laserArray.shift() //cap total lasers
break
}
}
@@ -4744,9 +4741,9 @@ const spawn = {
Matter.Body.setAngularVelocity(this, 0)
}
ctx.beginPath();
this.lasers(this.vertices[0], this.angle + Math.PI / 3);
this.lasers(this.vertices[1], this.angle + Math.PI);
this.lasers(this.vertices[2], this.angle - Math.PI / 3);
this.laserArray(this.vertices[0], this.angle + Math.PI / 3);
this.laserArray(this.vertices[1], this.angle + Math.PI);
this.laserArray(this.vertices[2], this.angle - Math.PI / 3);
ctx.strokeStyle = "#50f";
ctx.lineWidth = 1.5;
ctx.setLineDash([70 + 300 * Math.random(), 55 * Math.random()]);
@@ -4757,7 +4754,7 @@ const spawn = {
ctx.stroke(); // Draw it
}
};
me.lasers = function (where, angle) {
me.laserArray = function (where, angle) {
const seeRange = 7000;
best = {
x: null,

View File

@@ -2634,25 +2634,6 @@ const tech = {
tech.isDarkStar = false
}
},
{
name: "ablative drones",
descriptionFunction() {
return `after losing ${tech.isEnergyHealth ? "<strong class='color-f'>energy</strong>" : "<strong class='color-h'>health</strong>"} there is a chance<br>to rebuild your broken parts as <strong>drones</strong>`
},
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed: () => true,
requires: "",
effect() {
tech.isDroneOnDamage = true;
// for (let i = 0; i < 4; i++) b.drone()
},
remove() {
tech.isDroneOnDamage = false;
}
},
{
name: "non-Newtonian armor",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Non-Newtonian_fluid' class="link">non-Newtonian armor</a>`,
@@ -4574,7 +4555,7 @@ const tech = {
name: "deprecated",
scale: 0.08,
descriptionFunction() {
return `after <span class='color-remove'>removing</span> this gain<br><strong>${1 + this.scale}x</strong> <strong class='color-d'>damage</strong> per <span class='color-remove'>removed</span> ${powerUps.orb.tech()}<em style ="float: right;">(${(1 + this.scale * ((this.frequency === 0 ? 0 : 1) + tech.removeCount)).toFixed(2)}x)</em>`
return `after <span class='color-remove'>removing</span> this gain <strong>${1 + this.scale}x</strong> <strong class='color-d'>damage</strong><br>per ${powerUps.orb.tech()} <span class='color-remove'>removed</span> this game<em style ="float: right;">(${(1 + this.scale * ((this.frequency === 0 ? 0 : 1) + tech.removeCount)).toFixed(2)}x)</em>`
},
maxCount: 1,
count: 0,
@@ -6607,7 +6588,7 @@ const tech = {
allowed() {
return tech.haveGunCheck("drones", false) && !tech.isDroneRespawn && tech.bulletsLastLonger === 1 && !tech.isDronesTravel && (build.isExperimentSelection || powerUps.research.count > 1)
},
requires: "drones, not drone repair, anti-shear topology, autonomous navigation",
requires: "drones, not drone repair, anti-shear topology, autonomous navigation, ",
effect() {
const num = 5
tech.isForeverDrones += num
@@ -6640,6 +6621,27 @@ const tech = {
// if (this.count > 0) powerUps.research.changeRerolls(2)
}
},
{
name: "ablative drones",
descriptionFunction() {
return `after losing ${tech.isEnergyHealth ? "<strong class='color-f'>energy</strong>" : "<strong class='color-h'>health</strong>"} there is a chance<br>to rebuild your broken parts as <strong>drones</strong>`
},
isGunTech: true,
maxCount: 1,
count: 0,
frequency: 1,
frequencyDefault: 1,
allowed() {
return (tech.haveGunCheck("drones") && !tech.isForeverDrones) || (m.fieldMode === 4 && simulation.molecularMode === 3)
},
requires: "drones, not fault tolerance",
effect() {
tech.isDroneOnDamage = true;
},
remove() {
tech.isDroneOnDamage = false;
}
},
{
name: "reduced tolerances",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Engineering_tolerance' class="link">reduced tolerances</a>`,