4 community levels

new community levels: (you can enable community maps in the settings)
  rings by thatLittleFrog
  flappyGon by Digin
  trial by Cirryn and Tarantula Hawk
  arena level updated by Whyisthisnotavalable

difficulty scaling:  0.84->0.85x player damage per level
research spawn per level is no longer in the difficulty settings
  instead players get 1 research for only the first few levels
cell boss has less health at high difficulty

converted JUNK tech to additive, instead of the multiplicative
  makes the first JUNK you take do the same, but if you take too much you can get to 100%
right aligned some text in tech descriptions
added some circles to the in-game console messages

renamed slow light -> delayed-choice - a single 0.4 second delayed 0.7x damage laser beam
  also now works with reflection
plasma torch field gets 1.5x damage by default
molecular assembler coupling 0.8->0.6 energy per second
nail-bot upgrade 5->4x fire rate
foam-bot upgrade 3->2.5x size and fire rate
sound-bot upgrade 2.5->2x fire rate, damage, 1->2x wave packet length
boom-bot upgrade reduced range, bot acceleration
orbital-bot upgrade 1.5->2x radius
perimeter defense 0.95->0.96x damage taken per bot
network effect 1.05->1.04x damage per bot
tech: working mass - cleaned up physics and logic a bit
negative feedback scales with health below maxHealth, not health below 100
  1.007->1.006x damage per missing health
homeostasis scales with missing health, not health below 100
  limit of 0.2x at 0 health
This commit is contained in:
landgreen
2024-06-20 19:13:51 -07:00
parent 1903b9e938
commit 5e12cea685
10 changed files with 2181 additions and 881 deletions

View File

