level ban setting

new setting: level ban list
bug fix: removed a command to preventDefault on space key, this might break something else
new boss added to level - Temple

snake tails have a lower mass and whip around a bit
auto targeting no longer works for stealth mobs
  snipers, sneakers, ghosters
snipers fire more often at high difficulty, but bullets move slower at all difficulties
hoppers have move gravity, so it feels like they are hopping a bit faster
This commit is contained in:
landgreen
2022-08-11 16:46:42 -07:00
parent 50dcc0c9dc
commit fee9526268
9 changed files with 454 additions and 152 deletions

View File

@@ -247,6 +247,8 @@ const build = {
<br><strong class='color-defense'>defense</strong>: ${(1-m.harmReduction()).toPrecision(3)} &nbsp; &nbsp; difficulty: ${(1/simulation.dmgScale).toPrecision(3)}
<br><strong><em>fire rate</em></strong>: ${((1-b.fireCDscale)*100).toFixed(b.fireCDscale < 0.1 ? 2 : 0)}%
<br><strong class='color-dup'>duplication</strong>: ${(tech.duplicationChance()*100).toFixed(0)}%
<br><strong class='color-coupling'>coupling</strong>: ${(m.coupling).toFixed(2)}
${m.coupling> 0 ? '<br>'+m.couplingDescription(): ""}
${botText}
<br>
<br><strong class='color-h'>health</strong>: (${(m.health*100).toFixed(0)} / ${(m.maxHealth*100).toFixed(0)})
@@ -920,7 +922,7 @@ window.addEventListener("keydown", function(event) {
input.fire = true
break
case input.key.field:
event.preventDefault();
// event.preventDefault();
input.field = true
break
case input.key.nextGun:
@@ -1248,7 +1250,6 @@ if (localstorageCheck()) {
localSettings = { isAllowed: false }
}
if (localSettings.isAllowed && !localSettings.isEmpty) {
console.log('restoring previous settings')
@@ -1279,10 +1280,18 @@ if (localSettings.isAllowed && !localSettings.isEmpty) {
simulation.fpsCapDefault = Number(localSettings.fpsCapDefault)
}
document.getElementById("fps-select").value = localSettings.fpsCapDefault
if (localSettings.banList.length === 0 || localSettings.banList === "undefined") {
localSettings.banList = ""
localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
}
document.getElementById("banned").value = localSettings.banList
} else {
console.log('setting default localSettings')
const isAllowed = localSettings.isAllowed //don't overwrite isAllowed value
localSettings = {
banList: "",
isAllowed: isAllowed,
personalSeeds: [],
isJunkExperiment: false,
@@ -1302,6 +1311,7 @@ if (localSettings.isAllowed && !localSettings.isEmpty) {
simulation.isCommunityMaps = localSettings.isCommunityMaps
document.getElementById("difficulty-select").value = localSettings.difficultyMode
document.getElementById("fps-select").value = localSettings.fpsCapDefault
document.getElementById("banned").value = localSettings.banList
}
document.getElementById("control-testing").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
// document.getElementById("experiment-button").style.visibility = (localSettings.loreCount === 0) ? "hidden" : "visible"
@@ -1322,6 +1332,11 @@ document.getElementById("fps-select").addEventListener("input", () => {
if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
});
document.getElementById("banned").addEventListener("input", () => {
localSettings.banList = document.getElementById("banned").value
if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
});
document.getElementById("community-maps").addEventListener("input", () => {
simulation.isCommunityMaps = document.getElementById("community-maps").checked
localSettings.isCommunityMaps = simulation.isCommunityMaps

View File

@@ -16,16 +16,16 @@ const level = {
start() {
if (level.levelsCleared === 0) { //this code only runs on the first level
// simulation.enableConstructMode() //used to build maps in testing mode
// level.difficultyIncrease(1 * 4) //30 is near max on hard //60 is near max on why
// level.difficultyIncrease(5 * 4) //30 is near max on hard //60 is near max on why
// simulation.isHorizontalFlipped = true
// m.maxHealth = m.health = 100
// tech.isRerollDamage = true
// powerUps.research.changeRerolls(100000)
// m.immuneCycle = Infinity //you can't take damage
// tech.tech[297].frequency = 100
// b.guns[0].ammo = 10000
// m.setField("time dilation") //molecular assembler time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass
// b.giveGuns("nail gun") //0 nail gun 1 shotgun 2 super balls 3 matter wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser
// b.guns[0].ammo = 1000000
// tech.giveTech("sentry");
// tech.giveTech("MACHO");
// tech.giveTech("elephant's toothpaste")
@@ -36,10 +36,8 @@ const level = {
// for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech");
// for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "research");
// spawn.flutter(1900, -500, 10)
// spawn.starter(1900, -500, 200)
// spawn.historyBoss(1900, -400)
// spawn.beetleBoss(1900, -400)
// spawn.snakeSpitBoss(1900, -400)
// for (let i = 0; i < 15; ++i) spawn.starter(1900 + 300 * Math.random(), -500 + 300 * Math.random())
// level.testing();
// for (let i = 0; i < 7; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research");
@@ -239,30 +237,44 @@ const level = {
}
},
populateLevels() { //run a second time if URL is loaded
if (document.getElementById("seed").value) {
if (document.getElementById("banned").value) { //remove levels from ban list in settings
const banList = document.getElementById("banned").value.replace(/,/g, ' ').replace(/\s\s+/g, ' ').replace(/[^\w\s]/g, '') //replace commas with spaces, replace double spaces with single, remove strange symbols
const remove = banList.split(" ");
console.log('remove these', remove)
console.log('community levels before', level.communityLevels)
for (let i = 0; i < remove.length; i++) {
const index = level.communityLevels.indexOf(remove[i])
if (index !== -1) level.communityLevels.splice(index, 1);
}
console.log('community levels after', level.communityLevels)
console.log('Landgreen levels before', level.playableLevels)
for (let i = 0; i < remove.length; i++) {
if (level.playableLevels.length + level.communityLevels.length * simulation.isCommunityMaps < 10) break //can't remove too many levels
const index = level.playableLevels.indexOf(remove[i])
if (index !== -1) level.playableLevels.splice(index, 1);
}
console.log('Landgreen levels after', level.playableLevels)
}
if (document.getElementById("seed").value) { //check for player entered seed in settings
Math.initialSeed = String(document.getElementById("seed").value)
Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it
}
if (simulation.isTraining) {
level.levels = level.trainingLevels.slice(0) //copy array, not by just by assignment
} else {
simulation.isHorizontalFlipped = (Math.seededRandom() < 0.5) ? true : false //if true, some maps are flipped horizontally
} else { //add remove and shuffle levels for the normal game (not training levels)
level.levels = level.playableLevels.slice(0) //copy array, not by just by assignment
if (simulation.isCommunityMaps) {
// level.levels.push(level.communityLevels)
level.levels = level.levels.concat(level.communityLevels)
level.levels = shuffle(level.levels); //shuffles order of maps
level.levels.splice(0, level.communityLevels.length); //remove some random levels to make up for adding the community levels
simulation.isHorizontalFlipped = false;
} else {
level.levels = shuffle(level.levels); //shuffles order of maps
simulation.isHorizontalFlipped = (Math.seededRandom() < 0.5) ? true : false //if true, some maps are flipped horizontally
}
// level.levels.splice(Math.floor(level.levels.length * (0.4 + 0.6 * Math.random())), 0, "reservoir"); //add level to the back half of the randomized levels list
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, "reservoir"); //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
// level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.2, level.levels.length * 0.5)), 0, "reactor"); //add level to the back half of the randomized levels list
// level.levels.splice(Math.floor(Math.seededRandom(level.levels.length * 0.7, level.levels.length)), 0, "reactor"); //add level to the back half of the randomized levels list
level.levels.splice(0, 2); //remove 2 levels from the start of the array
if (!build.isExperimentSelection || (build.hasExperimentalMode && !simulation.isCheating)) { //experimental mode is endless, unless you only have an experiment Tech
level.levels.unshift("intro"); //add level to the start of the randomized levels list
level.levels.push("gauntlet"); //add level to the end of the randomized levels list
@@ -9923,7 +9935,6 @@ const level = {
powerUps.spawn(3000, -230, "heal");
// level.difficultyIncrease(60)
},
temple() {
simulation.makeTextLog(`<strong>temple</strong> by <span class='color-var'>Scar1337</span>`);
@@ -9977,6 +9988,26 @@ const level = {
Rect.fromBounds = function(min, max) {
return new Rect(min.x, min.y, max.x - min.x, max.y - min.y);
}
Rect.prototype.isCollidingWith = function(other) {
const tc = {
p1: [this.pos.x, this.pos.y],
p2: [this.pos.x + this.width, this.pos.y + this.height]
};
const oc = {
p1: [other.pos.x, other.pos.y],
p2: [other.pos.x + other.width, other.pos.y + other.height]
};
// If one rectangle is on left side of other
if (tc.p1[0] >= oc.p2[0] || oc.p1[0] >= tc.p2[0])
return false;
// If one rectangle is above other
if (tc.p1[1] >= oc.p2[1] || oc.p1[1] >= tc.p2[1])
return false;
return true;
}
return Rect;
})();
@@ -9998,7 +10029,7 @@ const level = {
}
}
function secondRoomBoss(x, y, radius = 25, isDark = false) {
function secondRoomSuckerBoss(x, y, isDark = false, radius = 25) {
mobs.spawn(x, y, 12, radius, isDark ? "#000" : "#fff");
let me = mob[mob.length - 1];
me.isBoss = true;
@@ -10100,6 +10131,119 @@ const level = {
}
};
function secondRoomPlacerBoss(x, y, isDark = false, size = 70) {
mobs.spawn(x, y, isDark ? 3 : 4, size, isDark ? "#0008" : "#fff8");
let me = mob[mob.length - 1];
me.isBoss = true;
me.isDark = isDark;
me.stroke = isDark ? "#000" : "#fff";
me.seeAtDistance2 = 5e6; // Basically just see at all times, in the context it's given
me.accelMag = 0.0001 * simulation.accelScale;
me.collisionFilter.mask = cat.player | cat.bullet;
me.memory = 1600;
me.randomPRNGMult = Math.random() * 500;
me.attackCycle = 0;
me.maxAttackCycle = isDark ? 90 : 240;
Matter.Body.setDensity(me, 0.006); // extra dense, normal is 0.001 // makes effective life much larger
me.onDeath = function() {
powerUps.spawn(this.position.x + 20, this.position.y, "ammo");
if (Math.random() > 0.5) powerUps.spawn(this.position.x, this.position.y, "ammo");
if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, null, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5));
};
me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1);
me.do = function() {
// keep it slow, to stop issues from explosion knock backs
if (this.speed > 2) {
Matter.Body.setVelocity(this, {
x: this.velocity.x * 0.95,
y: this.velocity.y * 0.95
});
}
if (!(simulation.cycle % this.seePlayerFreq)) {
if (this.distanceToPlayer2() < this.seeAtDistance2) { // ignore cloak
this.locatePlayer();
if (!this.seePlayer.yes) this.seePlayer.yes = true;
} else if (this.seePlayer.recall) {
this.lostPlayer();
}
}
this.checkStatus();
if (this.seePlayer.recall) {
// accelerate towards the player
const forceMag = this.accelMag * this.mass;
const dx = this.seePlayer.position.x - this.position.x
const dy = this.seePlayer.position.y - this.position.y
const mag = Math.sqrt(dx * dx + dy * dy)
this.force.x += forceMag * dx / mag;
this.force.y += forceMag * dy / mag;
this.attackCycle++;
if (this.attackCycle > this.maxAttackCycle) {
this.attackCycle = 0;
secondRoomObstacle(this.position.x, this.position.y, this.isDark, size);
}
}
}
};
function secondRoomObstacle(x, y, isDark = false, size = 70) {
mobs.spawn(x, y, isDark ? 3 : 4, size, isDark ? "#0004" : "#fff4");
let me = mob[mob.length - 1];
me.stroke = isDark ? "#000b" : "#fffb";
me.collisionFilter.mask = isDark ? cat.player | cat.bullet : 0;
me.isDropPowerUp = false;
me.showHealthBar = false;
me.leaveBody = false;
me.timeLeft = 1200;
me.isObstacle = true;
me.damageReduction = isDark ? 0.5 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) : 0;
if (!isDark) {
me.isBadTarget = true;
me.attackCycle = 0;
me.maxAttackCycle = 10;
me.inertia = Infinity;
}
me.do = isDark ? function() {
Matter.Body.setVelocity(this, {
x: this.velocity.x * 0.95,
y: this.velocity.y * 0.95
});
} : function() {
Matter.Body.setVelocity(this, {
x: this.velocity.x * 0.95,
y: this.velocity.y * 0.95
});
if (Rect.fromBounds(this.bounds.min, this.bounds.max).isCollidingWith(Rect.fromBounds(player.bounds.min, player.bounds.max))) {
this.attackCycle++;
this.attackCycle = Math.min(this.attackCycle, 10);
} else {
this.attackCycle--;
this.attackCycle = Math.max(this.attackCycle, 0);
}
if (this.attackCycle > 0) {
ctx.beginPath();
const vertices = this.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
if (this.attackCycle >= 10) {
ctx.shadowBlur = 10;
ctx.shadowColor = "rgb(255, 210, 64)";
}
ctx.fillStyle = `rgba(255, 210, 64, ${this.attackCycle / 15})`;
ctx.fill();
ctx.shadowBlur = 0;
if (this.attackCycle >= 10) {
DrawTools.lightning(this.position, m.pos, simulation.cycle);
m.damage(0.003 * simulation.dmgScale);
}
}
this.timeLimit();
}
}
function mobGrenade(...args) {
spawn.grenade(...args);
const pulseRadius = args[3] || Math.min(550, 250 + simulation.difficulty * 3)
@@ -10209,12 +10353,12 @@ const level = {
}
}
me.horizon = function() {
if (this.isInvulnerable) return;
if (this.isInvulnerable) return this.fill = "#f00";
// eventHorizon waves in and out
const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008));
const charge = this.attackCycle / 90;
this.fill = this.isInvulnerable ? "#f00" : `rgb(${charge * 255},${charge * 255},${charge * 255})`;
this.fill = `rgb(${charge * 255},${charge * 255},${charge * 255})`;
// draw darkness
ctx.fillStyle = `rgba(${charge * 225},${20 + charge * 195},${40 + charge * 215},0.6)`;
DrawTools.arc(this.position.x, this.position.y, eventHorizon * 0.2, 0, 2 * Math.PI);
@@ -11048,7 +11192,7 @@ const level = {
if (simulation.cycle % 4 === 0) {
let newMobPositions = [];
for (const i of mob) {
if (!(i.isMACHO || i.isWIMP)) newMobPositions.push({ x: i.position.x, y: i.position.y });
if (!(i.isMACHO || i.isWIMP || i.isObstacle)) newMobPositions.push({ x: i.position.x, y: i.position.y });
}
mobPositionsQueue.shift();
mobPositionsQueue.push(newMobPositions);
@@ -11135,11 +11279,12 @@ const level = {
room2() {
if (!isInBound(secondRoomBounds)) return;
if (templePlayer.room2.spawnInitiatorCycles > Objects.room2Initiator.cap) {
const randomSecondRoomBoss = [secondRoomSuckerBoss, secondRoomPlacerBoss];
if (templePlayer.room2.cycles % 720 === 0 && templePlayer.room2.cycles <= 2160) {
const isOdd = Math.floor(templePlayer.room2.cycles / 720) & 1;
secondRoomBoss(-600, -9800, 25, isOdd);
secondRoomBoss(600, -9800, 25, isOdd);
secondRoomBoss(0, -9800, 25, !isOdd);
randomSecondRoomBoss[Math.floor(randomSecondRoomBoss.length * Math.random())](-600, -9800, isOdd);
randomSecondRoomBoss[Math.floor(randomSecondRoomBoss.length * Math.random())](600, -9800, isOdd);
randomSecondRoomBoss[Math.floor(randomSecondRoomBoss.length * Math.random())](0, -9800, !isOdd);
}
templePlayer.room2.cycles++;
if (templePlayer.room2.cycles === 2400) {
@@ -11310,6 +11455,7 @@ const level = {
DrawHandler.room2Top();
};
},
// temple() {
// simulation.makeTextLog(`<strong>temple</strong> by <span class='color-var'>Scar1337</span>`);

View File

@@ -898,6 +898,7 @@ const m = {
maxEnergy: 1, //can be increased by a tech
holdingTarget: null,
timeSkipLastCycle: 0,
coupling: 0,
// these values are set on reset by setHoldDefaults()
fieldFx: 1,
fieldJump: 1,
@@ -1517,6 +1518,30 @@ const m = {
}
},
hold() {},
couplingDescription() {
switch (m.fieldMode) {
case 0: //field emitter
return `gain the effects of all <strong class='color-f'>fields</strong>`
case 1: //standing wave
return `<strong>+20</strong> max <strong class='color-f'>energy</strong> per <strong class='color-coupling'>coupling</strong>`
case 2: //perfect diamagnetism
return `<strong>+10°</strong> <strong>arc</strong> per <strong class='color-coupling'>coupling</strong>`
case 3: //negative mass
return `<strong>+25%</strong> <strong class='color-defense'>defense</strong> per <strong class='color-coupling'>coupling</strong>`
case 4: //assembler
return `generate <strong>4</strong> <strong class='color-f'>energy</strong> per second per <strong class='color-coupling'>coupling</strong>`
case 5: //plasma
return `<strong>+13%</strong> <strong class='color-d'>damage</strong> per <strong class='color-coupling'>coupling</strong>`
case 6: //time dilation
return `<strong>+20%</strong> <strong><em>fire rate</em></strong> per <strong class='color-coupling'>coupling</strong>` //<strong>movement</strong>, <strong>jumping</strong>, and
case 7: //cloaking
return `remove <strong>+10%</strong> mob <strong>durability</strong> per <strong class='color-coupling'>coupling</strong>`
case 8: //pilot wave
return `________ per <strong class='color-coupling'>coupling</strong>`
case 9: //wormhole
return `<strong>+5%</strong> <strong class='color-dup'>duplication</strong> per <strong class='color-coupling'>coupling</strong>`
}
},
setField(index) {
if (isNaN(index)) { //find index by name
let found = false
@@ -3240,13 +3265,13 @@ const m = {
{
name: "wormhole",
//<strong class='color-worm'>wormholes</strong> attract <strong class='color-block'>blocks</strong> and power ups<br>
description: "use <strong class='color-f'>energy</strong> to <strong>tunnel</strong> through a <strong class='color-worm'>wormhole</strong><br><strong>+4%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second", //<br>bullets may also traverse <strong class='color-worm'>wormholes</strong>
description: "use <strong class='color-f'>energy</strong> to <strong>tunnel</strong> through a <strong class='color-worm'>wormhole</strong><br><strong>+3%</strong> chance to <strong class='color-dup'>duplicate</strong> spawned <strong>power ups</strong><br>generate <strong>6</strong> <strong class='color-f'>energy</strong> per second", //<br>bullets may also traverse <strong class='color-worm'>wormholes</strong>
drain: 0,
effect: function() {
m.fieldMeterColor = "#bbf" //"#0c5"
m.eyeFillColor = m.fieldMeterColor
m.duplicateChance = 0.04
m.duplicateChance = 0.03
m.fieldRange = 0
powerUps.setDupChance(); //needed after adjusting duplication chance

View File

@@ -921,7 +921,7 @@ const powerUps = {
if (tech.isExtraBotOption) {
const botTech = [] //make an array of bot options
for (let i = 0, len = tech.tech.length; i < len; i++) {
if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i)
if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isRecentlyShown) botTech.push(i)
}
if (botTech.length > 0) { //pick random bot tech
const choose = botTech[Math.floor(Math.random() * botTech.length)];

View File

@@ -1577,8 +1577,8 @@ const spawn = {
hopper(x, y, radius = 30 + Math.ceil(Math.random() * 30)) {
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
let me = mob[mob.length - 1];
me.accelMag = 0.04;
me.g = 0.0017; //required if using this.gravity
me.accelMag = 0.05;
me.g = 0.0032; //required if using this.gravity
me.frictionAir = 0.01;
me.friction = 1
me.frictionStatic = 1
@@ -1598,7 +1598,7 @@ const spawn = {
const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass;
const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
this.force.x += forceMag * Math.cos(angle);
this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.07 + 0.06) * this.mass; //antigravity
this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.06 + 0.1) * this.mass; //antigravity
}
} else {
//randomly hob if not aware of player
@@ -1609,7 +1609,7 @@ const spawn = {
const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass * (0.1 + Math.random() * 0.3);
const angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI;
this.force.x += forceMag * Math.cos(angle);
this.force.y += forceMag * Math.sin(angle) - 0.05 * this.mass; //antigravity
this.force.y += forceMag * Math.sin(angle) - 0.07 * this.mass; //antigravity
}
}
};
@@ -4782,6 +4782,7 @@ const spawn = {
me.alpha = 1; //used in drawSneaker
// me.leaveBody = false;
me.canTouchPlayer = false; //used in drawSneaker
me.isBadTarget = true;
me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
me.showHealthBar = false;
me.memory = 240;
@@ -4801,6 +4802,7 @@ const spawn = {
this.healthBar();
if (!this.canTouchPlayer) {
this.canTouchPlayer = true;
this.isBadTarget = false;
this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can touch player
}
}
@@ -4816,6 +4818,7 @@ const spawn = {
ctx.fill();
} else if (this.canTouchPlayer) { //stealth
this.canTouchPlayer = false;
this.isBadTarget = true;
this.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
}
};
@@ -4830,6 +4833,7 @@ const spawn = {
me.stroke = "transparent"; //used for drawGhost
me.alpha = 1; //used in drawGhost
me.canTouchPlayer = false; //used in drawGhost
me.isBadTarget = true;
// me.leaveBody = false;
me.collisionFilter.mask = cat.bullet //| cat.body
me.showHealthBar = false;
@@ -4857,6 +4861,7 @@ const spawn = {
this.healthBar();
if (!this.canTouchPlayer) {
this.canTouchPlayer = true;
this.isBadTarget = false;
this.collisionFilter.mask = cat.player | cat.bullet
}
}
@@ -4873,6 +4878,7 @@ const spawn = {
ctx.fill();
} else if (this.canTouchPlayer) {
this.canTouchPlayer = false;
this.isBadTarget = true;
this.collisionFilter.mask = cat.bullet; //can't touch player or walls
}
};
@@ -5055,7 +5061,7 @@ const spawn = {
};
Matter.Body.setDensity(me, 0.00004); //normal is 0.001
me.timeLeft = 200;
me.g = 0.001; //required if using this.gravity
// me.g = 0.001; //required if using this.gravity
me.frictionAir = 0;
me.restitution = 0.8;
me.leaveBody = false;
@@ -5066,7 +5072,7 @@ const spawn = {
me.collisionFilter.category = cat.mobBullet;
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
me.do = function() {
this.gravity();
// this.gravity();
this.timeLimit();
};
},
@@ -5134,10 +5140,11 @@ const spawn = {
me.frictionStatic = 0;
me.friction = 0;
me.canTouchPlayer = false; //used in drawSneaker
me.isBadTarget = true;
me.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
me.memory = 60 //140;
me.fireFreq = 0.006 + Math.random() * 0.002;
me.memory = 30 //140;
me.fireFreq = 0.005 + Math.random() * 0.002 + 0.0005 * simulation.difficulty; //larger = fire more often
me.noseLength = 0;
me.fireAngle = 0;
me.accelMag = 0.0005 * simulation.accelScale;
@@ -5183,8 +5190,8 @@ const spawn = {
this.torque -= 0.000004 * this.inertia;
} else if (this.noseLength > 1.5 && dot > -0.2 && dot < 0.2) {
//fire
spawn.sniperBullet(this.vertices[1].x, this.vertices[1].y, 7 + Math.ceil(this.radius / 15), 4);
const v = 10 + 15 * simulation.accelScale;
spawn.sniperBullet(this.vertices[1].x, this.vertices[1].y, 7 + Math.ceil(this.radius / 15), 5);
const v = 10 + 8 * simulation.accelScale;
Matter.Body.setVelocity(mob[mob.length - 1], {
x: this.velocity.x + this.fireDir.x * v + Math.random(),
y: this.velocity.y + this.fireDir.y * v + Math.random()
@@ -5216,6 +5223,7 @@ const spawn = {
this.healthBar();
if (!this.canTouchPlayer) {
this.canTouchPlayer = true;
this.isBadTarget = false;
this.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob; //can touch player
}
}
@@ -5231,11 +5239,12 @@ const spawn = {
ctx.fill();
} else if (this.canTouchPlayer) {
this.canTouchPlayer = false;
this.isBadTarget = true
this.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob //can't touch player
}
};
},
sniperBullet(x, y, radius = 9, sides = 4) { //bullets
sniperBullet(x, y, radius = 9, sides = 5) { //bullets
mobs.spawn(x, y, sides, radius, "rgb(255,0,155)");
let me = mob[mob.length - 1];
me.stroke = "transparent";
@@ -5924,11 +5933,12 @@ const spawn = {
mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, color1); //"rgb(55,170,170)"
let me = mob[mob.length - 1];
me.isBoss = true;
me.accelMag = 0.0004 + 0.0002 * Math.sqrt(simulation.accelScale)
me.accelMag = 0.0001 + 0.0004 * Math.sqrt(simulation.accelScale)
// me.accelMag = 0.0004 + 0.0002 * Math.sqrt(simulation.accelScale)
me.memory = 250;
me.laserRange = 500;
Matter.Body.setDensity(me, 0.0022 + 0.00022 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.startingDamageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.startingDamageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.damageReduction = 0
me.isInvulnerable = true
@@ -5952,7 +5962,7 @@ const spawn = {
this.cycle++
if (this.seePlayer.recall && ((this.cycle % 10) === 0)) {
if (this.canFire) {
if (this.cycle > 100) {
if (this.cycle > 120) {
this.cycle = 0
this.canFire = false
// Matter.Body.setAngularVelocity(this, 0.1)
@@ -5963,7 +5973,7 @@ const spawn = {
}
spawn.seeker(this.vertices[this.closestVertex1].x, this.vertices[this.closestVertex1].y, 6)
Matter.Body.setDensity(mob[mob.length - 1], 0.000001); //normal is 0.001
const velocity = Vector.mult(Vector.normalise(Vector.sub(this.position, this.vertices[this.closestVertex1])), -13)
const velocity = Vector.mult(Vector.normalise(Vector.sub(this.vertices[this.closestVertex1], this.position)), 15)
Matter.Body.setVelocity(mob[mob.length - 1], {
x: this.velocity.x + velocity.x,
y: this.velocity.y + velocity.y
@@ -5975,7 +5985,7 @@ const spawn = {
// x: this.velocity.x + velocity2.x,
// y: this.velocity.y + velocity2.y
// });
} else if (this.cycle > 210) {
} else if (this.cycle > 200) {
this.cycle = 0
this.canFire = true
@@ -6011,6 +6021,8 @@ const spawn = {
mag -= 10
let previousTailID = 0
const damping = 1
const stiffness = 1
for (let i = 0; i < nodes; ++i) {
angle -= 0.15 + i * 0.008
mag -= (i < 2) ? -15 : 5
@@ -6021,7 +6033,7 @@ const spawn = {
mob[mob.length - 1].previousTailID = previousTailID
previousTailID = mob[mob.length - 1].id
}
this.constrain2AdjacentMobs(nodes, Math.random() * 0.06 + 0.01);
this.constrain2AdjacentMobs(nodes, stiffness, false, damping);
for (let i = mob.length - 1, len = i - nodes; i > len; i--) { //set alternating colors
if (i % 2) {
@@ -6034,40 +6046,45 @@ const spawn = {
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - nodes],
bodyB: mob[mob.length - 1 - nodes],
stiffness: 0.05
stiffness: stiffness,
damping: damping
});
Composite.add(engine.world, consBB[consBB.length - 1]);
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - nodes + 1],
bodyB: mob[mob.length - 1 - nodes],
stiffness: 0.05
stiffness: stiffness,
damping: damping
});
Composite.add(engine.world, consBB[consBB.length - 1]);
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - nodes + 2],
bodyB: mob[mob.length - 1 - nodes],
stiffness: 0.05
stiffness: stiffness,
damping: damping
});
Composite.add(engine.world, consBB[consBB.length - 1]);
// spawn.shield(me, x, y, 1);
},
dragonFlyBoss(x, y, radius = 42) { //snake boss with a laser head
const nodes = Math.min(8 + Math.ceil(0.5 * simulation.difficulty), 40)
let angle = Math.PI
let mag = 300
const color1 = "#00bfd9" //"#f27"
mobs.spawn(x + mag * Math.cos(angle), y + mag * Math.sin(angle), 8, radius, "#000"); //"rgb(55,170,170)"
let me = mob[mob.length - 1];
me.isBoss = true;
me.accelMag = 0.0009 + 0.0002 * Math.sqrt(simulation.accelScale)
me.memory = 250;
me.laserRange = 400;
Matter.Body.setDensity(me, 0.00165 + 0.00011 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.startingDamageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.damageReduction = 0
me.isInvulnerable = true
me.accelMag = 0.0001 + 0.0004 * Math.sqrt(simulation.accelScale)
me.memory = 250;
me.flapRate = 0.4
me.flapArc = 0.2 //don't go past 1.57 for normal flaps
me.wingLength = 150
me.ellipticity = 0.3
me.angleOff = 0.4
me.onDeath = function() {
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
for (let i = 0, len = mob.length; i < len; i++) {
@@ -6101,15 +6118,10 @@ const spawn = {
this.wing(a - Math.PI / 2 + this.angleOff + this.flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingLength, this.ellipticity)
this.wing(a + Math.PI / 2 - this.angleOff - this.flapArc * Math.sin(simulation.cycle * this.flapRate), this.wingLength, this.ellipticity)
};
me.flapRate = 0.4
me.flapArc = 0.2 //don't go past 1.57 for normal flaps
me.wingLength = 150
me.ellipticity = 0.3
me.angleOff = 0.4
//extra space to give head room
angle -= 0.1
mag -= 10
let previousTailID = 0
const nodes = Math.min(8 + Math.ceil(0.5 * simulation.difficulty), 40)
for (let i = 0; i < nodes; ++i) {
angle -= 0.15 + i * 0.008
mag -= (i < 2) ? -15 : 5
@@ -6119,7 +6131,9 @@ const spawn = {
mob[mob.length - 1].previousTailID = previousTailID
previousTailID = mob[mob.length - 1].id
}
this.constrain2AdjacentMobs(nodes, Math.random() * 0.06 + 0.01);
const damping = 1
const stiffness = 1
this.constrain2AdjacentMobs(nodes, stiffness, false, damping);
for (let i = mob.length - 1, len = i - nodes; i > len; i--) { //set alternating colors
mob[i].fill = `hsla(${160+40*Math.random()}, 100%, ${5 + 25*Math.random()*Math.random()}%, 0.9)`
}
@@ -6127,19 +6141,22 @@ const spawn = {
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - nodes],
bodyB: mob[mob.length - 1 - nodes],
stiffness: 0.05
stiffness: stiffness,
damping: damping
});
Composite.add(engine.world, consBB[consBB.length - 1]);
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - nodes + 1],
bodyB: mob[mob.length - 1 - nodes],
stiffness: 0.05
stiffness: stiffness,
damping: damping
});
Composite.add(engine.world, consBB[consBB.length - 1]);
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - nodes + 2],
bodyB: mob[mob.length - 1 - nodes],
stiffness: 0.05
stiffness: stiffness,
damping: damping
});
Composite.add(engine.world, consBB[consBB.length - 1]);
// spawn.shield(me, x, y, 1);
@@ -6147,15 +6164,15 @@ const spawn = {
snakeBody(x, y, radius = 10) {
mobs.spawn(x, y, 8, radius, "rgba(0,180,180,0.4)");
let me = mob[mob.length - 1];
me.collisionFilter.mask = cat.bullet | cat.player | cat.mob //| cat.body
me.damageReduction = 0.23
Matter.Body.setDensity(me, 0.005); //normal is 0.001
me.collisionFilter.mask = cat.bullet | cat.player //| cat.mob //| cat.body
me.damageReduction = 0.015
Matter.Body.setDensity(me, 0.0001); //normal is 0.001
// me.accelMag = 0.0007 * simulation.accelScale;
me.leaveBody = Math.random() < 0.33 ? true : false;
me.showHealthBar = false;
me.isDropPowerUp = false;
me.frictionAir = 0.015;
me.frictionAir = 0;
me.isSnakeTail = true;
me.stroke = "transparent"
me.onDeath = function() {
@@ -6476,13 +6493,14 @@ const spawn = {
}
}
},
constrain2AdjacentMobs(nodes, stiffness, loop = false) {
constrain2AdjacentMobs(nodes, stiffness, loop = false, damping = 0) {
//runs through every combination of last 'num' bodies and constrains them
for (let i = 0; i < nodes - 1; ++i) {
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - i - 1],
bodyB: mob[mob.length - i - 2],
stiffness: stiffness
stiffness: stiffness,
damping: damping
});
Composite.add(engine.world, consBB[consBB.length - 1]);
}
@@ -6491,7 +6509,8 @@ const spawn = {
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - i - 1],
bodyB: mob[mob.length - i - 3],
stiffness: stiffness
stiffness: stiffness,
damping: damping
});
Composite.add(engine.world, consBB[consBB.length - 1]);
}
@@ -6501,19 +6520,22 @@ const spawn = {
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - 1],
bodyB: mob[mob.length - nodes],
stiffness: stiffness
stiffness: stiffness,
damping: damping
});
Composite.add(engine.world, consBB[consBB.length - 1]);
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - 2],
bodyB: mob[mob.length - nodes],
stiffness: stiffness
stiffness: stiffness,
damping: damping
});
Composite.add(engine.world, consBB[consBB.length - 1]);
consBB[consBB.length] = Constraint.create({
bodyA: mob[mob.length - 1],
bodyB: mob[mob.length - nodes + 1],
stiffness: stiffness
stiffness: stiffness,
damping: damping
});
Composite.add(engine.world, consBB[consBB.length - 1]);
}

View File

@@ -306,7 +306,41 @@ const tech = {
}
}
},
tech: [{
tech: [
// {
// name: "field coupling",
// descriptionFunction() {
// return `<strong>+1</strong> <strong class='color-f'>field</strong> <strong class='color-coupling'>coupling</strong> (${m.fieldUpgrades[m.fieldMode].name})<br>${ m.couplingDescription()}`
// },
// // isFieldTech: true,
// maxCount: 9,
// count: 0,
// frequency: 2,
// frequencyDefault: 2,
// allowed() {
// return (build.isExperimentSelection || powerUps.research.count > 1)
// },
// requires: "",
// // researchUsed: 0,
// // couplingToResearch: 0.1,
// effect() {
// m.coupling++
// // while (powerUps.research.count > 0) {
// // powerUps.research.changeRerolls(-1)
// // this.researchUsed++
// // m.coupling += this.couplingToResearch
// // }
// },
// remove() {
// m.coupling = 0
// // if (this.count) {
// // m.coupling -= this.researchUsed * this.couplingToResearch
// // powerUps.research.changeRerolls(this.researchUsed)
// // this.researchUsed = 0
// // }
// }
// },
{
name: "ordnance",
description: "</strong>double</strong> the <strong class='flicker'>frequency</strong> of finding <strong class='color-g'>gun</strong><strong class='color-m'>tech</strong><br>spawn a <strong class='color-g'>gun</strong>",
maxCount: 1,
@@ -644,7 +678,7 @@ const tech = {
allowed() {
return !tech.isEnergyHealth //(tech.crouchAmmoCount || tech.isCrouchRegen) &&
},
requires: "not mass-energy", //inductive coupling, desublimated ammunition,
requires: "not mass-energy",
effect() {
tech.isTurret = true
},
@@ -2428,7 +2462,7 @@ const tech = {
}
},
{
name: "inductive coupling",
name: "inductive charging",
description: "if <strong>crouched</strong> <strong>+600%</strong> passive <strong class='color-f'>energy</strong> generation<br>if not <strong>crouched</strong> <strong class='color-f'>energy</strong> generation is disabled",
maxCount: 1,
count: 0,
@@ -2511,7 +2545,7 @@ const tech = {
allowed() {
return !tech.isCrouchRegen
},
requires: "not inductive coupling",
requires: "not inductive charging",
effect() {
tech.isDamageAfterKillNoRegen = true;
m.regenEnergy = function() {
@@ -5788,21 +5822,11 @@ const tech = {
requires: "foam",
effect() {
tech.isFoamPressure = true;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "foam") {
b.guns[i].chooseFireMethod()
break
}
}
b.guns[8].chooseFireMethod()
},
remove() {
tech.isFoamPressure = false;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "foam") {
b.guns[i].chooseFireMethod()
break
}
}
b.guns[8].chooseFireMethod()
}
},
{
@@ -6436,7 +6460,7 @@ const tech = {
//**************************************************
//************************************************** field
//************************************************** tech
//**************************************************
//**************************************************
{
name: "zero point energy",
description: `use ${powerUps.orb.research(2)}<br><strong>+100</strong> maximum <strong class='color-f'>energy</strong>`,
@@ -7032,7 +7056,7 @@ const tech = {
{
name: "plasma-bot",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Robot' class="link">plasma-bot</a>`,
description: "remove your <strong>field</strong> to build a <strong class='color-bot'>bot</strong><br>that uses <strong class='color-f'>energy</strong> to emit <strong class='color-plasma'>plasma</strong>",
description: "remove your <strong class='color-f'>field</strong> to build a <strong class='color-bot'>bot</strong><br>that uses <strong class='color-f'>energy</strong> to emit <strong class='color-plasma'>plasma</strong>",
isFieldTech: true,
maxCount: 1,
count: 0,