hopMother
new mob type: hopMother - hoppers that drop eggs that explode on contact and after several seconds they hatch into baby hoppers regular hopper mobs have more life and more damage a few bug fixes
This commit is contained in:
@@ -4925,7 +4925,7 @@ const b = {
|
|||||||
return tech.dynamoBotCount + tech.foamBotCount + tech.soundBotCount + tech.nailBotCount + tech.laserBotCount + tech.boomBotCount + tech.orbitBotCount + tech.plasmaBotCount + tech.missileBotCount
|
return tech.dynamoBotCount + tech.foamBotCount + tech.soundBotCount + tech.nailBotCount + tech.laserBotCount + tech.boomBotCount + tech.orbitBotCount + tech.plasmaBotCount + tech.missileBotCount
|
||||||
},
|
},
|
||||||
hasBotUpgrade() {
|
hasBotUpgrade() {
|
||||||
return tech.isNailBotUpgrade + tech.isFoamBotUpgrade + tech.isBoomBotUpgrade + tech.isLaserBotUpgrade + tech.isOrbitBotUpgrade + tech.isDynamoBotUpgrade
|
return tech.isNailBotUpgrade + tech.isFoamBotUpgrade + tech.isBoomBotUpgrade + tech.isLaserBotUpgrade + tech.isOrbitBotUpgrade + tech.isDynamoBotUpgrade + tech.isSoundBotUpgrade
|
||||||
},
|
},
|
||||||
convertBotsTo(type) { //type can be a string like "dynamoBotCount"
|
convertBotsTo(type) { //type can be a string like "dynamoBotCount"
|
||||||
const totalPermanentBots = b.totalBots()
|
const totalPermanentBots = b.totalBots()
|
||||||
|
|||||||
@@ -1372,7 +1372,7 @@ window.addEventListener("keydown", function (event) {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (b.inventory.length > 1 && !simulation.testing) {
|
if (b.inventory.length > 1 && !simulation.testing && !tech.isGunCycle) {
|
||||||
switch (event.code) {
|
switch (event.code) {
|
||||||
case "Digit1":
|
case "Digit1":
|
||||||
simulation.switchToGunInInventory(0);
|
simulation.switchToGunInInventory(0);
|
||||||
|
|||||||
472
js/level.js
472
js/level.js
@@ -10,7 +10,7 @@ const level = {
|
|||||||
// playableLevels: ["pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion"],
|
// playableLevels: ["pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion", "pavilion"],
|
||||||
//see level.populateLevels: (intro, ... , reservoir or factory, reactor, ... , subway, final) added later
|
//see level.populateLevels: (intro, ... , reservoir or factory, reactor, ... , subway, final) added later
|
||||||
playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock"],
|
playableLevels: ["labs", "rooftops", "skyscrapers", "warehouse", "highrise", "office", "aerie", "satellite", "sewers", "testChamber", "pavilion", "lock"],
|
||||||
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", "dojo", "tlinat", "ruins", "ace", "crimsonTowers"],
|
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"],
|
||||||
trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon", "diamagnetism"],
|
trainingLevels: ["walk", "crouch", "jump", "hold", "throw", "throwAt", "deflect", "heal", "fire", "nailGun", "shotGun", "superBall", "matterWave", "missile", "stack", "mine", "grenades", "harpoon", "diamagnetism"],
|
||||||
levels: [],
|
levels: [],
|
||||||
start() {
|
start() {
|
||||||
@@ -27,7 +27,7 @@ const level = {
|
|||||||
// m.immuneCycle = Infinity //you can't take damage
|
// m.immuneCycle = Infinity //you can't take damage
|
||||||
// tech.tech[297].frequency = 100
|
// tech.tech[297].frequency = 100
|
||||||
// m.couplingChange(10)
|
// m.couplingChange(10)
|
||||||
// m.setField("molecular assembler") //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
|
// 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
|
||||||
// m.energy = 0
|
// m.energy = 0
|
||||||
// simulation.molecularMode = 2
|
// simulation.molecularMode = 2
|
||||||
// m.damage(0.1);
|
// m.damage(0.1);
|
||||||
@@ -48,10 +48,10 @@ const level = {
|
|||||||
// for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech");
|
// for (let i = 0; i < 3; i++) powerUps.directSpawn(450, -50, "tech");
|
||||||
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research");
|
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "research");
|
||||||
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling");
|
// for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling");
|
||||||
// level.testing();
|
|
||||||
|
|
||||||
// for (let i = 0; i < 10; ++i) spawn.sniper(1900, -500)
|
// level.testing();
|
||||||
// for (let i = 0; i < 1; ++i) spawn.slasher2(1900, -500)
|
// for (let i = 0; i < 4; ++i) spawn.hopMother(1900, -500)
|
||||||
|
// for (let i = 0; i < 0; ++i) spawn.hopper(1900, -500)
|
||||||
// for (let i = 0; i < 1; ++i) spawn.shooterBoss(1900, -2500)
|
// for (let i = 0; i < 1; ++i) spawn.shooterBoss(1900, -2500)
|
||||||
// spawn.suckerBoss(1900, -500, 25)
|
// spawn.suckerBoss(1900, -500, 25)
|
||||||
// spawn.slasher2(2000, -1150)
|
// spawn.slasher2(2000, -1150)
|
||||||
@@ -1915,7 +1915,7 @@ const level = {
|
|||||||
const mover = level.mover(2800, -300, 1000, 25); //x,y,width.height,VxGoal,force
|
const mover = level.mover(2800, -300, 1000, 25); //x,y,width.height,VxGoal,force
|
||||||
|
|
||||||
const train = level.transport(2900, -500, 500, 25, 8); //x,y,width.height,VxGoal,force
|
const train = level.transport(2900, -500, 500, 25, 8); //x,y,width.height,VxGoal,force
|
||||||
spawn.bodyRect(1900, -550, 50, 50);
|
// spawn.bodyRect(1900, -550, 50, 50);
|
||||||
const button = level.button(2535, -200)
|
const button = level.button(2535, -200)
|
||||||
// spawn.bodyRect(250, -450, 50, 50); //block on button
|
// spawn.bodyRect(250, -450, 50, 50); //block on button
|
||||||
|
|
||||||
@@ -5026,15 +5026,15 @@ const level = {
|
|||||||
powerUps.directSpawn(x + 50, y - 1525, "ammo");
|
powerUps.directSpawn(x + 50, y - 1525, "ammo");
|
||||||
powerUps.directSpawn(x + 1950, y - 1525, "ammo");
|
powerUps.directSpawn(x + 1950, y - 1525, "ammo");
|
||||||
powerUps.directSpawn(x + 1900, y - 1525, "ammo");
|
powerUps.directSpawn(x + 1900, y - 1525, "ammo");
|
||||||
spawn.hopMomBoss(x + 800, y + -2200)
|
spawn.hopMotherBoss(x + 800, y + -2200)
|
||||||
for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 150 + 750 * Math.random(), y + -1600)
|
for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 150 + 750 * Math.random(), y + -1600)
|
||||||
for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 1100 + 750 * Math.random(), y + -1600)
|
for (let i = 0; i < 6; ++i) spawn.hopBullet(x + 1100 + 750 * Math.random(), y + -1600)
|
||||||
spawn.hopper(x + 1550, y + -775);
|
spawn.hopper(x + 1550, y + -775);
|
||||||
spawn.hopper(x + 500, y + -775);
|
spawn.hopper(x + 500, y + -775);
|
||||||
spawn.hopper(x + 1400, y + -775);
|
spawn.hopMother(x + 1400, y + -775);
|
||||||
spawn.hopper(x + 550, y + -775);
|
spawn.hopMother(x + 550, y + -775);
|
||||||
spawn.hopper(x + 525, y + -1475);
|
spawn.hopMother(x + 525, y + -1475);
|
||||||
spawn.hopper(x + 1550, y + -1500);
|
spawn.hopMother(x + 1550, y + -1500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25602,456 +25602,6 @@ const level = {
|
|||||||
};
|
};
|
||||||
powerUps.addResearchToLevel(); //needs to run after mobs are spawned
|
powerUps.addResearchToLevel(); //needs to run after mobs are spawned
|
||||||
},
|
},
|
||||||
dojo() { // By
|
|
||||||
simulation.makeTextLog(`<strong>underpass</strong> by <span class='color-var'>weird_pusheen</span>`);
|
|
||||||
|
|
||||||
const vanishes = [];
|
|
||||||
const smoofes = [];
|
|
||||||
const leftRotor = level.rotor(-550, 900, 950, 25);
|
|
||||||
leftRotor.frictionAir = 0.01;
|
|
||||||
var leftSchwoof = level.boost(-20, -60, -2000);
|
|
||||||
var rightSchwoof = level.button(2550, -50);
|
|
||||||
var rightSchwoofState = false;
|
|
||||||
var rightSchwoofLive = true;
|
|
||||||
spawn.mapRect(2513, -39, 200, 100);
|
|
||||||
var pathPoints = [
|
|
||||||
[0, 0], // Index 0 is owned by M and is set to M's position during play
|
|
||||||
// this means that occasionally the boss will bonk M on the way to somewhere else, which gives it a chance to hurt M and gives the player a chance to hurt it
|
|
||||||
[250, -750], /* Left bases */
|
|
||||||
[250, -2500],
|
|
||||||
[350, -1500], // Left doorway
|
|
||||||
[1150, -1500], // Home base
|
|
||||||
[1150, -2750], // Upper base
|
|
||||||
[1950, -1500], // Right doorway
|
|
||||||
[2050, -750], /* Right bases */
|
|
||||||
[2050, -2500],
|
|
||||||
[-150, -250], // Left porthole
|
|
||||||
];
|
|
||||||
function isntIn(point, array) {
|
|
||||||
for (var x = 0; x < array.length; x++) {
|
|
||||||
if (point[0] == array[x][0] && point[1] == array[x][1]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
function isObstructed(v1, v2) {
|
|
||||||
var ret = Matter.Query.ray(map,
|
|
||||||
{
|
|
||||||
x: v1[0],
|
|
||||||
y: v1[1],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
x: v2[0],
|
|
||||||
y: v2[1]
|
|
||||||
}).length != 0;
|
|
||||||
return ret; // Kinda-ish stolen from mob.js
|
|
||||||
}
|
|
||||||
function pythag(p1, p2) {
|
|
||||||
var dx = p1[0] - p2[0];
|
|
||||||
var dy = p1[1] - p2[1];
|
|
||||||
return Math.sqrt(dx * dx + dy * dy);
|
|
||||||
}
|
|
||||||
var path = undefined; // This is a stupid way to go about pathfinding code. I might even clean it up!
|
|
||||||
function pathFind(goalPoint, startPoint, curPath = []) {
|
|
||||||
var myPoint = startPoint;
|
|
||||||
if (curPath.length) {
|
|
||||||
myPoint = curPath[curPath.length - 1];
|
|
||||||
}
|
|
||||||
if (path && (curPath.length >= path.length)) { // If we've already found a shorter or equal path, no reason to continue and waste CPU time
|
|
||||||
return; // Minimizes for HOP COUNT, not PATH LENGTH - path length was buggy
|
|
||||||
}
|
|
||||||
if (!isObstructed(myPoint, goalPoint)) { // If the line to the goal point ain't blocked by a map object, we've arrived!
|
|
||||||
path = [...curPath];
|
|
||||||
path.push(goalPoint);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pathPoints.forEach(testPoint => {
|
|
||||||
if (isntIn(testPoint, curPath)) { // If it's reusing points, there's clearly something wrong
|
|
||||||
if (!isObstructed(myPoint, testPoint)) { // If the line to the test point ain't blocked by a map object
|
|
||||||
var thing = [...curPath];
|
|
||||||
thing.push(testPoint);
|
|
||||||
pathFind(goalPoint, startPoint, thing); // Branch to a valid test point
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
level.setPosToSpawn(1200, 500);
|
|
||||||
level.exit.x = 51500;
|
|
||||||
level.exit.y = -1875;
|
|
||||||
spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20);
|
|
||||||
level.defaultZoom = 1500;
|
|
||||||
simulation.zoomTransition(level.defaultZoom)
|
|
||||||
document.body.style.backgroundColor = "#d8dadf";
|
|
||||||
|
|
||||||
spawn.mapRect(-500, 0, 3300, 300); // Floor
|
|
||||||
spawn.mapRect(-100, -3000, 2500, 100); // Ceiling
|
|
||||||
spawn.mapRect(-200, -3000, 100, 2600); // Left wall
|
|
||||||
spawn.mapRect(2400, -3000, 100, 3000); // Right wall
|
|
||||||
|
|
||||||
spawn.mapRect(500, -1000, 100, 500); /* obstruction blocks */
|
|
||||||
smoofes.push(map[map.length - 1]);
|
|
||||||
spawn.mapRect(500, -2500, 100, 500);
|
|
||||||
smoofes.push(map[map.length - 1]);
|
|
||||||
spawn.mapRect(1700, -1000, 100, 500);
|
|
||||||
smoofes.push(map[map.length - 1]);
|
|
||||||
spawn.mapRect(1700, -2500, 100, 500);
|
|
||||||
smoofes.push(map[map.length - 1]);
|
|
||||||
|
|
||||||
spawn.mapRect(-1000, 550, 200, 50); // Left chonky stepppp low
|
|
||||||
spawn.mapRect(-800, 300, 200, 50); // Left chonky stepppp high
|
|
||||||
spawn.mapVertex(-1000, 1200, "0 0 100 0 700 500 700 700 0 700"); // Left chonky
|
|
||||||
spawn.mapRect(3100, 550, 200, 50); // Right chonky stepppp low
|
|
||||||
spawn.mapRect(2900, 300, 200, 50); // Right chonky stepppp high
|
|
||||||
spawn.mapVertex(3300, 1200, "0 0 -100 0 -700 500 -700 700 0 700"); // Right chonky
|
|
||||||
const leftElevator = level.elevator(-1400 - 300, 1450, 300, 100, 500);
|
|
||||||
const rightElevator = level.elevator(-1400 + 5100, 1450, 300, 100, 500);
|
|
||||||
|
|
||||||
spawn.mapRect(-150, -1700, 200, 50);
|
|
||||||
spawn.mapRect(400, -2050, 200, 50);
|
|
||||||
spawn.mapRect(1600, -1000, 200, 50);
|
|
||||||
|
|
||||||
spawn.randomMob(1200, 700);
|
|
||||||
spawn.randomMob(600, 1000);
|
|
||||||
spawn.randomMob(1800, 1000);
|
|
||||||
spawn.randomMob(3200, 400);
|
|
||||||
spawn.randomMob(3000, 200);
|
|
||||||
spawn.randomMob(-900, 400);
|
|
||||||
spawn.randomMob(-700, 200);
|
|
||||||
spawn.randomMob(1200, 1000);
|
|
||||||
for (var i = 0; i < 4; i++) {
|
|
||||||
spawn.randomSmallMob(Math.random() * 600 - 600, Math.random() * 3000 - 400);
|
|
||||||
}
|
|
||||||
spawn.grenadier(-300, -1000);
|
|
||||||
spawn.grenadier(2600, -1000);
|
|
||||||
|
|
||||||
spawn.mapRect(-1400, 1450, 5100, 100); // The True Floor
|
|
||||||
|
|
||||||
const slime = level.hazard(-1250, 1400, 4800, 50);
|
|
||||||
slime.maxHeight = 600;
|
|
||||||
simulation.draw.body = function () {
|
|
||||||
ctx.beginPath();
|
|
||||||
for (let i = 0, len = body.length; i < len; ++i) {
|
|
||||||
if (!body[i].hidden) {
|
|
||||||
let vertices = body[i].vertices;
|
|
||||||
ctx.moveTo(vertices[0].x, vertices[0].y);
|
|
||||||
for (let j = 1; j < vertices.length; j++) {
|
|
||||||
ctx.lineTo(vertices[j].x, vertices[j].y);
|
|
||||||
}
|
|
||||||
ctx.lineTo(vertices[0].x, vertices[0].y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.lineWidth = 2;
|
|
||||||
ctx.fillStyle = color.block;
|
|
||||||
ctx.fill();
|
|
||||||
ctx.strokeStyle = color.blockS;
|
|
||||||
ctx.stroke();
|
|
||||||
} // Override the old draw code to allow intelligent hiding of blocks - preferably this becomes official code because it's just a single added if statement and makes a lot of things cleaner and more intelligent
|
|
||||||
|
|
||||||
const vanish = function (x, y, width, height) { // normal vanishes don't work well on my map for some reason, so I rewrote
|
|
||||||
x += width / 2;
|
|
||||||
y += height / 2;
|
|
||||||
const getVertices = function (bX, bY, bW, bH) { return [{ x: bX, y: bY, index: 0, isInternal: false }, { x: bX + bW, y: bY, index: 1, isInternal: false }, { x: bX + bW, y: bY + bH, index: 4, isInternal: false }, { x: bX, y: bY + bH, index: 3, isInternal: false }] };
|
|
||||||
const cMask = cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet;
|
|
||||||
const vertices = getVertices(x, y, width, height);
|
|
||||||
const block = body[body.length] = Bodies.fromVertices(x, y, vertices, {
|
|
||||||
collisionFilter: {
|
|
||||||
category: cat.map,
|
|
||||||
mask: cMask
|
|
||||||
},
|
|
||||||
isNoSetCollision: true,
|
|
||||||
inertia: Infinity, //prevents rotation
|
|
||||||
isNotHoldable: true,
|
|
||||||
isNonStick: true, //this keep sporangium from sticking
|
|
||||||
isTouched: false,
|
|
||||||
cWidth: width,
|
|
||||||
hiddenCycle: 0,
|
|
||||||
isStatic: true,
|
|
||||||
query() {
|
|
||||||
if (this.cWidth <= 0) {
|
|
||||||
if (this.cWidth > -100) {
|
|
||||||
this.cWidth = -100;
|
|
||||||
Matter.Body.setVertices(this, vertices);
|
|
||||||
}
|
|
||||||
this.isTouched = false;
|
|
||||||
this.collisionFilter.mask = undefined;
|
|
||||||
this.hidden = true;
|
|
||||||
this.hiddenCycle++;
|
|
||||||
if (this.hiddenCycle > 100) {
|
|
||||||
if (Matter.Query.collides(this, [player]).length) {
|
|
||||||
this.hiddenCycle = 50;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.hiddenCycle = 0;
|
|
||||||
this.cWidth = width;
|
|
||||||
this.collisionFilter.mask = cMask;
|
|
||||||
this.hidden = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (this.isTouched) {
|
|
||||||
Matter.Body.setVertices(this, getVertices(x, y, this.cWidth, height * (this.cWidth / width)));
|
|
||||||
this.cWidth -= 3;
|
|
||||||
}
|
|
||||||
else if (Matter.Query.collides(this, [player]).length) { // Elseif short circuit avoids expensive collision detection
|
|
||||||
this.isTouched = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return block;
|
|
||||||
};
|
|
||||||
|
|
||||||
vanishes.push(vanish(800, 800, 800, 50));
|
|
||||||
vanishes.push(vanish(400, 1100, 400, 50));
|
|
||||||
vanishes.push(vanish(1600, 1100, 400, 50));
|
|
||||||
spawn.bodyRect(1700, 812, 300, 25, 1, {
|
|
||||||
collisionFilter: {
|
|
||||||
category: cat.body,
|
|
||||||
mask: cat.player | cat.body | cat.bullet | cat.powerUp | cat.mob | cat.mobBullet | cat.map
|
|
||||||
},
|
|
||||||
isNoSetCollision: true,
|
|
||||||
isNotHoldable: true,
|
|
||||||
isNonStick: true, //this keep sporangium from sticking
|
|
||||||
restitution: 1,
|
|
||||||
friction: 0,
|
|
||||||
frictionAir: 0,
|
|
||||||
frictionStatic: 0,
|
|
||||||
query() {
|
|
||||||
Matter.Body.setAngularVelocity(this, 0);
|
|
||||||
Matter.Body.applyForce(this, this.position, {
|
|
||||||
x: 0,
|
|
||||||
y: -(this.position.y - 812) * 0.002
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const zigzag = body[body.length - 1];
|
|
||||||
Matter.Body.applyForce(zigzag, zigzag.position, {
|
|
||||||
x: 0.1,
|
|
||||||
y: 0
|
|
||||||
});
|
|
||||||
var buttonWasDown = false;
|
|
||||||
level.customTopLayer = () => {
|
|
||||||
|
|
||||||
}
|
|
||||||
level.custom = () => {
|
|
||||||
rightSchwoof.isUp = false;
|
|
||||||
level.exit.drawAndCheck();
|
|
||||||
leftSchwoof.query();
|
|
||||||
level.enter.draw();
|
|
||||||
pathPoints[0][0] = m.pos.x;
|
|
||||||
pathPoints[0][1] = m.pos.y;
|
|
||||||
leftElevator.move();
|
|
||||||
rightElevator.move();
|
|
||||||
slime.query();
|
|
||||||
zigzag.query();
|
|
||||||
slime.levelRise(0.2);
|
|
||||||
for (var i = 0; i < vanishes.length; i++) {
|
|
||||||
vanishes[i].query();
|
|
||||||
}
|
|
||||||
if (!rightSchwoofState) {
|
|
||||||
var math = m.pos.y < leftRotor.position.y;
|
|
||||||
Matter.Body.setAngularVelocity(leftRotor, (math ? 1 : -1) * Math.PI / 45);
|
|
||||||
}
|
|
||||||
if (rightSchwoofLive) {
|
|
||||||
rightSchwoof.query();
|
|
||||||
rightSchwoof.draw();
|
|
||||||
if (rightSchwoofState) {
|
|
||||||
ctx.fillStyle = "lightgreen";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ctx.fillStyle = "red";
|
|
||||||
}
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(2615, -220, 40, 0, Math.PI * 2);
|
|
||||||
ctx.fill();
|
|
||||||
}
|
|
||||||
if (rightSchwoof.isUp) {
|
|
||||||
buttonWasDown = true;
|
|
||||||
}
|
|
||||||
else if (buttonWasDown) {
|
|
||||||
buttonWasDown = false;
|
|
||||||
rightSchwoofState = !rightSchwoofState;
|
|
||||||
}
|
|
||||||
if (Matter.Query.collides(player, smoofes).length) {
|
|
||||||
Matter.Body.applyForce(player, player.position, {
|
|
||||||
x: 0,
|
|
||||||
y: -0.015
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mobs.spawn(500, -500, 10, 100, "yellow"); /* TacticalBoss
|
|
||||||
Modes:
|
|
||||||
Spawn:
|
|
||||||
Pathfinds to a point above M and starts dropping mobs. Learns which mobs to drop to cause the most damage, of course.
|
|
||||||
Occasionally strikes at M.
|
|
||||||
Hide:
|
|
||||||
Pathfinds to the point furthest from M
|
|
||||||
Strike:
|
|
||||||
Pathfind really, really fast to M
|
|
||||||
Recharge:
|
|
||||||
Stop moving for a bit to "recharge" (this is so the player has a chance to hit it)
|
|
||||||
|
|
||||||
It must always Hide or Recharge after Spawning or Striking. Which one it does is based on some factor I'll figure out.
|
|
||||||
Pathfinding is a hypersimplified algorithm with hard-coded "points" that it can travel between. M is one of these.
|
|
||||||
*/
|
|
||||||
var boss = mob[mob.length - 1];
|
|
||||||
boss.isBoss = true;
|
|
||||||
boss.damageReduction = 0.2 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
|
|
||||||
boss.onDeath = function () {
|
|
||||||
powerUps.spawnBossPowerUp(this.position.x, this.position.y);
|
|
||||||
level.exit.x = 2560;
|
|
||||||
level.exit.y = -90;
|
|
||||||
rightSchwoofLive = false;
|
|
||||||
};
|
|
||||||
var spawnables = {};
|
|
||||||
["hopper", "stabber", "springer", "striker", "sneaker", "grower"].forEach((m) => { /* Used to be spawn.fullPickList, but some of those mobs don't do collision-only damage and would thus never be properly selected for */
|
|
||||||
if (spawn[m]) {
|
|
||||||
spawnables[m] = {
|
|
||||||
fun: spawn[m],
|
|
||||||
name: m,
|
|
||||||
weight: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
boss.stabCycle = 0;
|
|
||||||
boss.spawnCycle = 0;
|
|
||||||
function spawny() {
|
|
||||||
var totalWeight = 0;
|
|
||||||
Object.keys(spawnables).forEach(key => {
|
|
||||||
totalWeight += spawnables[key].weight;
|
|
||||||
});
|
|
||||||
var cursorWeight = 0;
|
|
||||||
var choice = Math.random();
|
|
||||||
var mC = undefined;
|
|
||||||
Object.values(spawnables).forEach((thing) => {
|
|
||||||
var lower = cursorWeight / totalWeight;
|
|
||||||
cursorWeight += thing.weight;
|
|
||||||
var upper = cursorWeight / totalWeight;
|
|
||||||
if ((choice > lower && choice <= upper) || !mC) {
|
|
||||||
mC = thing;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mC.fun(boss.position.x, boss.position.y);
|
|
||||||
var sp = mob[mob.length - 1];
|
|
||||||
sp.typeName = mC.name;
|
|
||||||
sp.onHit = () => {
|
|
||||||
spawnables[sp.typeName].weight += 1;
|
|
||||||
};
|
|
||||||
var oldFun = sp.onDeath;
|
|
||||||
sp.onDeath = () => { /* Mobs that die are worth less */
|
|
||||||
oldFun.call(sp);
|
|
||||||
spawnables[sp.typeName].weight -= 0.3; /* But not too much less */
|
|
||||||
};
|
|
||||||
}
|
|
||||||
boss.spawnDelay = 40;
|
|
||||||
boss.mode = "hide";
|
|
||||||
boss.modeSwitch = -1; // Randomize mode immediately
|
|
||||||
boss.damageReduction = 0.1;
|
|
||||||
var oldOnHit = boss.onHit;
|
|
||||||
boss.onHit = () => {
|
|
||||||
boss.modeSwitch = -1; // After striking the player, always switch modes
|
|
||||||
oldOnHit.call(boss);
|
|
||||||
};
|
|
||||||
boss.do = () => {
|
|
||||||
path = undefined;
|
|
||||||
var pfGoal = [0, 0];
|
|
||||||
boss.modeSwitch--;
|
|
||||||
if (boss.modeSwitch < 0) {
|
|
||||||
if (!boss.isShielded) {
|
|
||||||
spawn.shield(boss, boss.position.x, boss.position.y, 0.75); // Every time the mode switches, have a 75% chance to gain a new shield
|
|
||||||
}
|
|
||||||
if (boss.mode == "hide" || boss.mode == "recharge") {
|
|
||||||
if (Math.random() > 0.5) {
|
|
||||||
boss.mode = "spawn";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
boss.mode = "strike";
|
|
||||||
}
|
|
||||||
boss.modeSwitch = 600;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (boss.mode == "strike") {
|
|
||||||
boss.mode = "hide"; // Always hides after striking
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (Math.random() > 0.5) {
|
|
||||||
boss.mode = "hide";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
boss.mode = "recharge"; // same when it goes into recharge mode
|
|
||||||
spawn.shield(boss, boss.position.x, boss.position.y, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boss.modeSwitch = 200;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (boss.mode == "hide") { /* Find the furthest point from M and get to it */
|
|
||||||
var longest = 0;
|
|
||||||
pathPoints.forEach(item => {
|
|
||||||
if (item[0] == 1150) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var iL = pythag(item, [m.pos.x, m.pos.y]);
|
|
||||||
if (iL > longest) {
|
|
||||||
longest = iL;
|
|
||||||
pfGoal = item;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (boss.mode == "strike") {
|
|
||||||
pfGoal = pathPoints[0]; // Target M
|
|
||||||
}
|
|
||||||
else if (boss.mode == "spawn") {
|
|
||||||
pfGoal = pathPoints[4]; // Go to Home Base to spawn
|
|
||||||
}
|
|
||||||
if (boss.mode != "recharge") {
|
|
||||||
if (m.pos.x > 2350 || m.pos.x < -150 || m.pos.y > 50) {
|
|
||||||
boss.mode = "hide";
|
|
||||||
}
|
|
||||||
pathFind(pfGoal, [boss.position.x, boss.position.y]);
|
|
||||||
if (!path) {
|
|
||||||
return; // If it couldn't pathfind, just drift
|
|
||||||
}
|
|
||||||
var goalX = path[0][0];
|
|
||||||
var goalY = path[0][1];
|
|
||||||
|
|
||||||
var dX = goalX - boss.position.x;
|
|
||||||
var dY = goalY - boss.position.y;
|
|
||||||
var hyp = Math.sqrt(dX * dX + dY * dY);
|
|
||||||
Matter.Body.applyForce(boss, {
|
|
||||||
x: goalX,
|
|
||||||
y: goalY
|
|
||||||
}, {
|
|
||||||
x: dX / hyp * 0.04 * (boss.mode == "strike" ? 2 : 1),
|
|
||||||
y: dY / hyp * 0.04 * (boss.mode == "strike" ? 2 : 1)// - 0.005
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (boss.mode == "spawn") {
|
|
||||||
boss.stabCycle++;
|
|
||||||
if (boss.stabCycle > 25) {
|
|
||||||
if (Math.abs(dX) < 200 && dY > 0) {
|
|
||||||
Matter.Body.applyForce(boss, {
|
|
||||||
x: player.position.x,
|
|
||||||
y: player.position.y
|
|
||||||
}, {
|
|
||||||
x: 0,
|
|
||||||
y: 5
|
|
||||||
});
|
|
||||||
}
|
|
||||||
boss.stabCycle = 0;
|
|
||||||
}
|
|
||||||
boss.spawnCycle++;
|
|
||||||
if (boss.spawnCycle > boss.spawnDelay) {
|
|
||||||
spawny();
|
|
||||||
boss.spawnDelay += 4;
|
|
||||||
boss.spawnCycle = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
boss.showHealthBar = true;
|
|
||||||
powerUps.addResearchToLevel() //needs to run after mobs are spawned
|
|
||||||
},
|
|
||||||
tlinat() { // _Destined_ formerly Richard0820#2652
|
tlinat() { // _Destined_ formerly Richard0820#2652
|
||||||
simulation.makeTextLog(`<strong>tlinat</strong> by <span class='color-var'>Richard0820</span>`);
|
simulation.makeTextLog(`<strong>tlinat</strong> by <span class='color-var'>Richard0820</span>`);
|
||||||
simulation.fallHeight = 1 / 0, level.setPosToSpawn(0, -1e3), level.exit.x = 5100, level.exit.y = 3770, spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20), spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20), level.defaultZoom = 3000, simulation.zoomTransition(level.defaultZoom), document.body.style.backgroundColor = "#d8dadf";
|
simulation.fallHeight = 1 / 0, level.setPosToSpawn(0, -1e3), level.exit.x = 5100, level.exit.y = 3770, spawn.mapRect(level.enter.x, level.enter.y + 20, 100, 20), spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 20), level.defaultZoom = 3000, simulation.zoomTransition(level.defaultZoom), document.body.style.backgroundColor = "#d8dadf";
|
||||||
|
|||||||
@@ -733,6 +733,9 @@ const powerUps = {
|
|||||||
if (localSettings.isHideImages) {
|
if (localSettings.isHideImages) {
|
||||||
document.getElementById("choose-grid").style.gridTemplateColumns = width
|
document.getElementById("choose-grid").style.gridTemplateColumns = width
|
||||||
text += powerUps.researchAndCancelText(type)
|
text += powerUps.researchAndCancelText(type)
|
||||||
|
} else if (totalChoices === 0) {
|
||||||
|
document.getElementById("choose-grid").style.gridTemplateColumns = width
|
||||||
|
text += powerUps.researchAndCancelText(type)
|
||||||
} else if (totalChoices === 1 || canvas.width < 1200) {
|
} else if (totalChoices === 1 || canvas.width < 1200) {
|
||||||
document.getElementById("choose-grid").style.gridTemplateColumns = width
|
document.getElementById("choose-grid").style.gridTemplateColumns = width
|
||||||
text += powerUps.researchAndCancelText(type)
|
text += powerUps.researchAndCancelText(type)
|
||||||
@@ -903,39 +906,39 @@ const powerUps = {
|
|||||||
if (b.guns[i].isRecentlyShown) removeOption(i)
|
if (b.guns[i].isRecentlyShown) removeOption(i)
|
||||||
}
|
}
|
||||||
for (let i = 0; i < b.guns.length; i++) b.guns[i].isRecentlyShown = false //reset recently shown back to zero
|
for (let i = 0; i < b.guns.length; i++) b.guns[i].isRecentlyShown = false //reset recently shown back to zero
|
||||||
if (options.length > 0) {
|
// if (options.length > 0) {
|
||||||
let text = powerUps.buildColumns(totalChoices, "gun")
|
let text = powerUps.buildColumns(totalChoices, "gun")
|
||||||
for (let i = 0; i < totalChoices; i++) {
|
for (let i = 0; i < totalChoices; i++) {
|
||||||
const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
|
const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
|
||||||
// text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${choose})"><div class="grid-title"><div class="circle-grid gun"></div> ${b.guns[choose].name}</div> ${b.guns[choose].description}</div>`
|
// text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${choose})"><div class="grid-title"><div class="circle-grid gun"></div> ${b.guns[choose].name}</div> ${b.guns[choose].description}</div>`
|
||||||
text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`)
|
text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`)
|
||||||
|
|
||||||
b.guns[choose].isRecentlyShown = true
|
b.guns[choose].isRecentlyShown = true
|
||||||
removeOption(choose)
|
removeOption(choose)
|
||||||
if (options.length < 1) break
|
if (options.length < 1) break
|
||||||
|
}
|
||||||
|
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.isExtraBotOption) {
|
if (botTech.length > 0) { //pick random bot tech
|
||||||
const botTech = [] //make an array of bot options
|
// const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
||||||
for (let i = 0, len = tech.tech.length; i < len; i++) {
|
// const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : "";
|
||||||
if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i)
|
// text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"> <span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
|
||||||
}
|
const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
||||||
if (botTech.length > 0) { //pick random bot tech
|
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
||||||
// const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
||||||
// const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : "";
|
text += `<div class="choose-grid-module card-background" onclick="powerUps.choose('tech',${choose})" ${style}>
|
||||||
// text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"> <span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
|
|
||||||
const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
|
||||||
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
|
||||||
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
|
||||||
text += `<div class="choose-grid-module card-background" onclick="powerUps.choose('tech',${choose})" ${style}>
|
|
||||||
<div class="card-text">
|
<div class="card-text">
|
||||||
<div class="grid-title"><span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${techCountText}</div>
|
<div class="grid-title"><span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${techCountText}</div>
|
||||||
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (tech.isOneGun && b.inventory.length > 0) text += `<div style = "color: #f24">replaces your current gun</div>`
|
|
||||||
document.getElementById("choose-grid").innerHTML = text
|
|
||||||
powerUps.showDraft();
|
|
||||||
}
|
}
|
||||||
|
if (tech.isOneGun && b.inventory.length > 0) text += `<div style = "color: #f24">replaces your current gun</div>`
|
||||||
|
document.getElementById("choose-grid").innerHTML = text
|
||||||
|
powerUps.showDraft();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
138
js/spawn.js
138
js/spawn.js
@@ -1,7 +1,7 @@
|
|||||||
//main object for spawning things in a level
|
//main object for spawning things in a level
|
||||||
const spawn = {
|
const spawn = {
|
||||||
nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture"],
|
nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture"],
|
||||||
// other bosses: suckerBoss, laserBoss, tetherBoss, bounceBoss, sprayBoss, mineBoss, hopMomBoss //these need a particular level to work so they are not included in the random pool
|
// other bosses: suckerBoss, laserBoss, tetherBoss, bounceBoss, sprayBoss, mineBoss, hopMotherBoss //these need a particular level to work so they are not included in the random pool
|
||||||
randomBossList: [
|
randomBossList: [
|
||||||
"orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss",
|
"orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss",
|
||||||
"powerUpBoss", "powerUpBossBaby", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss",
|
"powerUpBoss", "powerUpBossBaby", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss",
|
||||||
@@ -21,8 +21,8 @@ const spawn = {
|
|||||||
pickList: ["starter", "starter"],
|
pickList: ["starter", "starter"],
|
||||||
fullPickList: [
|
fullPickList: [
|
||||||
"slasher", "slasher", "slasher2", "slasher3",
|
"slasher", "slasher", "slasher2", "slasher3",
|
||||||
|
"hopper", "hopper", "hopMother", "hopMother",
|
||||||
"flutter", "flutter", "flutter",
|
"flutter", "flutter", "flutter",
|
||||||
"hopper", "hopper", "hopper",
|
|
||||||
"stabber", "stabber", "stabber",
|
"stabber", "stabber", "stabber",
|
||||||
"springer", "springer", "springer",
|
"springer", "springer", "springer",
|
||||||
"shooter", "shooter",
|
"shooter", "shooter",
|
||||||
@@ -2343,10 +2343,7 @@ const spawn = {
|
|||||||
const springStiffness = 0.00014;
|
const springStiffness = 0.00014;
|
||||||
const springDampening = 0.0005;
|
const springDampening = 0.0005;
|
||||||
|
|
||||||
me.springTarget = {
|
me.springTarget = { x: me.position.x, y: me.position.y };
|
||||||
x: me.position.x,
|
|
||||||
y: me.position.y
|
|
||||||
};
|
|
||||||
const len = cons.length;
|
const len = cons.length;
|
||||||
cons[len] = Constraint.create({
|
cons[len] = Constraint.create({
|
||||||
pointA: me.springTarget,
|
pointA: me.springTarget,
|
||||||
@@ -2359,10 +2356,7 @@ const spawn = {
|
|||||||
cons[len].length = 100 + 1.5 * radius;
|
cons[len].length = 100 + 1.5 * radius;
|
||||||
me.cons = cons[len];
|
me.cons = cons[len];
|
||||||
|
|
||||||
me.springTarget2 = {
|
me.springTarget2 = { x: me.position.x, y: me.position.y };
|
||||||
x: me.position.x,
|
|
||||||
y: me.position.y
|
|
||||||
};
|
|
||||||
const len2 = cons.length;
|
const len2 = cons.length;
|
||||||
cons[len2] = Constraint.create({
|
cons[len2] = Constraint.create({
|
||||||
pointA: me.springTarget2,
|
pointA: me.springTarget2,
|
||||||
@@ -2379,15 +2373,15 @@ const spawn = {
|
|||||||
this.checkStatus();
|
this.checkStatus();
|
||||||
this.springAttack();
|
this.springAttack();
|
||||||
};
|
};
|
||||||
|
|
||||||
me.onDeath = function () {
|
me.onDeath = function () {
|
||||||
this.removeCons();
|
this.removeCons();
|
||||||
};
|
};
|
||||||
spawn.shield(me, x, y);
|
spawn.shield(me, x, y);
|
||||||
},
|
},
|
||||||
hopper(x, y, radius = 30 + Math.ceil(Math.random() * 30)) {
|
hopper(x, y, radius = 35 + Math.ceil(Math.random() * 30)) {
|
||||||
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
|
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
|
||||||
let me = mob[mob.length - 1];
|
let me = mob[mob.length - 1];
|
||||||
|
Matter.Body.setDensity(me, 0.0015); //normal is 0.001
|
||||||
me.accelMag = 0.05;
|
me.accelMag = 0.05;
|
||||||
me.g = 0.0032; //required if using this.gravity
|
me.g = 0.0032; //required if using this.gravity
|
||||||
me.frictionAir = 0.01;
|
me.frictionAir = 0.01;
|
||||||
@@ -2425,6 +2419,116 @@ const spawn = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
hopMother(x, y, radius = 20 + Math.ceil(Math.random() * 20)) {
|
||||||
|
mobs.spawn(x, y, 5, radius, "rgb(50,170,200)");
|
||||||
|
let me = mob[mob.length - 1];
|
||||||
|
Matter.Body.setDensity(me, 0.0008); //normal is 0.001
|
||||||
|
me.accelMag = 0.05;
|
||||||
|
me.g = 0.0032; //required if using this.gravity
|
||||||
|
me.frictionAir = 0.01;
|
||||||
|
me.friction = 1
|
||||||
|
me.frictionStatic = 1
|
||||||
|
me.restitution = 0;
|
||||||
|
me.delay = 120 + 110 * simulation.CDScale;
|
||||||
|
me.randomHopFrequency = 300 + Math.floor(Math.random() * 150);
|
||||||
|
me.randomHopCD = simulation.cycle + me.randomHopFrequency;
|
||||||
|
Matter.Body.rotate(me, Math.random());
|
||||||
|
spawn.shield(me, x, y);
|
||||||
|
me.dropEgg = function () {
|
||||||
|
if (mob.length < 360) {
|
||||||
|
let where = { x: this.position.x, y: this.position.y + 0.3 * radius }
|
||||||
|
for (let i = 0; i < 30; i++) { //find the ground
|
||||||
|
if (Matter.Query.point(map, where).length > 0 || Matter.Query.point(body, where).length > 0) break
|
||||||
|
where.y += 1
|
||||||
|
}
|
||||||
|
spawn.hopEgg(where.x, where.y - 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
me.do = function () {
|
||||||
|
this.gravity();
|
||||||
|
this.seePlayerCheck();
|
||||||
|
this.checkStatus();
|
||||||
|
if (this.seePlayer.recall) {
|
||||||
|
if (this.cd < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
|
||||||
|
this.cd = simulation.cycle + this.delay;
|
||||||
|
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.06 + 0.1) * this.mass; //antigravity
|
||||||
|
this.dropEgg();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//randomly hob if not aware of player
|
||||||
|
if (this.randomHopCD < simulation.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) {
|
||||||
|
this.randomHopCD = simulation.cycle + this.randomHopFrequency;
|
||||||
|
//slowly change randomHopFrequency after each hop
|
||||||
|
this.randomHopFrequency = Math.max(100, this.randomHopFrequency + (0.5 - Math.random()) * 200);
|
||||||
|
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.07 * this.mass; //antigravity
|
||||||
|
if (Math.random() < 0.2) this.dropEgg();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
hopEgg(x, y) {
|
||||||
|
mobs.spawn(x, y, 10, 9 + Math.floor(3 * Math.random()), "rgba(50, 150, 150,0.3)"); //"rgb(100,170,150)" //"rgb(61, 125, 121)"
|
||||||
|
let me = mob[mob.length - 1];
|
||||||
|
me.stroke = "transparent";
|
||||||
|
Matter.Body.setDensity(me, 0.0001); //normal is 0.001
|
||||||
|
// Matter.Body.setStatic(me, true); //make static (disables taking damage)
|
||||||
|
me.frictionAir = 1
|
||||||
|
me.damageReduction = 2
|
||||||
|
me.collisionFilter.mask = cat.bullet //| cat.body
|
||||||
|
// me.collisionFilter.category = cat.mobBullet;
|
||||||
|
// me.collisionFilter.mask = cat.bullet | cat.body // | cat.player
|
||||||
|
me.isMine = true
|
||||||
|
me.leaveBody = false;
|
||||||
|
me.isDropPowerUp = false;
|
||||||
|
me.isBadTarget = true;
|
||||||
|
me.isMobBullet = true;
|
||||||
|
me.isUnstable = true; //dies when blocked
|
||||||
|
me.showHealthBar = false;
|
||||||
|
me.explodeRange = 210 + 140 * Math.random()
|
||||||
|
me.isExploding = false
|
||||||
|
me.countDown = Math.ceil(4 * Math.random())
|
||||||
|
me.hatchTimer = 600 + Math.floor(120 * Math.random())
|
||||||
|
me.isInvulnerable = true //not actually invulnerable, just prevents block + ice-9 interaction
|
||||||
|
me.do = function () {
|
||||||
|
this.checkStatus();
|
||||||
|
this.hatchTimer--
|
||||||
|
if (this.hatchTimer < 1) {
|
||||||
|
spawn.hopBullet(this.position.x, this.position.y)
|
||||||
|
this.death();
|
||||||
|
}
|
||||||
|
if (Matter.Query.collides(this, [player]).length > 0) this.isExploding = true
|
||||||
|
if (this.isExploding) {
|
||||||
|
if (this.countDown-- < 0) { //explode
|
||||||
|
this.death();
|
||||||
|
//hit player
|
||||||
|
if (Vector.magnitude(Vector.sub(this.position, player.position)) < this.explodeRange && m.immuneCycle < m.cycle) {
|
||||||
|
m.damage(0.01 * simulation.dmgScale * (tech.isRadioactiveResistance ? 0.25 : 1));
|
||||||
|
m.energy -= 0.1 * (tech.isRadioactiveResistance ? 0.25 : 1)
|
||||||
|
if (m.energy < 0) m.energy = 0
|
||||||
|
}
|
||||||
|
const range = this.explodeRange + 50 //mines get a slightly larger range to explode
|
||||||
|
for (let i = 0, len = mob.length; i < len; ++i) {
|
||||||
|
if (mob[i].alive && Vector.magnitude(Vector.sub(this.position, mob[i].position)) < range && mob[i].isMine) {
|
||||||
|
mob[i].isExploding = true //explode other mines
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simulation.drawList.push({ //add dmg to draw queue
|
||||||
|
x: this.position.x,
|
||||||
|
y: this.position.y,
|
||||||
|
radius: this.explodeRange,
|
||||||
|
color: "rgba(50,180,180,0.45)",
|
||||||
|
time: 16
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
hopBullet(x, y, radius = 10 + Math.ceil(Math.random() * 8)) {
|
hopBullet(x, y, radius = 10 + Math.ceil(Math.random() * 8)) {
|
||||||
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
|
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
|
||||||
let me = mob[mob.length - 1];
|
let me = mob[mob.length - 1];
|
||||||
@@ -2434,7 +2538,7 @@ const spawn = {
|
|||||||
// me.isBadTarget = true;
|
// me.isBadTarget = true;
|
||||||
me.isMobBullet = true;
|
me.isMobBullet = true;
|
||||||
me.showHealthBar = false;
|
me.showHealthBar = false;
|
||||||
me.timeLeft = 1200 + Math.floor(600 * Math.random());
|
me.timeLeft = 1140 + Math.floor(480 * Math.random());
|
||||||
|
|
||||||
me.isRandomMove = Math.random() < 0.3 //most chase player, some don't
|
me.isRandomMove = Math.random() < 0.3 //most chase player, some don't
|
||||||
me.accelMag = 0.01; //jump height
|
me.accelMag = 0.01; //jump height
|
||||||
@@ -2448,7 +2552,7 @@ const spawn = {
|
|||||||
me.collisionFilter.category = cat.mobBullet;
|
me.collisionFilter.category = cat.mobBullet;
|
||||||
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
|
me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet;
|
||||||
me.onHit = function () {
|
me.onHit = function () {
|
||||||
this.explode(this.mass);
|
this.explode(0.5 * this.mass);
|
||||||
};
|
};
|
||||||
me.do = function () {
|
me.do = function () {
|
||||||
this.gravity();
|
this.gravity();
|
||||||
@@ -2465,18 +2569,18 @@ const spawn = {
|
|||||||
this.timeLimit();
|
this.timeLimit();
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
hopMomBoss(x, y, radius = 120) {
|
hopMotherBoss(x, y, radius = 120) {
|
||||||
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
|
mobs.spawn(x, y, 5, radius, "rgb(0,200,180)");
|
||||||
let me = mob[mob.length - 1];
|
let me = mob[mob.length - 1];
|
||||||
me.isBoss = true;
|
me.isBoss = true;
|
||||||
me.damageReduction = 0.08 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
|
me.damageReduction = 0.09 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
|
||||||
me.accelMag = 0.05; //jump height
|
me.accelMag = 0.05; //jump height
|
||||||
me.g = 0.003; //required if using this.gravity
|
me.g = 0.003; //required if using this.gravity
|
||||||
me.frictionAir = 0.01;
|
me.frictionAir = 0.01;
|
||||||
me.friction = 1
|
me.friction = 1
|
||||||
me.frictionStatic = 1
|
me.frictionStatic = 1
|
||||||
me.restitution = 0;
|
me.restitution = 0;
|
||||||
me.delay = 120 + 40 * simulation.CDScale;
|
me.delay = 130 + 40 * simulation.CDScale;
|
||||||
Matter.Body.rotate(me, Math.random() * Math.PI);
|
Matter.Body.rotate(me, Math.random() * Math.PI);
|
||||||
spawn.shield(me, x, y, 1);
|
spawn.shield(me, x, y, 1);
|
||||||
me.onDeath = function () {
|
me.onDeath = function () {
|
||||||
|
|||||||
20
todo.txt
20
todo.txt
@@ -1,24 +1,14 @@
|
|||||||
******************************************************** NEXT PATCH **************************************************
|
******************************************************** NEXT PATCH **************************************************
|
||||||
|
|
||||||
missile Bot: +10% bigger explosions, +10% damage, +7% fire rate
|
new mob type: hopMother - hoppers that drop eggs that explode on contact and after several seconds they hatch into baby hoppers
|
||||||
plasma Bot: +40% damage, and drains 2% less energy
|
regular hopper mobs have more life and more damage
|
||||||
1st ionization energy: 8->11 energy per heal
|
|
||||||
mass-energy: defense reduction factor 0.13->0.33
|
|
||||||
neutron bomb: +25% damage
|
|
||||||
non-renewables: 78->88% damage
|
|
||||||
junk DNA: applies to all damage, not just spores
|
|
||||||
pseudoscience: adds (1-4)->(1-3) JUNK to tech pool per free research
|
|
||||||
futures exchange: 4.1->4.3 duplication per cancel
|
|
||||||
|
|
||||||
default skin has slightly more narrow legs
|
|
||||||
|
|
||||||
added ammo to gun descriptions
|
|
||||||
calculate the ammo drop rate for each gun live based on ammo tech?
|
|
||||||
need to make a generic function
|
|
||||||
|
|
||||||
|
a few bug fixes
|
||||||
|
|
||||||
*********************************************************** TODO *****************************************************
|
*********************************************************** TODO *****************************************************
|
||||||
|
|
||||||
|
a mob/boss? that drops the mines from reactor and final boss
|
||||||
|
|
||||||
more (all) bosses need to be made of parts
|
more (all) bosses need to be made of parts
|
||||||
good examples: spiderBoss, dragonFlyBoss, beetleBoss
|
good examples: spiderBoss, dragonFlyBoss, beetleBoss
|
||||||
methods:
|
methods:
|
||||||
|
|||||||
Reference in New Issue
Block a user