@@ -553,17 +553,18 @@ const m = {
if (tech.isHarmMACHO) dmg *= tech.isMoveMACHO ? 0.3 : 0.4
if (tech.isImmortal) dmg *= 0.7
if (m.fieldMode === 0 || m.fieldMode === 3) dmg *= 0.973 ** m.coupling
if (tech.isLowHealthDefense) dmg *= 1 - Math.max(0, 1 - m.health) * 0.8
if (tech.isHarmReduceNoKill && m.lastKillCycle + 300 < m.cycle) dmg *= 0.3
if (tech.isAddBlockMass && m.isHolding) dmg *= 0.1
if (tech.isSpeedHarm && (tech.speedAdded + player.speed) > 0.1) dmg *= 1 - Math.min((tech.speedAdded + player.speed) * 0.0193, 0.8) //capped at speed of 55
if (tech.isHarmReduce && input.field) dmg *= 0.1
if (tech.isNeutronium && input.field && m.fieldCDcycle < m.cycle) dmg *= 0.05
if (tech.isBotArmor) dmg *= 0.95 ** b.totalBots()
if (tech.isBotArmor) dmg *= 0.96 ** b.totalBots()
if (tech.isHarmArmor && m.lastHarmCycle + 600 > m.cycle) dmg *= 0.3;
if (tech.isNoFireDefense && m.cycle > m.fireCDcycle + 120) dmg *= 0.3
if (tech.isTurret && m.crouch) dmg *= 0.3;
if (tech.isFirstDer && b.inventory[0] === b.activeGun) dmg *= 0.85 ** b.inventory.length
// if (tech.isLowHealthDefense) dmg *= Math.pow(0.3, Math.max(0, (tech.isEnergyHealth ? m.maxEnergy - m.energy : m.maxHealth - m.health)))
if (tech.isLowHealthDefense) dmg *= Math.pow(0.2, Math.max(0, 1 - (tech.isEnergyHealth ? m.energy / m.maxEnergy : m.health / m.maxHealth)))
// return tech.isEnergyHealth ? Math.pow(dmg, 0.7) : dmg //defense has less effect
// dmg *= m.fieldHarmReduction
return dmg * m.fieldHarmReduction
@@ -2115,7 +2116,7 @@ const m = {
isFieldActive: false,
fieldRange: 155,
fieldShieldingScale: 1,
// fieldDamage: 1,
fieldDamage: 1,
isSneakAttack: false,
lastHit: 0, //stores value of last damage player took above a threshold, in m.damage
sneakAttackCycle: 0,
@@ -2152,6 +2153,7 @@ const m = {
m.eyeFillColor = m.fieldMeterColor
m.fieldShieldingScale = 1;
m.fieldBlockCD = 10;
m.fieldDamage = 1
m.fieldHarmReduction = 1;
m.lastHit = 0
m.isSneakAttack = false
@@ -2241,7 +2243,7 @@ const m = {
} else {
m.fieldRegen = 0.001 //6 energy per second
}
if (m.fieldMode === 0 || m.fieldMode === 4) m.fieldRegen += 0.000133 * m.coupling
if (m.fieldMode === 0 || m.fieldMode === 4) m.fieldRegen += 0.0001 * m.coupling
if (tech.isTimeCrystals) {
m.fieldRegen *= 2.5
} else if (tech.isGroundState) {
@@ -2867,7 +2869,7 @@ const m = {
case 3: //negative mass
return `<strong>${(0.973 ** couple).toFixed(2)}x</strong> <strong class='color-defense'>damage taken</strong>`
case 4: //assembler
return `<strong>+${(0.8 * couple).toFixed(1)}</strong> <strong class='color-f'>energy</strong> per second`
return `<strong>+${(0.6 * couple).toFixed(1)}</strong> <strong class='color-f'>energy</strong> per second`
case 5: //plasma
return `<strong>${(1 + 0.015 * couple).toFixed(3)}x</strong> <strong class='color-d'>damage</strong>`
case 6: //time dilation
@@ -2883,7 +2885,7 @@ const m = {
}
},
couplingChange(change = 0) {
if (change > 0 && level.onLevel !== -1) simulation.makeTextLog(`m.coupling <span class='color-symbol'>+=</span> ${change}`, 60); //level.onLevel !== -1 means not on lore level
if (change > 0 && level.onLevel !== -1) simulation.makeTextLog(`<div class="coupling-circle"></div> m.coupling <span class='color-symbol'>+=</span> ${change}`, 60); //level.onLevel !== -1 means not on lore level
m.coupling += change
if (m.coupling < 0) {
//look for coupling power ups on this level and remove them to prevent exploiting tech ejections
@@ -2921,7 +2923,7 @@ const m = {
document.getElementById("field").innerHTML = m.fieldUpgrades[index].name
m.setHoldDefaults();
m.fieldUpgrades[index].effect();
simulation.makeTextLog(`<span class='color-var'>m</span>.setField("<span class='color-text'>${m.fieldUpgrades[m.fieldMode].name}</span>")`);
simulation.makeTextLog(`<div class="circle-grid field"></div> &nbsp; <span class='color-var'>m</span>.setField("<strong class='color-text'>${m.fieldUpgrades[m.fieldMode].name}</strong>")<br>input.key.field<span class='color-symbol'>:</span> ["<span class='color-text'>MouseRight</span>"]`);
},
fieldUpgrades: [{
name: "field emitter",
@@ -3058,7 +3060,7 @@ const m = {
},
{
name: "perfect diamagnetism",
description: "<strong>deflecting</strong> does not drain <strong class='color-f'>energy</strong><br>maintains <strong>functionality</strong> while <strong>inactive</strong><br><strong>5</strong> <strong class='color-f'>energy</strong> per second",
description: "<strong>deflecting</strong> does not drain <strong class='color-f'>energy</strong><br><strong>shield</strong> maintains <strong>functionality</strong> while inactive<br><strong>5</strong> <strong class='color-f'>energy</strong> per second",
effect: () => {
m.fieldMeterColor = "#48f" //"#0c5"
m.eyeFillColor = m.fieldMeterColor
@@ -3481,11 +3483,11 @@ const m = {
},
{
name: "molecular assembler",
description: `excess <strong class='color-f'>energy</strong> used to <strong class='color-print'>print</strong> ${simulation.molecularMode === 0 ? "<strong class='color-p' style='letter-spacing: 2px;'>spores" : simulation.molecularMode === 1 ? "<strong>missiles" : simulation.molecularMode === 2 ? "<strong class='color-s'>ice IX" : "<strong>drones"}</strong><br>use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs<br><strong>12</strong> <strong class='color-f'>energy</strong> per second`,
description: `use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs<br>excess <strong class='color-f'>energy</strong> used to <strong class='color-print'>print</strong> ${simulation.molecularMode === 0 ? "<strong class='color-p' style='letter-spacing: 2px;'>spores" : simulation.molecularMode === 1 ? "<strong>missiles" : simulation.molecularMode === 2 ? "<strong class='color-s'>ice IX" : "<strong>drones"}</strong><br><strong>12</strong> <strong class='color-f'>energy</strong> per second`,
setDescription() {
return `excess <strong class='color-f'>energy</strong> used to <strong class='color-print'>print</strong> ${simulation.molecularMode === 0 ? "<strong class='color-p' style='letter-spacing: 2px;'>spores" : simulation.molecularMode === 1 ? "<strong>missiles" : simulation.molecularMode === 2 ? "<strong class='color-s'>ice IX" : "<strong>drones"}</strong><br>use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs<br><strong>12</strong> <strong class='color-f'>energy</strong> per second`
return `use <strong class='color-f'>energy</strong> to <strong>deflect</strong> mobs<br>excess <strong class='color-f'>energy</strong> used to <strong class='color-print'>print</strong> ${simulation.molecularMode === 0 ? "<strong class='color-p' style='letter-spacing: 2px;'>spores" : simulation.molecularMode === 1 ? "<strong>missiles" : simulation.molecularMode === 2 ? "<strong class='color-s'>ice IX" : "<strong>drones"}</strong><br><strong>12</strong> <strong class='color-f'>energy</strong> per second`
},
blockJumpPhase: 0,
effect: () => {
m.fieldMeterColor = "#ff0"
m.eyeFillColor = m.fieldMeterColor
@@ -3596,115 +3598,15 @@ const m = {
m.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists)
}
m.drawRegenEnergy()
if (tech.isBlockJump) {
if (m.onGround && m.buttonCD_jump + 10 < m.cycle) this.blockJumpPhase = 0 //reset after touching ground or block
if (this.blockJumpPhase === 0 && !m.onGround) { //1st jump or fall
this.blockJumpPhase = 1
} else if (this.blockJumpPhase === 1 && !input.up && m.buttonCD_jump + 10 < m.cycle) { //not pressing jump
this.blockJumpPhase = 2
} else if (this.blockJumpPhase === 2 && input.up && m.buttonCD_jump + 10 < m.cycle) { //2nd jump
this.blockJumpPhase = 3
//make a block
const radius = 25 + Math.floor(15 * Math.random())
body[body.length] = Matter.Bodies.polygon(m.pos.x, m.pos.y + 65 + radius, 4, radius, {
friction: 0.05,
frictionAir: 0.001,
collisionFilter: {
category: cat.body,
mask: cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
},
classType: "body",
});
const block = body[body.length - 1]
//mess with the block shape (this code is horrible)
Composite.add(engine.world, block); //add to world
const r1 = radius * (1 + 0.4 * Math.random())
const r2 = radius * (1 + 0.4 * Math.random())
let angle = 0
const vertices = []
for (let i = 0, len = block.vertices.length; i < len; i++) {
angle += 2 * Math.PI / len
vertices.push({ x: block.position.x + r1 * Math.cos(angle), y: block.position.y + r2 * Math.sin(angle) })
}
Matter.Body.setVertices(block, vertices)
Matter.Body.setAngle(block, Math.PI / 4)
Matter.Body.setVelocity(block, { x: 0.9 * player.velocity.x, y: 10 });
Matter.Body.applyForce(block, m.pos, { x: 0, y: m.jumpForce * 0.12 * Math.min(m.standingOn.mass, 5) });
if (tech.isBlockRestitution) {
block.restitution = 0.999 //extra bouncy
block.friction = block.frictionStatic = block.frictionAir = 0.001
}
if (tech.isAddBlockMass) {
const expand = function (that, massLimit) {
if (that.mass < massLimit) {
const scale = 1.04;
Matter.Body.scale(that, scale, scale);
setTimeout(expand, 20, that, massLimit);
}
};
expand(block, Math.min(20, block.mass * 3))
}
//jump
m.buttonCD_jump = m.cycle; //can't jump again until 20 cycles pass
let horizontalVelocity = 8 * (- input.left + input.right)
Matter.Body.setVelocity(player, { x: player.velocity.x + horizontalVelocity, y: -7.5 + 0.25 * player.velocity.y });
player.force.y = -m.jumpForce; //player jump force
} else if (this.blockJumpPhase === 3 && m.onGround && m.buttonCD_jump + 10 < m.cycle) {
//reset
this.blockJumpPhase = 0 //reset
}
}
// if (tech.isBlockJump) {
// //make sure only 1 ephemera is running
// simulation.ephemera.push({
// name: "2 jump",
// mode: 0,
// do() {
// // console.log('hi')
// if (m.buttonCD_jump + 20 < m.cycle && m.onGround) simulation.removeEphemera(this.name)
// if (this.mode === 0) {
// if (!input.up) this.mode = 1
// } else if (this.mode === 1) {
// if (input.up && m.buttonCD_jump + 20 < m.cycle) {
// simulation.removeEphemera(this.name)
// //make a block
// body[body.length] = Matter.Bodies.polygon(m.pos.x, m.pos.y + 80, 4, 30 + Math.floor(10 * Math.random()), {
// friction: 0.05,
// frictionAir: 0.001,
// collisionFilter: {
// category: cat.body,
// mask: cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
// },
// classType: "body",
// // isPrinted: true,
// });
// const who = body[body.length - 1]
// Composite.add(engine.world, who); //add to world
// Matter.Body.setVelocity(who, { x: player.velocity.x * 0.5, y: +30 });
// Matter.Body.applyForce(who, m.pos, { x: 0, y: m.jumpForce * 0.12 * Math.min(m.standingOn.mass, 5) });
// //jump again
// m.buttonCD_jump = m.cycle; //can't jump again until 20 cycles pass
// player.force.y = -m.jumpForce; //player jump force
// Matter.Body.setVelocity(player, { x: player.velocity.x, y: -7.5 + 0.25 * player.velocity.y });
// }
// }
// },
// })
// }
}
}
},
{
name: "plasma torch",
description: "use <strong class='color-f'>energy</strong> to emit short range <strong class='color-plasma'>plasma</strong><br><strong class='color-d'>damages</strong> and <strong>pushes</strong> mobs away<br><strong>10</strong> <strong class='color-f'>energy</strong> per second",
description: "use <strong class='color-f'>energy</strong> to emit short range <strong class='color-plasma'>plasma</strong><br><strong>1.5x</strong> <strong class='color-d'>damage</strong><br><strong>10</strong> <strong class='color-f'>energy</strong> per second",
set() {
b.isExtruderOn = false
m.fieldDamage = 1.5
// m.fieldCDcycleAlternate = 0
if (m.plasmaBall) {
@@ -4500,16 +4402,18 @@ const m = {
}
this.drawRegenEnergyCloaking()
if (m.isSneakAttack && m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) > m.cycle) { //show sneak attack status
m.fieldDamage = 4.5 * (1 + 0.033 * m.coupling)
const timeLeft = (m.sneakAttackCycle + Math.min(100, 0.66 * (m.cycle - m.enterCloakCycle)) - m.cycle) * 0.5
ctx.beginPath();
ctx.arc(m.pos.x, m.pos.y, 32, 0, 2 * Math.PI);
ctx.strokeStyle = "rgba(180,30,70,0.5)";//"rgba(0,0,0,0.7)";//"rgba(255,255,255,0.7)";//"rgba(255,0,100,0.7)";
ctx.lineWidth = Math.max(Math.min(10, timeLeft), 3);
ctx.stroke();
// ctx.globalCompositeOperation = "multiply";
// m.drawCloakedM()
// ctx.globalCompositeOperation = "source-over";
} else {
m.fieldDamage = 1
}
}
}
@@ -4742,66 +4646,6 @@ const m = {
m.fieldRadius = 0
}
m.drawRegenEnergy("rgba(0,0,0,0.2)")
if (tech.isBlockJump) {
if (m.onGround && m.buttonCD_jump + 10 < m.cycle) this.blockJumpPhase = 0 //reset after touching ground or block
if (this.blockJumpPhase === 0 && !m.onGround) { //1st jump or fall
this.blockJumpPhase = 1
} else if (this.blockJumpPhase === 1 && !input.up && m.buttonCD_jump + 10 < m.cycle) { //not pressing jump
this.blockJumpPhase = 2
} else if (this.blockJumpPhase === 2 && input.up && m.buttonCD_jump + 10 < m.cycle) { //2nd jump
this.blockJumpPhase = 3
//make a block
const radius = 25 + Math.floor(15 * Math.random())
body[body.length] = Matter.Bodies.polygon(m.pos.x, m.pos.y + 60 + radius, 4, radius, {
friction: 0.05,
frictionAir: 0.001,
collisionFilter: {
category: cat.body,
mask: cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
},
classType: "body",
});
const block = body[body.length - 1]
//mess with the block shape (this code is horrible)
Composite.add(engine.world, block); //add to world
const r1 = radius * (1 + 0.4 * Math.random())
const r2 = radius * (1 + 0.4 * Math.random())
let angle = 0
const vertices = []
for (let i = 0, len = block.vertices.length; i < len; i++) {
angle += 2 * Math.PI / len
vertices.push({ x: block.position.x + r1 * Math.cos(angle), y: block.position.y + r2 * Math.sin(angle) })
}
Matter.Body.setVertices(block, vertices)
Matter.Body.setAngle(block, Math.PI / 4)
Matter.Body.setVelocity(block, { x: 0.9 * player.velocity.x, y: 10 });
Matter.Body.applyForce(block, m.pos, { x: 0, y: m.jumpForce * 0.12 * Math.min(m.standingOn.mass, 5) });
if (tech.isBlockRestitution) {
block.restitution = 0.999 //extra bouncy
block.friction = block.frictionStatic = block.frictionAir = 0.001
}
if (tech.isAddBlockMass) {
const expand = function (that, massLimit) {
if (that.mass < massLimit) {
const scale = 1.04;
Matter.Body.scale(that, scale, scale);
setTimeout(expand, 20, that, massLimit);
}
};
expand(block, Math.min(20, block.mass * 3))
}
//jump
m.buttonCD_jump = m.cycle; //can't jump again until 20 cycles pass
let horizontalVelocity = 8 * (- input.left + input.right)
Matter.Body.setVelocity(player, { x: player.velocity.x + horizontalVelocity, y: -7.5 + 0.25 * player.velocity.y });
player.force.y = -m.jumpForce; //player jump force
} else if (this.blockJumpPhase === 3 && m.onGround && m.buttonCD_jump + 10 < m.cycle) {
//reset
this.blockJumpPhase = 0 //reset
}
}
}
}
},