mantisBoss
mantisBoss: 3 punching mobs, eject your ammo when you get punched invulnerable except for 1 second after moving powerUpBossBaby: smaller, cuter, faster, can't move through walls slashBoss renamed revolutionBoss invulnerable every other revolution of it's blades new mob state: invulnerable - immune to damage and status effects (stun, dots, freeze) damage and harm circle graphic size have been made more consistent bug fixes
This commit is contained in:
22
js/bullet.js
22
js/bullet.js
@@ -1932,7 +1932,7 @@ const b = {
|
|||||||
simulation.drawList.push({
|
simulation.drawList.push({
|
||||||
x: path[1].x,
|
x: path[1].x,
|
||||||
y: path[1].y,
|
y: path[1].y,
|
||||||
radius: Math.sqrt(dmg) * 50,
|
radius: 600 * dmg * best.who.damageReduction,
|
||||||
color: "rgba(255,0,255,0.2)",
|
color: "rgba(255,0,255,0.2)",
|
||||||
time: simulation.drawTime * 4
|
time: simulation.drawTime * 4
|
||||||
});
|
});
|
||||||
@@ -2058,7 +2058,8 @@ const b = {
|
|||||||
simulation.drawList.push({ //add dmg to draw queue
|
simulation.drawList.push({ //add dmg to draw queue
|
||||||
x: path[path.length - 1].x,
|
x: path[path.length - 1].x,
|
||||||
y: path[path.length - 1].y,
|
y: path[path.length - 1].y,
|
||||||
radius: Math.sqrt(damage) * 100,
|
// radius: Math.sqrt(damage) * 100 * mob[k].damageReduction,
|
||||||
|
radius: 600 * damage * best.who.damageReduction,
|
||||||
color: tech.laserColorAlpha,
|
color: tech.laserColorAlpha,
|
||||||
time: simulation.drawTime
|
time: simulation.drawTime
|
||||||
});
|
});
|
||||||
@@ -2705,7 +2706,7 @@ const b = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onEnd() {
|
onEnd() {
|
||||||
if (tech.isDroneRespawn) {
|
if (tech.isDroneRespawn && b.inventory.length) {
|
||||||
const who = b.guns[b.activeGun]
|
const who = b.guns[b.activeGun]
|
||||||
if (who.name === "drones" && who.ammo > 0 && mob.length) {
|
if (who.name === "drones" && who.ammo > 0 && mob.length) {
|
||||||
b.drone({ x: this.position.x, y: this.position.y }, 0)
|
b.drone({ x: this.position.x, y: this.position.y }, 0)
|
||||||
@@ -3178,7 +3179,7 @@ const b = {
|
|||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
if (targets.length - i > 0) {
|
if (targets.length - i > 0) {
|
||||||
const index = Math.floor(Math.random() * targets.length)
|
const index = Math.floor(Math.random() * targets.length)
|
||||||
const speed = 10 + 10 * Math.random()
|
const speed = 6 + 6 * Math.random()
|
||||||
const velocity = Vector.mult(Vector.normalise(Vector.sub(targets[index].position, this.position)), speed)
|
const velocity = Vector.mult(Vector.normalise(Vector.sub(targets[index].position, this.position)), speed)
|
||||||
b.foam(this.position, Vector.rotate(velocity, 0.5 * (Math.random() - 0.5)), radius)
|
b.foam(this.position, Vector.rotate(velocity, 0.5 * (Math.random() - 0.5)), radius)
|
||||||
} else {
|
} else {
|
||||||
@@ -3342,7 +3343,7 @@ const b = {
|
|||||||
simulation.drawList.push({ //add dmg to draw queue
|
simulation.drawList.push({ //add dmg to draw queue
|
||||||
x: this.position.x,
|
x: this.position.x,
|
||||||
y: this.position.y,
|
y: this.position.y,
|
||||||
radius: Math.log(2 * dmg + 1.1) * 40,
|
radius: Math.log(2 * dmg + 1.1) * 40 * who.damageReduction,
|
||||||
color: simulation.playerDmgColor,
|
color: simulation.playerDmgColor,
|
||||||
time: simulation.drawTime
|
time: simulation.drawTime
|
||||||
});
|
});
|
||||||
@@ -3395,7 +3396,7 @@ const b = {
|
|||||||
simulation.drawList.push({ //add dmg to draw queue
|
simulation.drawList.push({ //add dmg to draw queue
|
||||||
x: this.position.x,
|
x: this.position.x,
|
||||||
y: this.position.y,
|
y: this.position.y,
|
||||||
radius: Math.log(2 * dmg + 1.1) * 40,
|
radius: Math.log(2 * dmg + 1.1) * 40 * who.damageReduction,
|
||||||
color: simulation.playerDmgColor,
|
color: simulation.playerDmgColor,
|
||||||
time: simulation.drawTime
|
time: simulation.drawTime
|
||||||
});
|
});
|
||||||
@@ -3651,7 +3652,7 @@ const b = {
|
|||||||
simulation.drawList.push({ //add dmg to draw queue
|
simulation.drawList.push({ //add dmg to draw queue
|
||||||
x: this.position.x,
|
x: this.position.x,
|
||||||
y: this.position.y,
|
y: this.position.y,
|
||||||
radius: Math.log(2 * dmg + 1.1) * 40,
|
radius: 600 * dmg * q[i].damageReduction,
|
||||||
color: 'rgba(0,0,0,0.4)',
|
color: 'rgba(0,0,0,0.4)',
|
||||||
time: simulation.drawTime
|
time: simulation.drawTime
|
||||||
});
|
});
|
||||||
@@ -4204,7 +4205,8 @@ const b = {
|
|||||||
simulation.drawList.push({
|
simulation.drawList.push({
|
||||||
x: path[1].x,
|
x: path[1].x,
|
||||||
y: path[1].y,
|
y: path[1].y,
|
||||||
radius: Math.sqrt(dmg) * 50,
|
// radius: Math.sqrt(dmg) * 50 * mob[k].damageReduction,
|
||||||
|
radius: 600 * dmg * best.who.damageReduction,
|
||||||
color: "rgba(255,0,255,0.2)",
|
color: "rgba(255,0,255,0.2)",
|
||||||
time: simulation.drawTime * 4
|
time: simulation.drawTime * 4
|
||||||
});
|
});
|
||||||
@@ -4297,7 +4299,7 @@ const b = {
|
|||||||
simulation.drawList.push({ //add dmg to draw queue
|
simulation.drawList.push({ //add dmg to draw queue
|
||||||
x: this.position.x,
|
x: this.position.x,
|
||||||
y: this.position.y,
|
y: this.position.y,
|
||||||
radius: Math.log(2 * dmg + 1.1) * 40,
|
radius: 600 * dmg * q[i].damageReduction,
|
||||||
color: 'rgba(0,0,0,0.4)',
|
color: 'rgba(0,0,0,0.4)',
|
||||||
time: simulation.drawTime
|
time: simulation.drawTime
|
||||||
});
|
});
|
||||||
@@ -5211,7 +5213,7 @@ const b = {
|
|||||||
simulation.drawList.push({ //add dmg to draw queue
|
simulation.drawList.push({ //add dmg to draw queue
|
||||||
x: this.position.x,
|
x: this.position.x,
|
||||||
y: this.position.y,
|
y: this.position.y,
|
||||||
radius: Math.log(2 * dmg + 1.1) * 40,
|
radius: Math.log(2 * dmg + 1.1) * 40 * q[i].damageReduction,
|
||||||
color: 'rgba(0,0,0,0.4)',
|
color: 'rgba(0,0,0,0.4)',
|
||||||
time: simulation.drawTime
|
time: simulation.drawTime
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ function collisionChecks(event) {
|
|||||||
simulation.drawList.push({ //add dmg to draw queue
|
simulation.drawList.push({ //add dmg to draw queue
|
||||||
x: pairs[i].activeContacts[0].vertex.x,
|
x: pairs[i].activeContacts[0].vertex.x,
|
||||||
y: pairs[i].activeContacts[0].vertex.y,
|
y: pairs[i].activeContacts[0].vertex.y,
|
||||||
radius: dmg * 2000,
|
radius: Math.sqrt(dmg) * 500,
|
||||||
color: "rgba(255,0,255,0.2)",
|
color: "rgba(255,0,255,0.2)",
|
||||||
time: simulation.drawTime
|
time: simulation.drawTime
|
||||||
});
|
});
|
||||||
@@ -163,7 +163,7 @@ function collisionChecks(event) {
|
|||||||
simulation.drawList.push({ //add dmg to draw queue
|
simulation.drawList.push({ //add dmg to draw queue
|
||||||
x: pairs[i].activeContacts[0].vertex.x,
|
x: pairs[i].activeContacts[0].vertex.x,
|
||||||
y: pairs[i].activeContacts[0].vertex.y,
|
y: pairs[i].activeContacts[0].vertex.y,
|
||||||
radius: dmg * 500,
|
radius: Math.sqrt(dmg) * 200,
|
||||||
color: simulation.mobDmgColor,
|
color: simulation.mobDmgColor,
|
||||||
time: simulation.drawTime
|
time: simulation.drawTime
|
||||||
});
|
});
|
||||||
@@ -182,7 +182,7 @@ function collisionChecks(event) {
|
|||||||
simulation.drawList.push({ //add dmg to draw queue
|
simulation.drawList.push({ //add dmg to draw queue
|
||||||
x: pairs[i].activeContacts[0].vertex.x,
|
x: pairs[i].activeContacts[0].vertex.x,
|
||||||
y: pairs[i].activeContacts[0].vertex.y,
|
y: pairs[i].activeContacts[0].vertex.y,
|
||||||
radius: Math.log(2 * dmg + 1.1) * 40,
|
radius: Math.log(2 * dmg + 1.1) * 40 * mob[k].damageReduction,
|
||||||
color: simulation.playerDmgColor,
|
color: simulation.playerDmgColor,
|
||||||
time: simulation.drawTime
|
time: simulation.drawTime
|
||||||
});
|
});
|
||||||
@@ -217,7 +217,7 @@ function collisionChecks(event) {
|
|||||||
simulation.drawList.push({
|
simulation.drawList.push({
|
||||||
x: pairs[i].activeContacts[0].vertex.x,
|
x: pairs[i].activeContacts[0].vertex.x,
|
||||||
y: pairs[i].activeContacts[0].vertex.y,
|
y: pairs[i].activeContacts[0].vertex.y,
|
||||||
radius: Math.log(2 * dmg + 1.1) * 40,
|
radius: Math.log(2 * dmg + 1.1) * 40 * mob[k].damageReduction,
|
||||||
color: simulation.playerDmgColor,
|
color: simulation.playerDmgColor,
|
||||||
time: simulation.drawTime
|
time: simulation.drawTime
|
||||||
});
|
});
|
||||||
|
|||||||
48
js/index.js
48
js/index.js
@@ -215,32 +215,30 @@ const build = {
|
|||||||
if (tech.missileBotCount) botText += `<br>missile-bots: ${tech.missileBotCount}`
|
if (tech.missileBotCount) botText += `<br>missile-bots: ${tech.missileBotCount}`
|
||||||
|
|
||||||
const harm = (1 - m.harmReduction()) * 100
|
const harm = (1 - m.harmReduction()) * 100
|
||||||
let text = ""
|
let text = `<div class="pause-grid-module" style = "font-size: 13px;line-height: 120%;padding: 5px;">`
|
||||||
if (!simulation.isChoosing) text += `<div class="pause-grid-module">
|
if (!simulation.isChoosing) text += `<br><span style="font-size:1.5em;font-weight: 600;">PAUSED</span> press P to resume
|
||||||
<span style="font-size:1.5em;font-weight: 600;">PAUSED</span> press P to resume</div>`
|
<br><br><svg class="SVG-button" onclick="build.shareURL(false)" width="92" height="20" style="padding:0px; margin: 1px;">
|
||||||
text += `<div class="pause-grid-module" style = "font-size: 13px;line-height: 120%;padding: 5px;">
|
<g stroke='none' fill='#333' stroke-width="2" font-size="14px" font-family="Ariel, sans-serif"> <text x="5" y="15">copy build url</text></g>
|
||||||
${simulation.isCheating? "<em>lore disabled</em><br><br>": ""}
|
</svg><br>`
|
||||||
<strong class='color-d'>damage</strong> increase: ${((tech.damageFromTech()-1)*100).toFixed(0)}%
|
text += `<strong class='color-d'>damage</strong> increase: ${((tech.damageFromTech()-1)*100).toFixed(0)}%
|
||||||
<br><strong class='color-harm'>harm</strong> reduction: ${harm.toFixed(harm > 90 ? 2 : 0)}%
|
<br><strong class='color-harm'>harm</strong> reduction: ${harm.toFixed(harm > 90 ? 2 : 0)}%
|
||||||
<br><strong><em>fire delay</em></strong> decrease: ${((1-b.fireCDscale)*100).toFixed(b.fireCDscale < 0.1 ? 2 : 0)}%
|
<br><strong><em>fire delay</em></strong> decrease: ${((1-b.fireCDscale)*100).toFixed(b.fireCDscale < 0.1 ? 2 : 0)}%
|
||||||
<br><strong class='color-dup'>duplication</strong> chance: ${(tech.duplicationChance()*100).toFixed(0)}%
|
<br><strong class='color-dup'>duplication</strong> chance: ${(tech.duplicationChance()*100).toFixed(0)}%
|
||||||
${botText}
|
${botText}
|
||||||
<br>
|
<br>
|
||||||
<br><strong class='color-m'>tech</strong>: ${tech.totalCount} <strong class='color-r'>research</strong>: ${powerUps.research.count}
|
<br><strong class='color-m'>tech</strong>: ${tech.totalCount} <strong class='color-r'>research</strong>: ${powerUps.research.count}
|
||||||
<br><strong class='color-h'>health</strong>: (${(m.health*100).toFixed(0)} / ${(m.maxHealth*100).toFixed(0)}) <strong class='color-f'>energy</strong>: (${(m.energy*100).toFixed(0)} / ${(m.maxEnergy*100).toFixed(0)})
|
<br><strong class='color-h'>health</strong>: (${(m.health*100).toFixed(0)} / ${(m.maxHealth*100).toFixed(0)}) <strong class='color-f'>energy</strong>: (${(m.energy*100).toFixed(0)} / ${(m.maxEnergy*100).toFixed(0)})
|
||||||
<br>position: (${player.position.x.toFixed(1)}, ${player.position.y.toFixed(1)}) velocity: (${player.velocity.x.toFixed(1)}, ${player.velocity.y.toFixed(1)})
|
<br><strong class='color-g'>gun</strong>: ${b.activeGun !== null ? b.guns[b.activeGun].name: "null"} <strong class='color-g'>ammo</strong>: ${b.activeGun !== null ? b.guns[b.activeGun].ammo: "0"}
|
||||||
<br>mouse: (${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)}) mass: ${player.mass.toFixed(1)}
|
<br>position: (${player.position.x.toFixed(1)}, ${player.position.y.toFixed(1)}) velocity: (${player.velocity.x.toFixed(1)}, ${player.velocity.y.toFixed(1)})
|
||||||
<br>
|
<br>mouse: (${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)}) mass: ${player.mass.toFixed(1)}
|
||||||
<br>level: ${level.levels[level.onLevel]} (${level.difficultyText()}) ${m.cycle} cycles
|
<br>
|
||||||
<br>${mob.length} mobs, ${body.length} blocks, ${bullet.length} bullets, ${powerUp.length} power ups
|
<br>level: ${level.levels[level.onLevel]} (${level.difficultyText()}) ${m.cycle} cycles
|
||||||
|
<br>${mob.length} mobs, ${body.length} blocks, ${bullet.length} bullets, ${powerUp.length} power ups
|
||||||
|
|
||||||
<br>damage difficulty scale: ${(b.dmgScale*100).toFixed(2) }%
|
<br>damage difficulty scale: ${(b.dmgScale*100).toFixed(2) }%
|
||||||
<br>harm difficulty scale: ${(simulation.dmgScale*100).toFixed(0)}%
|
<br>harm difficulty scale: ${(simulation.dmgScale*100).toFixed(0)}%
|
||||||
<br>heal difficulty scale: ${(simulation.healScale*100).toFixed(1)}%
|
<br>heal difficulty scale: ${(simulation.healScale*100).toFixed(1)}%
|
||||||
<br>
|
${simulation.isCheating ? "<br><br><em>lore disabled</em>": ""}
|
||||||
<svg class="SVG-button" onclick="build.shareURL(false)" width="110" height="25" style="padding:2px; margin: 10px;">
|
|
||||||
<g stroke='none' fill='#333' stroke-width="2" font-size="17px" font-family="Ariel, sans-serif"> <text x="5" y="18">copy build url</text> </g>
|
|
||||||
</svg>
|
|
||||||
</div>`;
|
</div>`;
|
||||||
for (let i = 0, len = b.inventory.length; i < len; i++) {
|
for (let i = 0, len = b.inventory.length; i < len; i++) {
|
||||||
text += `<div class="pause-grid-module"><div class="grid-title"><div class="circle-grid gun"></div> ${build.nameLink(b.guns[b.inventory[i]].name)} - <span style="font-size:100%;font-weight: 100;">${b.guns[b.inventory[i]].ammo}</span></div> ${b.guns[b.inventory[i]].description}</div>`
|
text += `<div class="pause-grid-module"><div class="grid-title"><div class="circle-grid gun"></div> ${build.nameLink(b.guns[b.inventory[i]].name)} - <span style="font-size:100%;font-weight: 100;">${b.guns[b.inventory[i]].ammo}</span></div> ${b.guns[b.inventory[i]].description}</div>`
|
||||||
|
|||||||
33
js/level.js
33
js/level.js
@@ -16,8 +16,8 @@ const level = {
|
|||||||
// localSettings.levelsClearedLastGame = 10
|
// localSettings.levelsClearedLastGame = 10
|
||||||
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why
|
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why
|
||||||
// simulation.isHorizontalFlipped = true
|
// simulation.isHorizontalFlipped = true
|
||||||
// m.setField("wormhole")
|
// m.setField("plasma torch")
|
||||||
// b.giveGuns("shotgun")
|
// b.giveGuns("drones")
|
||||||
// b.giveGuns("nail gun")
|
// b.giveGuns("nail gun")
|
||||||
// b.giveGuns("harpoon")
|
// b.giveGuns("harpoon")
|
||||||
// tech.giveTech("needle gun")
|
// tech.giveTech("needle gun")
|
||||||
@@ -2337,13 +2337,15 @@ const level = {
|
|||||||
spawn.mapRect(4850, -275, 50, 175);
|
spawn.mapRect(4850, -275, 50, 175);
|
||||||
|
|
||||||
//???
|
//???
|
||||||
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why
|
level.difficultyIncrease(1) //30 is near max on hard //60 is near max on why
|
||||||
|
m.addHealth(Infinity)
|
||||||
|
|
||||||
// spawn.starter(1900, -500, 200) //big boy
|
// spawn.starter(1900, -500, 200) //big boy
|
||||||
|
|
||||||
// spawn.launcherOne(1700, -500)
|
|
||||||
// spawn.launcherBoss(3200, -500)
|
// spawn.launcherBoss(3200, -500)
|
||||||
// spawn.laserTargetingBoss(1700, -500)
|
// spawn.laserTargetingBoss(1700, -500)
|
||||||
// spawn.powerUpBoss(3200, -500)
|
// spawn.powerUpBoss(3200, -500)
|
||||||
|
// spawn.powerUpBossBaby(3200, -500)
|
||||||
// spawn.snakeBoss(1700, -500)
|
// spawn.snakeBoss(1700, -500)
|
||||||
// spawn.streamBoss(3200, -500)
|
// spawn.streamBoss(3200, -500)
|
||||||
// spawn.pulsarBoss(1700, -500)
|
// spawn.pulsarBoss(1700, -500)
|
||||||
@@ -2355,28 +2357,19 @@ const level = {
|
|||||||
// spawn.laserBombingBoss(1700, -500)
|
// spawn.laserBombingBoss(1700, -500)
|
||||||
// spawn.launcherBoss(3200, -500)
|
// spawn.launcherBoss(3200, -500)
|
||||||
// spawn.blockBoss(1700, -500)
|
// spawn.blockBoss(1700, -500)
|
||||||
// spawn.slashBoss(3200, -500)
|
// spawn.blinkBoss(3200, -500)
|
||||||
// spawn.spiderBoss(3200, -500)
|
// spawn.mantisBoss(1700, -500)
|
||||||
// spawn.tetherBoss(1700, -500) //go to actual level?
|
// spawn.tetherBoss(1700, -500) //go to actual level?
|
||||||
|
spawn.revolutionBoss(1900, -500)
|
||||||
|
// spawn.bomberBoss(1400, -500)
|
||||||
|
// spawn.cellBossCulture(1600, -500)
|
||||||
|
|
||||||
|
// spawn.launcherOne(1700, -500)
|
||||||
// for (let i = 0; i < 10; ++i) spawn.bodyRect(1600 + 5, -500, 30, 40);
|
// for (let i = 0; i < 10; ++i) spawn.bodyRect(1600 + 5, -500, 30, 40);
|
||||||
// for (let i = 0; i < 5; i++) spawn.focuser(1900, -500)
|
// for (let i = 0; i < 5; i++) spawn.focuser(1900, -500)
|
||||||
// spawn.slashBoss(1900, -500)
|
// spawn.pulsar(1900, -500)
|
||||||
spawn.pulsar(1900, -500)
|
|
||||||
// spawn.shield(mob[mob.length - 1], 1900, -500, 1);
|
// spawn.shield(mob[mob.length - 1], 1900, -500, 1);
|
||||||
// mob[mob.length - 1].isShielded = true
|
// mob[mob.length - 1].isShielded = true
|
||||||
// spawn.growBossCulture(1200, -500)
|
|
||||||
// spawn.laserTargetingBoss(1600, -400)
|
|
||||||
// spawn.blinkBoss(1600, -500)
|
|
||||||
// spawn.laserTargetingBoss(1700, -120)
|
|
||||||
// spawn.bomberBoss(1400, -500)
|
|
||||||
// spawn.laser(1800, -320)
|
|
||||||
// spawn.laserBombingBoss(1600, -500)
|
|
||||||
// spawn.laserTargetingBoss(1600, -500)
|
|
||||||
// spawn.laserBoss(1600, -500)
|
|
||||||
// spawn.cellBossCulture(1600, -500)
|
|
||||||
// spawn.nodeGroup(1200, -500, "grenadier")
|
|
||||||
// spawn.nodeGroup(1800, -500, "grenadier")
|
|
||||||
// spawn.nodeGroup(1200, 0, "grenadier")
|
// spawn.nodeGroup(1200, 0, "grenadier")
|
||||||
// spawn.blinkBoss(1200, -500)
|
// spawn.blinkBoss(1200, -500)
|
||||||
// spawn.suckerBoss(2900, -500)
|
// spawn.suckerBoss(2900, -500)
|
||||||
|
|||||||
31
js/mob.js
31
js/mob.js
@@ -59,7 +59,7 @@ const mobs = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function applySlow(whom) {
|
function applySlow(whom) {
|
||||||
if (!whom.shield && !whom.isShielded && !m.isBodiesAsleep) {
|
if (!whom.shield && !whom.isShielded && !m.isBodiesAsleep && who.damageReduction > 0) {
|
||||||
if (whom.isBoss) cycles = Math.floor(cycles * 0.25)
|
if (whom.isBoss) cycles = Math.floor(cycles * 0.25)
|
||||||
let i = whom.status.length
|
let i = whom.status.length
|
||||||
while (i--) {
|
while (i--) {
|
||||||
@@ -98,7 +98,7 @@ const mobs = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
statusStun(who, cycles = 180) {
|
statusStun(who, cycles = 180) {
|
||||||
if (!who.shield && !who.isShielded && !m.isBodiesAsleep) {
|
if (!who.shield && !who.isShielded && !m.isBodiesAsleep && who.damageReduction > 0) {
|
||||||
Matter.Body.setVelocity(who, {
|
Matter.Body.setVelocity(who, {
|
||||||
x: who.velocity.x * 0.8,
|
x: who.velocity.x * 0.8,
|
||||||
y: who.velocity.y * 0.8
|
y: who.velocity.y * 0.8
|
||||||
@@ -150,7 +150,7 @@ const mobs = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
statusDoT(who, tickDamage, cycles = 180) {
|
statusDoT(who, tickDamage, cycles = 180) {
|
||||||
if (!who.isShielded && who.alive) {
|
if (!who.isShielded && who.alive && who.damageReduction > 0) {
|
||||||
who.status.push({
|
who.status.push({
|
||||||
effect() {
|
effect() {
|
||||||
if ((simulation.cycle - this.startCycle) % 30 === 0 && !m.isBodiesAsleep) {
|
if ((simulation.cycle - this.startCycle) % 30 === 0 && !m.isBodiesAsleep) {
|
||||||
@@ -579,7 +579,7 @@ const mobs = {
|
|||||||
springAttack() {
|
springAttack() {
|
||||||
// set new values of the ends of the spring constraints
|
// set new values of the ends of the spring constraints
|
||||||
const stepRange = 600
|
const stepRange = 600
|
||||||
if (this.seePlayer.recall && Matter.Query.ray(map, this.position, player.position).length === 0) {
|
if (this.seePlayer.recall && Matter.Query.ray(map, this.position, this.seePlayer.position).length === 0) {
|
||||||
if (!(simulation.cycle % (this.seePlayerFreq * 2))) {
|
if (!(simulation.cycle % (this.seePlayerFreq * 2))) {
|
||||||
const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position))
|
const unit = Vector.normalise(Vector.sub(this.seePlayer.position, this.position))
|
||||||
const goal = Vector.add(this.position, Vector.mult(unit, stepRange))
|
const goal = Vector.add(this.position, Vector.mult(unit, stepRange))
|
||||||
@@ -650,7 +650,7 @@ const mobs = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
//move to a random location
|
//move to a random location
|
||||||
if (!(simulation.cycle % (this.seePlayerFreq * 5))) {
|
if (!(simulation.cycle % (this.seePlayerFreq * 4))) {
|
||||||
best = {
|
best = {
|
||||||
x: null,
|
x: null,
|
||||||
y: null,
|
y: null,
|
||||||
@@ -797,6 +797,27 @@ const mobs = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
invulnerability() {
|
||||||
|
if (this.isInvulnerable) {
|
||||||
|
if (this.invulnerabilityCountDown > 0) {
|
||||||
|
this.invulnerabilityCountDown--
|
||||||
|
//graphics //draw a super shield?
|
||||||
|
ctx.beginPath();
|
||||||
|
let vertices = this.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 = 20;
|
||||||
|
// ctx.fillStyle = `rgba(${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},0.5)`
|
||||||
|
// ctx.fill();
|
||||||
|
ctx.strokeStyle = "rgba(255,255,255,0.4)";
|
||||||
|
ctx.stroke();
|
||||||
|
} else {
|
||||||
|
this.isInvulnerable = false
|
||||||
|
this.damageReduction = this.startingDamageReduction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
grow() {
|
grow() {
|
||||||
if (!m.isBodiesAsleep) {
|
if (!m.isBodiesAsleep) {
|
||||||
if (this.seePlayer.recall) {
|
if (this.seePlayer.recall) {
|
||||||
|
|||||||
@@ -327,7 +327,6 @@ const m = {
|
|||||||
tech.tech[i].name !== "Ψ(t) collapse" &&
|
tech.tech[i].name !== "Ψ(t) collapse" &&
|
||||||
tech.tech[i].name !== "non-unitary operator" &&
|
tech.tech[i].name !== "non-unitary operator" &&
|
||||||
tech.tech[i].name !== "-quantum leap-"
|
tech.tech[i].name !== "-quantum leap-"
|
||||||
|
|
||||||
) {
|
) {
|
||||||
totalTech += tech.tech[i].count
|
totalTech += tech.tech[i].count
|
||||||
tech.tech[i].remove();
|
tech.tech[i].remove();
|
||||||
|
|||||||
@@ -1,6 +1,36 @@
|
|||||||
let powerUp = [];
|
let powerUp = [];
|
||||||
|
|
||||||
const powerUps = {
|
const powerUps = {
|
||||||
|
ejectGraphic(color = "68, 102, 119") {
|
||||||
|
simulation.drawList.push({
|
||||||
|
x: m.pos.x,
|
||||||
|
y: m.pos.y,
|
||||||
|
radius: 100,
|
||||||
|
color: `rgba(${color}, 0.8)`,
|
||||||
|
time: 4
|
||||||
|
});
|
||||||
|
simulation.drawList.push({
|
||||||
|
x: m.pos.x,
|
||||||
|
y: m.pos.y,
|
||||||
|
radius: 75,
|
||||||
|
color: `rgba(${color}, 0.6)`,
|
||||||
|
time: 8
|
||||||
|
});
|
||||||
|
simulation.drawList.push({
|
||||||
|
x: m.pos.x,
|
||||||
|
y: m.pos.y,
|
||||||
|
radius: 50,
|
||||||
|
color: `rgba(${color}, 0.3)`,
|
||||||
|
time: 12
|
||||||
|
});
|
||||||
|
simulation.drawList.push({
|
||||||
|
x: m.pos.x,
|
||||||
|
y: m.pos.y,
|
||||||
|
radius: 25,
|
||||||
|
color: `rgba(${color}, 0.15)`,
|
||||||
|
time: 16
|
||||||
|
});
|
||||||
|
},
|
||||||
orb: {
|
orb: {
|
||||||
research(num = 1) {
|
research(num = 1) {
|
||||||
switch (num) {
|
switch (num) {
|
||||||
@@ -963,8 +993,11 @@ const powerUps = {
|
|||||||
tech.tech[choose].isLost = true;
|
tech.tech[choose].isLost = true;
|
||||||
simulation.updateTechHUD();
|
simulation.updateTechHUD();
|
||||||
m.fieldCDcycle = m.cycle + 30; //disable field so you can't pick up the ejected tech
|
m.fieldCDcycle = m.cycle + 30; //disable field so you can't pick up the ejected tech
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
} else {
|
} else if (tech.tech[choose].count) {
|
||||||
// simulation.makeTextLog(`<div class='circle tech'></div> <strong>${tech.tech[choose].name}</strong> was ejected`, 600) //message about what tech was lost
|
// simulation.makeTextLog(`<div class='circle tech'></div> <strong>${tech.tech[choose].name}</strong> was ejected`, 600) //message about what tech was lost
|
||||||
simulation.makeTextLog(`<span class='color-var'>tech</span>.remove("<span class='color-text'>${tech.tech[choose].name}</span>")`)
|
simulation.makeTextLog(`<span class='color-var'>tech</span>.remove("<span class='color-text'>${tech.tech[choose].name}</span>")`)
|
||||||
|
|
||||||
@@ -978,6 +1011,9 @@ const powerUps = {
|
|||||||
tech.tech[choose].isLost = true;
|
tech.tech[choose].isLost = true;
|
||||||
simulation.updateTechHUD();
|
simulation.updateTechHUD();
|
||||||
m.fieldCDcycle = m.cycle + 30; //disable field so you can't pick up the ejected tech
|
m.fieldCDcycle = m.cycle + 30; //disable field so you can't pick up the ejected tech
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// removeRandomTech() {
|
// removeRandomTech() {
|
||||||
|
|||||||
@@ -397,6 +397,7 @@ const simulation = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tech.isCrouchAmmo) tech.isCrouchAmmo = 1 //this prevents hacking the tech by switching guns
|
if (tech.isCrouchAmmo) tech.isCrouchAmmo = 1 //this prevents hacking the tech by switching guns
|
||||||
|
|
||||||
b.activeGun = b.inventory[b.inventoryGun];
|
b.activeGun = b.inventory[b.inventoryGun];
|
||||||
if (b.guns[b.activeGun].charge) b.guns[b.activeGun].charge = 0; //if switching into foam set charge to 0
|
if (b.guns[b.activeGun].charge) b.guns[b.activeGun].charge = 0; //if switching into foam set charge to 0
|
||||||
simulation.updateGunHUD();
|
simulation.updateGunHUD();
|
||||||
|
|||||||
443
js/spawn.js
443
js/spawn.js
@@ -1,9 +1,12 @@
|
|||||||
//main object for spawning things in a level
|
//main object for spawning things in a level
|
||||||
const spawn = {
|
const spawn = {
|
||||||
nonCollideBossList: ["snakeBoss"], //"cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss", "spawnerBossCulture", "growBossCulture"
|
nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss", "spawnerBossCulture", "growBossCulture"],
|
||||||
// other bosses: suckerBoss, laserBoss, tetherBoss, //these need a particular level to work so they are not included in the random pool
|
// other bosses: suckerBoss, laserBoss, tetherBoss, //these need a particular level to work so they are not included in the random pool
|
||||||
// "shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss",, , "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss", "snakeSpitBoss", "laserBombingBoss", , "slashBoss"
|
randomLevelBoss(x, y, options = [
|
||||||
randomLevelBoss(x, y, options = ["snakeBoss", "powerUpBoss", "blockBoss"]) {
|
"shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss",
|
||||||
|
"powerUpBoss", "powerUpBossBaby", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss",
|
||||||
|
"snakeSpitBoss", "laserBombingBoss", "blockBoss", "revolutionBoss", "mantisBoss"
|
||||||
|
]) {
|
||||||
spawn[options[Math.floor(Math.random() * options.length)]](x, y)
|
spawn[options[Math.floor(Math.random() * options.length)]](x, y)
|
||||||
},
|
},
|
||||||
pickList: ["starter", "starter"],
|
pickList: ["starter", "starter"],
|
||||||
@@ -1165,6 +1168,64 @@ const spawn = {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
powerUpBossBaby(x, y, vertices = 9, radius = 70) {
|
||||||
|
mobs.spawn(x, y, vertices, radius, "transparent");
|
||||||
|
let me = mob[mob.length - 1];
|
||||||
|
me.isBoss = true;
|
||||||
|
me.frictionAir = 0.006
|
||||||
|
me.seeAtDistance2 = 1000000;
|
||||||
|
me.accelMag = 0.0007 * simulation.accelScale;
|
||||||
|
Matter.Body.setDensity(me, 0.0008); //normal is 0.001
|
||||||
|
me.collisionFilter.mask = cat.bullet | cat.player | cat.body | cat.map
|
||||||
|
me.memory = Infinity;
|
||||||
|
me.seePlayerFreq = 30
|
||||||
|
me.lockedOn = null;
|
||||||
|
if (vertices === 9) {
|
||||||
|
//on primary spawn
|
||||||
|
powerUps.spawnBossPowerUp(me.position.x, me.position.y)
|
||||||
|
powerUps.spawn(me.position.x, me.position.y, "heal");
|
||||||
|
powerUps.spawn(me.position.x, me.position.y, "ammo");
|
||||||
|
} else if (!m.isCloak) {
|
||||||
|
me.foundPlayer();
|
||||||
|
}
|
||||||
|
me.onHit = function() { //run this function on hitting player
|
||||||
|
if (powerUps.ejectTech()) {
|
||||||
|
powerUps.ejectGraphic("150, 138, 255");
|
||||||
|
powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "ammo");
|
||||||
|
powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "research");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
me.onDeath = function() {
|
||||||
|
this.leaveBody = false;
|
||||||
|
if (vertices > 3) {
|
||||||
|
this.isDropPowerUp = false;
|
||||||
|
spawn.powerUpBossBaby(this.position.x, this.position.y, vertices - 1)
|
||||||
|
Matter.Body.setVelocity(mob[mob.length - 1], {
|
||||||
|
x: this.velocity.x,
|
||||||
|
y: this.velocity.y
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for (let i = 0; i < powerUp.length; i++) powerUp[i].collisionFilter.mask = cat.map | cat.powerUp
|
||||||
|
};
|
||||||
|
me.damageReduction = 0.15 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
|
||||||
|
me.do = function() {
|
||||||
|
// this.armor();
|
||||||
|
this.stroke = `hsl(0,0%,${80 + 25 * Math.sin(simulation.cycle * 0.01)}%)`
|
||||||
|
|
||||||
|
//steal all power ups
|
||||||
|
for (let i = 0; i < Math.min(powerUp.length, this.vertices.length); i++) {
|
||||||
|
powerUp[i].collisionFilter.mask = 0
|
||||||
|
Matter.Body.setPosition(powerUp[i], this.vertices[i])
|
||||||
|
Matter.Body.setVelocity(powerUp[i], {
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.seePlayerByHistory();
|
||||||
|
this.attraction();
|
||||||
|
this.checkStatus();
|
||||||
|
};
|
||||||
|
},
|
||||||
powerUpBoss(x, y, vertices = 9, radius = 130) {
|
powerUpBoss(x, y, vertices = 9, radius = 130) {
|
||||||
mobs.spawn(x, y, vertices, radius, "transparent");
|
mobs.spawn(x, y, vertices, radius, "transparent");
|
||||||
let me = mob[mob.length - 1];
|
let me = mob[mob.length - 1];
|
||||||
@@ -1186,9 +1247,11 @@ const spawn = {
|
|||||||
me.foundPlayer();
|
me.foundPlayer();
|
||||||
}
|
}
|
||||||
me.onHit = function() { //run this function on hitting player
|
me.onHit = function() { //run this function on hitting player
|
||||||
powerUps.ejectTech()
|
if (powerUps.ejectTech()) {
|
||||||
powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "ammo");
|
powerUps.ejectGraphic("150, 138, 255");
|
||||||
powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "research");
|
powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "ammo");
|
||||||
|
powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "research");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
me.onDeath = function() {
|
me.onDeath = function() {
|
||||||
this.leaveBody = false;
|
this.leaveBody = false;
|
||||||
@@ -1222,6 +1285,7 @@ const spawn = {
|
|||||||
this.checkStatus();
|
this.checkStatus();
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
// chaser(x, y, radius = 35 + Math.ceil(Math.random() * 40)) {
|
// chaser(x, y, radius = 35 + Math.ceil(Math.random() * 40)) {
|
||||||
// mobs.spawn(x, y, 8, radius, "rgb(255,150,100)"); //"#2c9790"
|
// mobs.spawn(x, y, 8, radius, "rgb(255,150,100)"); //"#2c9790"
|
||||||
// let me = mob[mob.length - 1];
|
// let me = mob[mob.length - 1];
|
||||||
@@ -1784,6 +1848,277 @@ const spawn = {
|
|||||||
spawn.groupShield(targets, x, y, sideLength + 1 * radius + nodes * 5 - 25);
|
spawn.groupShield(targets, x, y, sideLength + 1 * radius + nodes * 5 - 25);
|
||||||
spawn.allowShields = true;
|
spawn.allowShields = true;
|
||||||
},
|
},
|
||||||
|
mantisBoss(x, y, radius = 35) {
|
||||||
|
mobs.spawn(x, y, 5, radius, "#6ba");
|
||||||
|
let me = mob[mob.length - 1];
|
||||||
|
me.babyList = [] //list of mobs that are apart of this boss
|
||||||
|
Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger and damage on collision
|
||||||
|
me.damageReduction = 0.1 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) //normal is 1, most bosses have 0.25
|
||||||
|
me.isBoss = true;
|
||||||
|
me.friction = 0;
|
||||||
|
me.frictionAir = 0.0067;
|
||||||
|
me.g = 0.0002; //required if using this.gravity
|
||||||
|
me.seePlayerFreq = 300;
|
||||||
|
const springStiffness = 0.0004; //simulation.difficulty
|
||||||
|
const springDampening = 0.005;
|
||||||
|
|
||||||
|
me.springTarget = {
|
||||||
|
x: me.position.x,
|
||||||
|
y: me.position.y
|
||||||
|
};
|
||||||
|
const len = cons.length;
|
||||||
|
cons[len] = Constraint.create({
|
||||||
|
pointA: me.springTarget,
|
||||||
|
bodyB: me,
|
||||||
|
stiffness: springStiffness,
|
||||||
|
damping: springDampening
|
||||||
|
});
|
||||||
|
Composite.add(engine.world, cons[cons.length - 1]);
|
||||||
|
cons[len].length = 100 + 1.5 * radius;
|
||||||
|
me.cons = cons[len];
|
||||||
|
me.springTarget2 = { x: me.position.x, y: me.position.y };
|
||||||
|
const len2 = cons.length;
|
||||||
|
cons[len2] = Constraint.create({
|
||||||
|
pointA: me.springTarget2,
|
||||||
|
bodyB: me,
|
||||||
|
stiffness: springStiffness,
|
||||||
|
damping: springDampening,
|
||||||
|
length: 0
|
||||||
|
});
|
||||||
|
Composite.add(engine.world, cons[cons.length - 1]);
|
||||||
|
cons[len2].length = 100 + 1.5 * radius;
|
||||||
|
me.cons2 = cons[len2];
|
||||||
|
|
||||||
|
me.startingDamageReduction = me.damageReduction
|
||||||
|
me.isInvulnerable = false
|
||||||
|
me.invulnerabilityCountDown = 0
|
||||||
|
|
||||||
|
me.do = function() {
|
||||||
|
this.checkStatus();
|
||||||
|
this.gravity();
|
||||||
|
//draw the two dots on the end of the springs
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(this.cons.pointA.x, this.cons.pointA.y, 6, 0, 2 * Math.PI);
|
||||||
|
ctx.arc(this.cons2.pointA.x, this.cons2.pointA.y, 6, 0, 2 * Math.PI);
|
||||||
|
ctx.fillStyle = "#222";
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
this.seePlayerCheck()
|
||||||
|
// this.seePlayerByHistory()
|
||||||
|
if (this.isInvulnerable) {
|
||||||
|
ctx.beginPath();
|
||||||
|
let vertices = this.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);
|
||||||
|
for (let i = 0; i < this.babyList.length; i++) {
|
||||||
|
if (this.babyList[i].alive) {
|
||||||
|
let vertices = this.babyList[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 = 20;
|
||||||
|
ctx.strokeStyle = "rgba(255,255,255,0.7)";
|
||||||
|
ctx.stroke();
|
||||||
|
} else if (this.invulnerabilityCountDown > 0) {
|
||||||
|
this.invulnerabilityCountDown--
|
||||||
|
} else {
|
||||||
|
this.isInvulnerable = true
|
||||||
|
this.startingDamageReduction = this.damageReduction
|
||||||
|
this.damageReduction = 0
|
||||||
|
for (let i = 0; i < this.babyList.length; i++) {
|
||||||
|
if (this.babyList[i].alive) {
|
||||||
|
this.babyList[i].isInvulnerable = true
|
||||||
|
this.babyList[i].damageReduction = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// set new values of the ends of the spring constraints
|
||||||
|
const stepRange = 1200
|
||||||
|
if (this.seePlayer.recall && Matter.Query.ray(map, this.position, this.seePlayer.position).length === 0) {
|
||||||
|
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.cons.length = -200;
|
||||||
|
this.cons2.length = 100 + 1.5 * this.radius;
|
||||||
|
|
||||||
|
this.isInvulnerable = false
|
||||||
|
this.invulnerabilityCountDown = 40 + Math.max(0, 70 - simulation.difficulty * 2)
|
||||||
|
this.damageReduction = this.startingDamageReduction
|
||||||
|
for (let i = 0; i < this.babyList.length; i++) {
|
||||||
|
if (this.babyList[i].alive) this.babyList[i].damageReduction = this.startingDamageReduction
|
||||||
|
}
|
||||||
|
} 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.cons.length = 100 + 1.5 * this.radius;
|
||||||
|
this.cons2.length = -200;
|
||||||
|
|
||||||
|
this.isInvulnerable = false
|
||||||
|
this.invulnerabilityCountDown = 40 + Math.max(0, 70 - simulation.difficulty * 2)
|
||||||
|
this.damageReduction = this.startingDamageReduction
|
||||||
|
for (let i = 0; i < this.babyList.length; i++) {
|
||||||
|
if (this.babyList[i].alive) this.babyList[i].damageReduction = this.startingDamageReduction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.torque = this.lookTorque * this.inertia;
|
||||||
|
//spring to random place on map
|
||||||
|
const vertexCollision = function(v1, v1End, domain) {
|
||||||
|
for (let i = 0; i < domain.length; ++i) {
|
||||||
|
let vertices = domain[i].vertices;
|
||||||
|
const len = vertices.length - 1;
|
||||||
|
for (let j = 0; j < len; j++) {
|
||||||
|
results = simulation.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]);
|
||||||
|
if (results.onLine1 && results.onLine2) {
|
||||||
|
const dx = v1.x - results.x;
|
||||||
|
const dy = v1.y - results.y;
|
||||||
|
const dist2 = dx * dx + dy * dy;
|
||||||
|
if (dist2 < best.dist2 && (!domain[i].mob || domain[i].alive)) {
|
||||||
|
best = {
|
||||||
|
x: results.x,
|
||||||
|
y: results.y,
|
||||||
|
dist2: dist2,
|
||||||
|
who: domain[i],
|
||||||
|
v1: vertices[j],
|
||||||
|
v2: vertices[j + 1]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results = simulation.checkLineIntersection(v1, v1End, vertices[0], vertices[len]);
|
||||||
|
if (results.onLine1 && results.onLine2) {
|
||||||
|
const dx = v1.x - results.x;
|
||||||
|
const dy = v1.y - results.y;
|
||||||
|
const dist2 = dx * dx + dy * dy;
|
||||||
|
if (dist2 < best.dist2) {
|
||||||
|
best = {
|
||||||
|
x: results.x,
|
||||||
|
y: results.y,
|
||||||
|
dist2: dist2,
|
||||||
|
who: domain[i],
|
||||||
|
v1: vertices[0],
|
||||||
|
v2: vertices[len]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//move to a random location
|
||||||
|
if (!(simulation.cycle % (this.seePlayerFreq))) {
|
||||||
|
best = {
|
||||||
|
x: null,
|
||||||
|
y: null,
|
||||||
|
dist2: Infinity,
|
||||||
|
who: null,
|
||||||
|
v1: null,
|
||||||
|
v2: null
|
||||||
|
};
|
||||||
|
const seeRange = 3000;
|
||||||
|
const look = {
|
||||||
|
x: this.position.x + seeRange * Math.cos(this.angle),
|
||||||
|
y: this.position.y + seeRange * Math.sin(this.angle)
|
||||||
|
};
|
||||||
|
vertexCollision(this.position, look, map);
|
||||||
|
if (best.dist2 != Infinity) {
|
||||||
|
this.springTarget.x = best.x;
|
||||||
|
this.springTarget.y = best.y;
|
||||||
|
this.cons.length = 100 + 1.5 * this.radius;
|
||||||
|
this.cons2.length = 100 + 1.5 * this.radius;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
me.onDeath = function() {
|
||||||
|
this.removeCons();
|
||||||
|
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
|
||||||
|
for (let i = 0; i < this.babyList.length; i++) {
|
||||||
|
if (this.babyList[i].alive) {
|
||||||
|
this.babyList[i].isInvulnerable = false
|
||||||
|
this.babyList[i].damageReduction = this.startingDamageReduction
|
||||||
|
this.babyList[i].collisionFilter.mask = cat.bullet | cat.player | cat.map | cat.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const sideLength = 120 // distance between each node mob
|
||||||
|
const nodes = 3
|
||||||
|
const angle = 2 * Math.PI / nodes
|
||||||
|
spawn.allowShields = false; //don't want shields on individual mobs, it messes with the constraints
|
||||||
|
for (let i = 0; i < nodes; ++i) {
|
||||||
|
spawn.striker(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), 20, 12);
|
||||||
|
const babyMob = mob[mob.length - 1]
|
||||||
|
me.babyList.push(babyMob)
|
||||||
|
babyMob.fill = "rgb(68, 102, 119)"
|
||||||
|
babyMob.isBoss = true;
|
||||||
|
// Matter.Body.setDensity(babyMob, 0.001); //extra dense //normal is 0.001 //makes effective life much larger and increases damage
|
||||||
|
babyMob.damageReduction = 0.1 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
|
||||||
|
babyMob.collisionFilter.mask = cat.bullet | cat.player //can't touch other mobs //cat.map | cat.body |
|
||||||
|
babyMob.delay = 60 + 50 * simulation.CDScale;
|
||||||
|
babyMob.strikeRange = 600
|
||||||
|
babyMob.onHit = function() {
|
||||||
|
this.cd = simulation.cycle + this.delay;
|
||||||
|
//dislodge ammo
|
||||||
|
if (b.inventory.length) {
|
||||||
|
let isRemovedAmmo = false
|
||||||
|
const numRemoved = 3
|
||||||
|
for (let j = 0; j < numRemoved; j++) {
|
||||||
|
for (let i = 0; i < b.inventory.length; i++) {
|
||||||
|
const gun = b.guns[b.inventory[i]]
|
||||||
|
if (gun.ammo > 0 && gun.ammo !== Infinity) {
|
||||||
|
gun.ammo -= Math.ceil((0.45 * Math.random() + 0.45 * Math.random()) * gun.ammoPack) //Math.ceil(Math.random() * target.ammoPack)
|
||||||
|
if (gun.ammo < 0) gun.ammo = 0
|
||||||
|
isRemovedAmmo = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isRemovedAmmo) {
|
||||||
|
simulation.updateGunHUD();
|
||||||
|
for (let j = 0; j < numRemoved; j++) powerUps.directSpawn(this.position.x + 10 * Math.random(), this.position.y + 10 * Math.random(), "ammo");
|
||||||
|
powerUps.ejectGraphic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const stiffness = 0.01
|
||||||
|
const damping = 0.1
|
||||||
|
for (let i = 1; i < nodes; ++i) { //attach to center mob
|
||||||
|
consBB[consBB.length] = Constraint.create({
|
||||||
|
bodyA: mob[mob.length - i],
|
||||||
|
bodyB: mob[mob.length - i - 1],
|
||||||
|
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],
|
||||||
|
stiffness: stiffness,
|
||||||
|
damping: damping
|
||||||
|
});
|
||||||
|
Composite.add(engine.world, consBB[consBB.length - 1]);
|
||||||
|
|
||||||
|
|
||||||
|
for (let i = 0; i < nodes; ++i) { //attach to center mob
|
||||||
|
consBB[consBB.length] = Constraint.create({
|
||||||
|
bodyA: me,
|
||||||
|
bodyB: mob[mob.length - i - 1],
|
||||||
|
stiffness: stiffness,
|
||||||
|
damping: damping
|
||||||
|
});
|
||||||
|
Composite.add(engine.world, consBB[consBB.length - 1]);
|
||||||
|
}
|
||||||
|
spawn.allowShields = true;
|
||||||
|
},
|
||||||
// timeSkipBoss(x, y, radius = 55) {
|
// timeSkipBoss(x, y, radius = 55) {
|
||||||
// mobs.spawn(x, y, 6, radius, '#000');
|
// mobs.spawn(x, y, 6, radius, '#000');
|
||||||
// let me = mob[mob.length - 1];
|
// let me = mob[mob.length - 1];
|
||||||
@@ -2358,12 +2693,13 @@ const spawn = {
|
|||||||
me.memory = 240
|
me.memory = 240
|
||||||
me.seePlayerFreq = 60
|
me.seePlayerFreq = 60
|
||||||
me.blinkRange = 235
|
me.blinkRange = 235
|
||||||
if (false && 0.5 < Math.random()) {
|
if (0.5 < Math.random()) {
|
||||||
me.grenadeDelay = 260
|
me.grenadeDelay = 260
|
||||||
|
me.blinkRange *= 1.5
|
||||||
} else {
|
} else {
|
||||||
me.grenadeDelay = 100
|
me.grenadeDelay = 100
|
||||||
}
|
}
|
||||||
me.pulseRadius = 1.4 * Math.min(550, 220 + simulation.difficulty * 4)
|
me.pulseRadius = 1.5 * Math.min(550, 200 + simulation.difficulty * 2)
|
||||||
me.delay = 30 + 35 * simulation.CDScale;
|
me.delay = 30 + 35 * simulation.CDScale;
|
||||||
me.nextBlinkCycle = me.delay;
|
me.nextBlinkCycle = me.delay;
|
||||||
spawn.shield(me, x, y, 1);
|
spawn.shield(me, x, y, 1);
|
||||||
@@ -2919,8 +3255,9 @@ const spawn = {
|
|||||||
me.g = 0.00015; //required if using this.gravity
|
me.g = 0.00015; //required if using this.gravity
|
||||||
me.frictionStatic = 0;
|
me.frictionStatic = 0;
|
||||||
me.friction = 0;
|
me.friction = 0;
|
||||||
me.delay = 90 * simulation.CDScale;
|
me.delay = 30 + 60 * simulation.CDScale;
|
||||||
me.cd = Infinity;
|
me.cd = Infinity;
|
||||||
|
me.strikeRange = 300
|
||||||
Matter.Body.rotate(me, Math.PI * 0.1);
|
Matter.Body.rotate(me, Math.PI * 0.1);
|
||||||
spawn.shield(me, x, y);
|
spawn.shield(me, x, y);
|
||||||
me.onDamage = function() {
|
me.onDamage = function() {
|
||||||
@@ -2953,7 +3290,7 @@ const spawn = {
|
|||||||
if (distMag < 400) {
|
if (distMag < 400) {
|
||||||
Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), distMag - 20 - radius));
|
Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), distMag - 20 - radius));
|
||||||
} else {
|
} else {
|
||||||
Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), 300));
|
Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), this.strikeRange));
|
||||||
}
|
}
|
||||||
ctx.lineTo(this.position.x, this.position.y);
|
ctx.lineTo(this.position.x, this.position.y);
|
||||||
ctx.lineWidth = radius * 2.1;
|
ctx.lineWidth = radius * 2.1;
|
||||||
@@ -2966,7 +3303,7 @@ const spawn = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
slashBoss(x, y, radius = 70) {
|
revolutionBoss(x, y, radius = 70) {
|
||||||
const sides = 9 + Math.floor(Math.min(12, 0.2 * simulation.difficulty))
|
const sides = 9 + Math.floor(Math.min(12, 0.2 * simulation.difficulty))
|
||||||
const coolBends = [-1.8, 0, 0, 0.9, 1.2]
|
const coolBends = [-1.8, 0, 0, 0.9, 1.2]
|
||||||
const bendFactor = coolBends[Math.floor(Math.random() * coolBends.length)];
|
const bendFactor = coolBends[Math.floor(Math.random() * coolBends.length)];
|
||||||
@@ -2979,7 +3316,7 @@ const spawn = {
|
|||||||
me.laserAngle = 0;
|
me.laserAngle = 0;
|
||||||
me.swordDamage = 0.0025 * simulation.dmgScale
|
me.swordDamage = 0.0025 * simulation.dmgScale
|
||||||
|
|
||||||
spawn.shield(me, x, y, 1);
|
// spawn.shield(me, x, y, 1);
|
||||||
Matter.Body.setDensity(me, 0.005); //extra dense //normal is 0.001 //makes effective life much larger
|
Matter.Body.setDensity(me, 0.005); //extra dense //normal is 0.001 //makes effective life much larger
|
||||||
me.damageReduction = 0.11 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
|
me.damageReduction = 0.11 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
|
||||||
me.isBoss = true;
|
me.isBoss = true;
|
||||||
@@ -2989,42 +3326,62 @@ const spawn = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//invulnerability every 1/4 fraction of life lost
|
||||||
|
//required setup for invulnerable
|
||||||
|
// me.isInvulnerable = false
|
||||||
|
// me.isNextInvulnerability = 0.75
|
||||||
|
// me.invulnerabilityCountDown = 0
|
||||||
|
// me.invulnerable = function() {
|
||||||
|
// if (this.health < this.isNextInvulnerability) {
|
||||||
|
// this.isNextInvulnerability = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
|
||||||
|
// this.isInvulnerable = true
|
||||||
|
// this.startingDamageReduction = this.damageReduction
|
||||||
|
// this.damageReduction = 0
|
||||||
|
// this.invulnerabilityCountDown = 240
|
||||||
|
// }
|
||||||
|
// if (this.isInvulnerable) {
|
||||||
|
// if (this.invulnerabilityCountDown > 0) {
|
||||||
|
// this.invulnerabilityCountDown--
|
||||||
|
// //graphics //draw a super shield?
|
||||||
|
// ctx.beginPath();
|
||||||
|
// let vertices = this.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 = 20;
|
||||||
|
// // ctx.fillStyle = `rgba(${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},0.5)`
|
||||||
|
// // ctx.fill();
|
||||||
|
// ctx.strokeStyle = "rgba(255,255,255,0.7)";
|
||||||
|
// ctx.stroke();
|
||||||
|
// } else {
|
||||||
|
// this.isInvulnerable = false
|
||||||
|
// this.damageReduction = this.startingDamageReduction
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
me.startingDamageReduction = me.damageReduction
|
//invulnerable every other revolution
|
||||||
me.isInvulnerable = false
|
me.isInvulnerable = false
|
||||||
me.isNextInvulnerability = 0.75
|
|
||||||
me.invulnerabilityCountDown = 0
|
|
||||||
me.invulnerable = function() {
|
me.invulnerable = function() {
|
||||||
if (this.health < this.isNextInvulnerability) {
|
if (this.laserAngle % (4 * Math.PI) > 2 * Math.PI) {
|
||||||
this.isNextInvulnerability = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
|
if (!this.isInvulnerable) {
|
||||||
this.isInvulnerable = true
|
this.isInvulnerable = true
|
||||||
this.damageReduction = 0
|
this.startingDamageReduction = this.damageReduction
|
||||||
this.invulnerabilityCountDown = 180
|
this.damageReduction = 0
|
||||||
|
}
|
||||||
|
} else if (this.isInvulnerable) {
|
||||||
|
this.isInvulnerable = false
|
||||||
|
this.damageReduction = this.startingDamageReduction
|
||||||
}
|
}
|
||||||
if (this.isInvulnerable) {
|
if (this.isInvulnerable) {
|
||||||
if (this.invulnerabilityCountDown > 0) {
|
ctx.beginPath();
|
||||||
this.invulnerabilityCountDown--
|
let vertices = this.vertices;
|
||||||
//graphics //draw a super shield?
|
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.beginPath();
|
ctx.lineTo(vertices[0].x, vertices[0].y);
|
||||||
|
ctx.lineWidth = 20;
|
||||||
let vertices = this.vertices;
|
ctx.strokeStyle = "rgba(255,255,255,0.7)";
|
||||||
ctx.moveTo(vertices[0].x, vertices[0].y);
|
ctx.stroke();
|
||||||
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 = 20;
|
|
||||||
// ctx.fillStyle = `rgba(${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},${Math.floor(255 * Math.random())},0.5)`
|
|
||||||
// ctx.fill();
|
|
||||||
ctx.strokeStyle = "rgba(255,255,255,0.4)";
|
|
||||||
ctx.stroke();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.isInvulnerable = false
|
|
||||||
this.damageReduction = this.startingDamageReduction
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
js/tech.js
12
js/tech.js
@@ -1980,9 +1980,7 @@ const tech = {
|
|||||||
requires: "",
|
requires: "",
|
||||||
effect() {
|
effect() {
|
||||||
tech.isDroneOnDamage = true;
|
tech.isDroneOnDamage = true;
|
||||||
for (let i = 0; i < 4; i++) {
|
// for (let i = 0; i < 4; i++) b.drone()
|
||||||
b.drone() //spawn drone
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
remove() {
|
remove() {
|
||||||
tech.isDroneOnDamage = false;
|
tech.isDroneOnDamage = false;
|
||||||
@@ -5028,9 +5026,9 @@ const tech = {
|
|||||||
frequency: 1,
|
frequency: 1,
|
||||||
frequencyDefault: 1,
|
frequencyDefault: 1,
|
||||||
allowed() {
|
allowed() {
|
||||||
return tech.haveGunCheck("drones", false)
|
return tech.haveGunCheck("drones", false) && !tech.isDroneRespawn && tech.isBulletsLastLonger === 1
|
||||||
},
|
},
|
||||||
requires: "drones",
|
requires: "drones, not drone repair, anti-shear topology",
|
||||||
effect() {
|
effect() {
|
||||||
const num = 8
|
const num = 8
|
||||||
tech.isForeverDrones += num
|
tech.isForeverDrones += num
|
||||||
@@ -5385,9 +5383,9 @@ const tech = {
|
|||||||
isBot: true,
|
isBot: true,
|
||||||
isBotTech: true,
|
isBotTech: true,
|
||||||
isNonRefundable: true,
|
isNonRefundable: true,
|
||||||
requires: "foam gun, not bot upgrades NOT EXPERIMENT MODE,",
|
requires: "foam gun, NOT EXPERIMENT MODE, bot upgrades, fractionation, quantum foam",
|
||||||
allowed() {
|
allowed() {
|
||||||
return tech.haveGunCheck("foam", false) && !b.hasBotUpgrade()
|
return tech.haveGunCheck("foam", false) && !b.hasBotUpgrade() && !tech.isAmmoFoamSize && !tech.foamFutureFire
|
||||||
},
|
},
|
||||||
effect() {
|
effect() {
|
||||||
tech.giveTech("foam-bot upgrade")
|
tech.giveTech("foam-bot upgrade")
|
||||||
|
|||||||
@@ -435,7 +435,7 @@ summary {
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #ecf0f3;
|
background-color: #e8edf0;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity 3s;
|
transition: opacity 3s;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|||||||
41
todo.txt
41
todo.txt
@@ -1,15 +1,43 @@
|
|||||||
******************************************************** NEXT PATCH **************************************************
|
******************************************************** NEXT PATCH **************************************************
|
||||||
|
|
||||||
several tech now have fewer requirements to unlock
|
|
||||||
some normal tech is now considered gun tech (mostly explosion stuff)
|
mantisBoss: 3 punching mobs, eject your ammo when you get punched
|
||||||
snakeBoss tails, stay attached to each other
|
invulnerable except for 1 second after moving
|
||||||
"snakeBoss", "blockBoss", "powerupBoss" are now the only bosses
|
|
||||||
|
powerUpBossBaby: smaller, cuter, faster, can't move through walls
|
||||||
|
|
||||||
|
slashBoss renamed revolutionBoss
|
||||||
|
invulnerable every other revolution of it's blades
|
||||||
|
|
||||||
|
new mob state: invulnerable - immune to damage and status effects (stun, dots, freeze)
|
||||||
|
damage and harm circle graphic size have been made more consistent
|
||||||
|
|
||||||
bug fixes
|
bug fixes
|
||||||
|
|
||||||
|
|
||||||
******************************************************** TODO ********************************************************
|
******************************************************** TODO ********************************************************
|
||||||
|
|
||||||
suggestion: quasarBoss: inverted pulsar boss that hits everything except where its aiming
|
history vision messes up when drones hit boss?
|
||||||
|
for babypowerupboss
|
||||||
|
|
||||||
|
some boss mobs need invulnerability phases
|
||||||
|
powerUpBoss after death?
|
||||||
|
nerf powerup boss health or acceleration to balance
|
||||||
|
growboss
|
||||||
|
after one dies
|
||||||
|
|
||||||
|
electric motors: increases movement speed and jump height, but jumping and moving costs energy
|
||||||
|
overwrite the key event listeners?
|
||||||
|
JUNK tech?
|
||||||
|
|
||||||
|
make the shields that shieldBoss adds twice as damage resistant
|
||||||
|
|
||||||
|
mob that fires bullets in 4,5,6,7 different directions at once, no aiming
|
||||||
|
|
||||||
|
bug once: switching from shotgun to harpoon somehow set b.activeGun to not defined
|
||||||
|
https://discord.com/channels/645222059647172618/646505973610971165/919116288008290324
|
||||||
|
|
||||||
|
quasarBoss: inverted pulsar boss that hits everything except where its aiming
|
||||||
|
|
||||||
pulsar mobs retarget too easily
|
pulsar mobs retarget too easily
|
||||||
also they drift around too much
|
also they drift around too much
|
||||||
@@ -18,9 +46,6 @@ intro map: diegeticly draw a mouse with field highlighted
|
|||||||
also indicate space?
|
also indicate space?
|
||||||
dynamically adjust drawing after picking up a gun
|
dynamically adjust drawing after picking up a gun
|
||||||
|
|
||||||
some boss mobs need invulnerability phases
|
|
||||||
maybe trigger immunity to damage for 5-10s after taking the first hit?
|
|
||||||
|
|
||||||
|
|
||||||
increase mass and movement speed at the same time
|
increase mass and movement speed at the same time
|
||||||
increase jump differently because it scales extra with mass
|
increase jump differently because it scales extra with mass
|
||||||
|
|||||||
Reference in New Issue
Block a user