duplication mods

all bot upgrade mods are improved by about 33%
mod superdeterminism - spawns 6 mods  (was 3)

mod: futures exchange - canceling power ups increases duplication chance by 4%
mod: monte carlo experiment - spawn 2 mods, but you have a 50% chance to lose a random mod
  requires duplication mods, not available in custom
mod: exchange symmetry - spawn 1 mod with double your normal duplication chance
  requires duplication mods, not available in custom
This commit is contained in:
landgreen
2020-11-29 05:40:02 -08:00
parent dd43d9413b
commit 5782d82b8d
7 changed files with 235 additions and 113 deletions

View File

@@ -1324,7 +1324,7 @@ const b = {
restitution: 0.6 * (1 + 0.5 * Math.random()), restitution: 0.6 * (1 + 0.5 * Math.random()),
dmg: 0, // 0.14 //damage done in addition to the damage from momentum dmg: 0, // 0.14 //damage done in addition to the damage from momentum
minDmgSpeed: 2, minDmgSpeed: 2,
lookFrequency: 60 + Math.floor(17 * Math.random()) - 10 * mod.isFoamBotUpgrade, lookFrequency: 60 + Math.floor(17 * Math.random()) - 20 * mod.isFoamBotUpgrade,
cd: 0, cd: 0,
delay: 100, delay: 100,
acceleration: 0.005 * (1 + 0.5 * Math.random()), acceleration: 0.005 * (1 + 0.5 * Math.random()),
@@ -1383,7 +1383,7 @@ const b = {
lookFrequency: 40 + Math.floor(7 * Math.random()), lookFrequency: 40 + Math.floor(7 * Math.random()),
drainThreshold: mod.isEnergyHealth ? 0.5 : 0.15, drainThreshold: mod.isEnergyHealth ? 0.5 : 0.15,
acceleration: 0.0015 * (1 + 0.3 * Math.random()), acceleration: 0.0015 * (1 + 0.3 * Math.random()),
range: 700 * (1 + 0.1 * Math.random()) + 250 * mod.isLaserBotUpgrade, range: 700 * (1 + 0.1 * Math.random()) + 300 * mod.isLaserBotUpgrade,
followRange: 150 + Math.floor(30 * Math.random()), followRange: 150 + Math.floor(30 * Math.random()),
offPlayer: { offPlayer: {
x: 0, x: 0,
@@ -1437,7 +1437,7 @@ const b = {
//hit target with laser //hit target with laser
if (this.lockedOn && this.lockedOn.alive && mech.energy > this.drainThreshold) { if (this.lockedOn && this.lockedOn.alive && mech.energy > this.drainThreshold) {
mech.energy -= 0.0012 * mod.isLaserDiode mech.energy -= 0.0012 * mod.isLaserDiode
b.laser(this.vertices[0], this.lockedOn.position, b.dmgScale * (0.06 + 0.1 * this.isUpgraded)) b.laser(this.vertices[0], this.lockedOn.position, b.dmgScale * (0.06 + 0.15 * this.isUpgraded))
} }
} }
}) })
@@ -1459,7 +1459,7 @@ const b = {
minDmgSpeed: 0, minDmgSpeed: 0,
lookFrequency: 43 + Math.floor(7 * Math.random()), lookFrequency: 43 + Math.floor(7 * Math.random()),
acceleration: 0.005 * (1 + 0.5 * Math.random()), acceleration: 0.005 * (1 + 0.5 * Math.random()),
range: 500 * (1 + 0.1 * Math.random()) + 250 * mod.isBoomBotUpgrade, range: 500 * (1 + 0.1 * Math.random()) + 350 * mod.isBoomBotUpgrade,
endCycle: Infinity, endCycle: Infinity,
classType: "bullet", classType: "bullet",
collisionFilter: { collisionFilter: {
@@ -1470,7 +1470,7 @@ const b = {
explode: 0, explode: 0,
beforeDmg() { beforeDmg() {
if (this.lockedOn) { if (this.lockedOn) {
const explosionRadius = Math.min(170 + 170 * this.isUpgraded, Vector.magnitude(Vector.sub(this.position, mech.pos)) - 30) const explosionRadius = Math.min(170 + 200 * this.isUpgraded, Vector.magnitude(Vector.sub(this.position, mech.pos)) - 30)
if (explosionRadius > 60) { if (explosionRadius > 60) {
this.explode = explosionRadius this.explode = explosionRadius
// //
@@ -1760,7 +1760,7 @@ const b = {
}) })
for (let i = 0; i < q.length; i++) { for (let i = 0; i < q.length; i++) {
mobs.statusStun(q[i], 180) mobs.statusStun(q[i], 180)
const dmg = 0.5 * b.dmgScale * (this.isUpgraded ? 2 : 1) * (mod.isCrit ? 4 : 1) const dmg = 0.5 * b.dmgScale * (this.isUpgraded ? 2.5 : 1) * (mod.isCrit ? 4 : 1)
q[i].damage(dmg); q[i].damage(dmg);
q[i].foundPlayer(); q[i].foundPlayer();
game.drawList.push({ //add dmg to draw queue game.drawList.push({ //add dmg to draw queue
@@ -1927,7 +1927,7 @@ const b = {
}, },
{ {
name: "shotgun", name: "shotgun",
description: "fire a <strong>burst</strong> of short range <strong> bullets</strong> <br><em>crouch to reduce recoil</em>", description: "fire a <strong>burst</strong> of short range <strong> bullets</strong>",
ammo: 0, ammo: 0,
ammoPack: 5.5, ammoPack: 5.5,
defaultAmmoPack: 5.5, defaultAmmoPack: 5.5,
@@ -2218,7 +2218,7 @@ const b = {
}, },
{ {
name: "wave beam", name: "wave beam",
description: "emit a <strong>sine wave</strong> of oscillating particles<br>that can propagate <strong>through solids</strong>", description: "emit a <strong>sine wave</strong> of oscillating particles<br>propagates through <strong>walls</strong>",
ammo: 0, ammo: 0,
ammoPack: 70, ammoPack: 70,
have: false, have: false,

View File

@@ -179,11 +179,12 @@ const build = {
pauseGrid() { pauseGrid() {
let text = "" let text = ""
if (!game.isChoosing) text += `<div class="pause-grid-module"> if (!game.isChoosing) text += `<div class="pause-grid-module">
<span style="font-size:1.5em;font-weight: 600;">PAUSED</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; press P to resume</div> <span style="font-size:1.5em;font-weight: 600;">PAUSED</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; press P to resume</div>`
<div class="pause-grid-module" style = "font-size: 13px;line-height: 120%;padding: 5px;"> text += `<div class="pause-grid-module" style = "font-size: 13px;line-height: 120%;padding: 5px;">
<strong class='color-d'>damage</strong> increase: ${((mod.damageFromMods()-1)*100).toFixed(0)}% <strong class='color-d'>damage</strong> increase: ${((mod.damageFromMods()-1)*100).toFixed(0)}%
<br><strong class='color-harm'>harm</strong> reduction: ${((1-mech.harmReduction())*100).toFixed(0)}% <br><strong class='color-harm'>harm</strong> reduction: ${((1-mech.harmReduction())*100).toFixed(0)}%
<br><strong>fire delay</strong> decrease: ${((1-b.fireCD)*100).toFixed(0)}% <br><strong>fire delay</strong> decrease: ${((1-b.fireCD)*100).toFixed(0)}%
<br><strong>duplication</strong> chance: ${(Math.min(1,mod.duplicationChance())*100).toFixed(0)}%
<br> <br>
<br><strong class='color-r'>rerolls</strong>: ${powerUps.reroll.rerolls} <br><strong class='color-r'>rerolls</strong>: ${powerUps.reroll.rerolls}
<br><strong class='color-h'>health</strong>: (${(mech.health*100).toFixed(0)} / ${(mech.maxHealth*100).toFixed(0)}) &nbsp; <strong class='color-f'>energy</strong>: (${(mech.energy*100).toFixed(0)} / ${(mech.maxEnergy*100).toFixed(0)}) <br><strong class='color-h'>health</strong>: (${(mech.health*100).toFixed(0)} / ${(mech.maxHealth*100).toFixed(0)}) &nbsp; <strong class='color-f'>energy</strong>: (${(mech.energy*100).toFixed(0)} / ${(mech.maxEnergy*100).toFixed(0)})
@@ -798,6 +799,7 @@ window.addEventListener("keydown", function(event) {
mod.giveMod() mod.giveMod()
break break
case "r": case "r":
mech.resetHistory();
Matter.Body.setPosition(player, game.mouseInGame); Matter.Body.setPosition(player, game.mouseInGame);
Matter.Body.setVelocity(player, { Matter.Body.setVelocity(player, {
x: 0, x: 0,

View File

@@ -19,7 +19,7 @@ const level = {
// mech.setField("wormhole") // mech.setField("wormhole")
// b.giveGuns("laser") // b.giveGuns("laser")
// mod.is3Missiles = true // mod.is3Missiles = true
// mod.giveMod("CPT reversal") // mod.giveMod("reallocation")
// mod.giveMod("diffuse beam") // mod.giveMod("diffuse beam")
level.intro(); //starting level level.intro(); //starting level
@@ -56,21 +56,7 @@ const level = {
level.addToWorld(); //add bodies to game engine level.addToWorld(); //add bodies to game engine
game.draw.setPaths(); game.draw.setPaths();
b.respawnBots(); b.respawnBots();
for (let i = 0; i < 300; i++) { //reset history mech.resetHistory();
mech.history[i] = {
position: {
x: mech.pos.x,
y: mech.pos.y,
},
velocity: {
x: player.velocity.x,
y: player.velocity.y
},
angle: mech.angle,
health: mech.health,
energy: mech.energy,
}
}
if (mod.isArmorFromPowerUps) { if (mod.isArmorFromPowerUps) {
mod.armorFromPowerUps += 0.05 * powerUps.totalPowerUps mod.armorFromPowerUps += 0.05 * powerUps.totalPowerUps
mech.setMaxHealth(); mech.setMaxHealth();

View File

@@ -1,10 +1,14 @@
const mod = { const mod = {
totalCount: null, totalCount: null,
setupAllMods() { setupAllMods(isLost = false) {
for (let i = 0, len = mod.mods.length; i < len; i++) { for (let i = 0, len = mod.mods.length; i < len; i++) {
mod.mods[i].remove(); mod.mods[i].remove();
if (isLost) {
mod.mods[i].isLost = false;
} else if (mod.mods[i].count > 0) {
mod.mods[i].isLost = true
}
mod.mods[i].count = 0 mod.mods[i].count = 0
if (mod.mods[i].isLost) mod.mods[i].isLost = false;
} }
mod.armorFromPowerUps = 0; mod.armorFromPowerUps = 0;
mod.totalCount = 0; mod.totalCount = 0;
@@ -98,6 +102,9 @@ const mod = {
if (mod.isSpeedDamage) dmg *= 1 + Math.min(0.33, player.speed * 0.011) if (mod.isSpeedDamage) dmg *= 1 + Math.min(0.33, player.speed * 0.011)
return dmg * mod.slowFire * mod.aimDamage return dmg * mod.slowFire * mod.aimDamage
}, },
duplicationChance() {
return (mod.isBayesian ? 0.16 : 0) + mod.cancelCount * 0.04 + mod.duplicateChance
},
totalBots() { totalBots() {
return mod.foamBotCount + mod.nailBotCount + mod.laserBotCount + mod.boomBotCount + mod.plasmaBotCount + mod.orbitBotCount return mod.foamBotCount + mod.nailBotCount + mod.laserBotCount + mod.boomBotCount + mod.plasmaBotCount + mod.orbitBotCount
}, },
@@ -559,7 +566,7 @@ const mod = {
}, },
{ {
name: "foam-bot upgrade", name: "foam-bot upgrade",
description: "<strong>150%</strong> increased <strong>foam size</strong><br><em>applies to all current and future foam-bots</em>", description: "<strong>200%</strong> increased <strong>foam</strong> <strong>size</strong> and <strong>fire rate</strong><br><em>applies to all current and future foam-bots</em>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -598,7 +605,7 @@ const mod = {
}, },
{ {
name: "boom-bot upgrade", name: "boom-bot upgrade",
description: "<strong>200%</strong> increased <strong class='color-e'>explosion</strong> <strong class='color-d'>damage</strong> and size<br><em>applies to all current and future boom-bots</em>", description: "<strong>250%</strong> increased <strong class='color-e'>explosion</strong> <strong class='color-d'>damage</strong> and size<br><em>applies to all current and future boom-bots</em>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -637,7 +644,7 @@ const mod = {
}, },
{ {
name: "laser-bot upgrade", name: "laser-bot upgrade",
description: "<strong>200%</strong> increased laser <strong class='color-d'>damage</strong><br><em>applies to all current and future laser-bots</em>", description: "<strong>350%</strong> increased laser <strong class='color-d'>damage</strong><br><em>applies to all current and future laser-bots</em>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -676,7 +683,7 @@ const mod = {
}, },
{ {
name: "orbital-bot upgrade", name: "orbital-bot upgrade",
description: "increase <strong class='color-d'>damage</strong> by <strong>100%</strong> and <strong>radius</strong> by <strong>30%</strong><br><em>applies to all current and future orbit-bots</em>", description: "increase <strong class='color-d'>damage</strong> by <strong>150%</strong> and <strong>radius</strong> by <strong>30%</strong><br><em>applies to all current and future orbit-bots</em>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -708,7 +715,7 @@ const mod = {
}, },
{ {
name: "perimeter defense", name: "perimeter defense",
description: "reduce <strong class='color-harm'>harm</strong> by <strong>4%</strong><br>for each of your permanent <strong>bots</strong>", description: "reduce <strong class='color-harm'>harm</strong> by <strong>5%</strong><br>for each of your permanent <strong>bots</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -1292,17 +1299,11 @@ const mod = {
requires: "", requires: "",
effect: () => { effect: () => {
mod.isBayesian = true mod.isBayesian = true
mod.duplicateChance += 0.16
game.draw.powerUp = game.draw.powerUpBonus //change power up draw game.draw.powerUp = game.draw.powerUpBonus //change power up draw
}, },
remove() { remove() {
if (mod.isBayesian) {
mod.duplicateChance -= 0.16
if (mod.duplicateChance < 0) mod.duplicateChance = 0
}
mod.isBayesian = false mod.isBayesian = false
if (mod.duplicateChance === 0) game.draw.powerUp = game.draw.powerUpNormal if (mod.duplicationChance() === 0) game.draw.powerUp = game.draw.powerUpNormal
} }
}, },
{ {
@@ -1317,14 +1318,110 @@ const mod = {
effect() { effect() {
mod.duplicateChance += 0.07 mod.duplicateChance += 0.07
game.draw.powerUp = game.draw.powerUpBonus //change power up draw game.draw.powerUp = game.draw.powerUpBonus //change power up draw
// this.description = `<strong>8%</strong> chance to <strong>duplicate</strong> spawned <strong>power ups</strong><br><em>chance to duplicate = ${mod.duplicateChance}</em>`
}, },
remove() { remove() {
mod.duplicateChance -= 0.08 * this.count mod.duplicateChance = 0
if (mod.duplicateChance === 0) game.draw.powerUp = game.draw.powerUpNormal if (mod.duplicationChance() === 0) game.draw.powerUp = game.draw.powerUpNormal
// this.description = `<strong>8%</strong> chance to <strong>duplicate</strong> spawned <strong>power ups</strong><br><em>chance to duplicate = ${mod.duplicateChance}</em>`
} }
}, },
{
name: "futures exchange",
description: "clicking <strong>X</strong> to cancel a <strong class='color-m'>mod</strong>, <strong class='color-f'>field</strong>, or <strong class='color-g'>gun</strong><br>increases power up <strong>duplication</strong> chance by <strong>4%</strong>",
maxCount: 1,
count: 0,
allowed() {
return !mod.isDeterminism
},
requires: "not determinism",
effect() {
mod.isCancelDuplication = true
mod.cancelCount = 0
game.draw.powerUp = game.draw.powerUpBonus //change power up draw
},
remove() {
mod.isCancelDuplication = false
mod.cancelCount = 0
if (mod.duplicationChance() === 0) game.draw.powerUp = game.draw.powerUpNormal
}
},
{
name: "reallocation",
description: "convert <strong>1</strong> random <strong class='color-m'>mod</strong> into <strong>3</strong> new <strong class='color-g'>guns</strong><br><em>recursive mods lose all stacks</em>",
maxCount: 1,
count: 0,
isNonRefundable: true,
isCustomHide: true,
allowed() {
return (mod.totalCount > 0) && !mod.isSuperDeterminism && mod.duplicationChance() > 0
},
requires: "at least 1 mod, a chance to duplicate power ups",
effect: () => {
const have = [] //find which mods you have
for (let i = 0; i < mod.mods.length; i++) {
if (mod.mods[i].count > 0) have.push(i)
}
const choose = have[Math.floor(Math.random() * have.length)]
game.makeTextLog(`<div class='circle mod'></div> &nbsp; <strong>${mod.mods[choose].name}</strong> removed by reallocation`, 300)
for (let i = 0; i < mod.mods[choose].count; i++) {
powerUps.spawn(mech.pos.x, mech.pos.y, "gun");
}
powerUps.spawn(mech.pos.x, mech.pos.y, "gun");
powerUps.spawn(mech.pos.x, mech.pos.y, "gun");
mod.mods[choose].count = 0;
mod.mods[choose].remove(); // remove a random mod form the list of mods you have
mod.mods[choose].isLost = true
game.updateModHUD();
},
remove() {}
},
{
name: "monte carlo experiment",
description: "spawn <strong>2</strong> <strong class='color-m'>mods</strong><br><strong>50%</strong> chance to remove <strong>1</strong> random <strong class='color-m'>mod</strong>",
maxCount: 1,
count: 0,
isNonRefundable: true,
isCustomHide: true,
allowed() {
return (mod.totalCount > 0) && !mod.isSuperDeterminism && mod.duplicationChance() > 0
},
requires: "at least 1 mod, a chance to duplicate power ups",
effect: () => {
const have = [] //find which mods you have
for (let i = 0; i < mod.mods.length; i++) {
if (mod.mods[i].count > 0) have.push(i)
}
const choose = have[Math.floor(Math.random() * have.length)]
game.makeTextLog(`<div class='circle mod'></div> &nbsp; <strong>${mod.mods[choose].name}</strong> removed by reallocation`, 300)
for (let i = 0; i < mod.mods[choose].count; i++) {
powerUps.spawn(mech.pos.x, mech.pos.y, "mod");
}
powerUps.spawn(mech.pos.x, mech.pos.y, "mod");
mod.mods[choose].count = 0;
mod.mods[choose].remove(); // remove a random mod form the list of mods you have
mod.mods[choose].isLost = true
game.updateModHUD();
},
remove() {}
},
{
name: "exchange symmetry",
description: `spawn <strong>1</strong> <strong class='color-m'>mod</strong><br>with <strong>double</strong> your normal chance for power up <strong>duplication</strong>`,
maxCount: 1,
count: 0,
isNonRefundable: true,
isCustomHide: true,
allowed() {
return !mod.isSuperDeterminism && mod.duplicationChance() > 0
},
requires: "at least 1 mod, a chance to duplicate power ups",
effect: () => {
const chanceStore = mod.duplicateChance
mod.duplicateChance = (mod.isBayesian ? 0.16 : 0) + mod.cancelCount * 0.04 + mod.duplicateChance * 2 //increase duplication chance to simulate doubling all 3 sources of duplication chance
powerUps.spawn(mech.pos.x, mech.pos.y, "mod");
mod.duplicateChance = chanceStore
},
remove() {}
},
{ {
name: "entanglement", name: "entanglement",
nameInfo: "<span id = 'mod-entanglement'></span>", nameInfo: "<span id = 'mod-entanglement'></span>",
@@ -1507,7 +1604,7 @@ const mod = {
}, },
{ {
name: "superdeterminism", name: "superdeterminism",
description: "spawn <strong>3</strong> <strong class='color-m'>mods</strong><br><strong class='color-r'>rerolls</strong>, <strong class='color-g'>guns</strong>, and <strong class='color-f'>fields</strong> no longer <strong>spawn</strong>", description: "spawn <strong>6</strong> <strong class='color-m'>mods</strong><br><strong class='color-r'>rerolls</strong>, <strong class='color-g'>guns</strong>, and <strong class='color-f'>fields</strong> no longer <strong>spawn</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
isNonRefundable: true, isNonRefundable: true,
@@ -1517,7 +1614,7 @@ const mod = {
requires: "determinism", requires: "determinism",
effect: () => { effect: () => {
mod.isSuperDeterminism = true; mod.isSuperDeterminism = true;
for (let i = 0; i < 3; i++) { //if you change the six also change it in Born rule for (let i = 0; i < 6; i++) { //if you change the six also change it in Born rule
powerUps.spawn(mech.pos.x, mech.pos.y, "mod"); powerUps.spawn(mech.pos.x, mech.pos.y, "mod");
} }
}, },
@@ -1543,7 +1640,7 @@ const mod = {
}, },
{ {
name: "renormalization", name: "renormalization",
description: "consuming a <strong class='color-r'>reroll</strong> for <strong>any</strong> purpose<br>has a <strong>37%</strong> chance to spawn a <strong class='color-r'>reroll</strong>", description: "consuming a <strong class='color-r'>reroll</strong> for <strong>any</strong> purpose<br>has a <strong>42%</strong> chance to spawn a <strong class='color-r'>reroll</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -1568,8 +1665,9 @@ const mod = {
requires: "at least 2 rerolls", requires: "at least 2 rerolls",
effect() { effect() {
mod.isImmortal = true; mod.isImmortal = true;
powerUps.spawn(mech.pos.x, mech.pos.y, "reroll", false); for (let i = 0; i < 4; i++) {
for (let i = 0; i < 4; i++) {} powerUps.spawn(mech.pos.x, mech.pos.y, "reroll", false);
}
}, },
remove() { remove() {
mod.isImmortal = false; mod.isImmortal = false;
@@ -1598,7 +1696,7 @@ const mod = {
if (mod.isDeterminism) count -= 3 //remove the bonus mods if (mod.isDeterminism) count -= 3 //remove the bonus mods
if (mod.isSuperDeterminism) count -= 2 //remove the bonus mods if (mod.isSuperDeterminism) count -= 2 //remove the bonus mods
mod.setupAllMods(); // remove all mods mod.setupAllMods(false); // remove all mods
for (let i = 0; i < count; i++) { // spawn new mods power ups for (let i = 0; i < count; i++) { // spawn new mods power ups
powerUps.spawn(mech.pos.x, mech.pos.y, "mod"); powerUps.spawn(mech.pos.x, mech.pos.y, "mod");
} }
@@ -1606,37 +1704,9 @@ const mod = {
}, },
remove() {} remove() {}
}, },
{
name: "reallocation",
description: "convert <strong>1</strong> random <strong class='color-m'>mod</strong> into <strong>2</strong> new <strong class='color-g'>guns</strong><br><em>recursive mods lose all stacks</em>",
maxCount: 1,
count: 0,
isNonRefundable: true,
isCustomHide: true,
allowed() {
return (mod.totalCount > 0) && !mod.isSuperDeterminism
},
requires: "at least 1 mod",
effect: () => {
const have = [] //find which mods you have
for (let i = 0; i < mod.mods.length; i++) {
if (mod.mods[i].count > 0) have.push(i)
}
const choose = have[Math.floor(Math.random() * have.length)]
game.makeTextLog(`<div class='circle mod'></div> &nbsp; <strong>${mod.mods[choose].name}</strong> removed by reallocation`, 300)
for (let i = 0; i < 2 * mod.mods[choose].count; i++) {
powerUps.spawn(mech.pos.x, mech.pos.y, "gun");
}
mod.mods[choose].count = 0;
mod.mods[choose].remove(); // remove a random mod form the list of mods you have
mod.mods[choose].isLost = true
game.updateModHUD();
},
remove() {}
},
{ {
name: "perpetual rerolls", name: "perpetual rerolls",
description: "find <strong>1</strong> <strong class='color-r'>reroll</strong> power up<br>at the start of each <strong>level</strong>", description: "find <strong>1</strong> <strong class='color-r'>reroll</strong> at the start of each <strong>level</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -1652,7 +1722,7 @@ const mod = {
}, },
{ {
name: "perpetual heals", name: "perpetual heals",
description: "find <strong>2</strong> <strong class='color-h'>heal</strong> power ups<br>at the start of each <strong>level</strong>", description: "find <strong>2</strong> <strong class='color-h'>heals</strong> at the start of each <strong>level</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -1668,7 +1738,7 @@ const mod = {
}, },
{ {
name: "perpetual ammo", name: "perpetual ammo",
description: "find <strong>2</strong> <strong class='color-g'>ammo</strong> power ups<br>at the start of each <strong>level</strong>", description: "find <strong>2</strong> <strong class='color-g'>ammo</strong> at the start of each <strong>level</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -1772,15 +1842,17 @@ const mod = {
} }
}, },
remove() { remove() {
mod.isIceCrystals = false; if (mod.isIceCrystals) {
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "nail gun") { if (b.guns[i].name === "nail gun") {
b.guns[i].ammoPack = b.guns[i].defaultAmmoPack; b.guns[i].ammoPack = b.guns[i].defaultAmmoPack;
b.guns[i].ammo = b.guns[i].recordedAmmo if (b.guns[i].recordedAmmo) b.guns[i].ammo = b.guns[i].recordedAmmo
game.updateGunHUD(); game.updateGunHUD();
break; break;
}
} }
} }
mod.isIceCrystals = false;
} }
}, },
{ {
@@ -1962,23 +2034,37 @@ const mod = {
mod.isFlechetteMultiShot = true; mod.isFlechetteMultiShot = true;
//cut current ammo by 1/3 //cut current ammo by 1/3
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "flechettes") b.guns[i].ammo = Math.ceil(b.guns[i].ammo / 3); if (b.guns[i].name === "flechettes") {
b.guns[i].ammo = Math.ceil(b.guns[i].ammo / 3);
break
}
} }
//cut ammo packs by 1/3 //cut ammo packs by 1/3
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "flechettes") b.guns[i].ammoPack = Math.ceil(b.guns[i].defaultAmmoPack / 3); if (b.guns[i].name === "flechettes") {
b.guns[i].ammoPack = Math.ceil(b.guns[i].defaultAmmoPack / 3);
break
}
} }
game.updateGunHUD(); game.updateGunHUD();
}, },
remove() { remove() {
if (mod.isFlechetteMultiShot) {
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "flechettes") {
b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 3);
break
}
}
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "flechettes") {
b.guns[i].ammoPack = b.guns[i].defaultAmmoPack;
break
}
game.updateGunHUD();
}
}
mod.isFlechetteMultiShot = false; mod.isFlechetteMultiShot = false;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "flechettes") b.guns[i].ammo = Math.ceil(b.guns[i].ammo * 3);
}
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "flechettes") b.guns[i].ammoPack = b.guns[i].defaultAmmoPack;
}
game.updateGunHUD();
} }
}, },
{ {
@@ -2727,7 +2813,6 @@ const mod = {
requires: "laser, not specular reflection<br>not diffraction grating", requires: "laser, not specular reflection<br>not diffraction grating",
effect() { effect() {
this.description = `add 10 more <strong>laser</strong> beams into into your past` this.description = `add 10 more <strong>laser</strong> beams into into your past`
//`<strong>8%</strong> chance to <strong>duplicate</strong> spawned <strong>power ups</strong><br><em>chance to duplicate = ${mod.duplicateChance}</em>`
mod.historyLaser++ mod.historyLaser++
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod() if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
@@ -3202,7 +3287,7 @@ const mod = {
}, },
{ {
name: "traversable geodesics", name: "traversable geodesics",
description: "your <strong>bullets</strong> can traverse <strong class='color-worm'>wormholes</strong><br>spawn a <strong class='color-g'>gun</strong> and <strong class='color-g'>ammo</strong> power up", description: "your <strong>bullets</strong> can traverse <strong class='color-worm'>wormholes</strong><br>spawn a <strong class='color-g'>gun</strong> and <strong class='color-g'>ammo</strong>",
maxCount: 1, maxCount: 1,
count: 0, count: 0,
allowed() { allowed() {
@@ -3220,7 +3305,7 @@ const mod = {
}, },
{ {
name: "heals", name: "heals",
description: "spawn <strong>6</strong> <strong class='color-h'>heal</strong> power ups", description: "spawn <strong>6</strong> <strong class='color-h'>heals</strong>",
maxCount: 9, maxCount: 9,
count: 0, count: 0,
isNonRefundable: true, isNonRefundable: true,
@@ -3239,7 +3324,7 @@ const mod = {
}, },
{ {
name: "ammo", name: "ammo",
description: "spawn <strong>6</strong> <strong class='color-g'>ammo</strong> power ups", description: "spawn <strong>6</strong> <strong class='color-g'>ammo</strong>",
maxCount: 9, maxCount: 9,
count: 0, count: 0,
isNonRefundable: true, isNonRefundable: true,
@@ -3258,7 +3343,7 @@ const mod = {
}, },
{ {
name: "rerolls", name: "rerolls",
description: "spawn <strong>4</strong> <strong class='color-r'>reroll</strong> power ups", description: "spawn <strong>4</strong> <strong class='color-r'>rerolls</strong>",
maxCount: 9, maxCount: 9,
count: 0, count: 0,
isNonRefundable: true, isNonRefundable: true,
@@ -3277,7 +3362,7 @@ const mod = {
}, },
{ {
name: "gun", name: "gun",
description: "spawn a <strong class='color-g'>gun</strong> power up", description: "spawn a <strong class='color-g'>gun</strong>",
maxCount: 9, maxCount: 9,
count: 0, count: 0,
isNonRefundable: true, isNonRefundable: true,
@@ -3294,7 +3379,7 @@ const mod = {
}, },
{ {
name: "field", name: "field",
description: "spawn a <strong class='color-f'>field</strong> power up", description: "spawn a <strong class='color-f'>field</strong>",
maxCount: 9, maxCount: 9,
count: 0, count: 0,
isNonRefundable: true, isNonRefundable: true,
@@ -3477,5 +3562,7 @@ const mod = {
isPerpetualReroll: null, isPerpetualReroll: null,
isPerpetualAmmo: null, isPerpetualAmmo: null,
isPerpetualHeal: null, isPerpetualHeal: null,
isPerpetualStun: null isPerpetualStun: null,
isCancelDuplication: null,
cancelCount: null
} }

View File

@@ -134,6 +134,23 @@ const mech = {
transX: 0, transX: 0,
transY: 0, transY: 0,
history: [], //tracks the last second of player position history: [], //tracks the last second of player position
resetHistory() {
for (let i = 0; i < 300; i++) { //reset history
mech.history[i] = {
position: {
x: mech.pos.x,
y: mech.pos.y,
},
velocity: {
x: player.velocity.x,
y: player.velocity.y
},
angle: mech.angle,
health: mech.health,
energy: mech.energy,
}
}
},
move() { move() {
mech.pos.x = player.position.x; mech.pos.x = player.position.x;
mech.pos.y = playerBody.position.y - mech.yOff; mech.pos.y = playerBody.position.y - mech.yOff;
@@ -480,6 +497,20 @@ const mech = {
let history = mech.history[(mech.cycle - steps) % 300] let history = mech.history[(mech.cycle - steps) % 300]
Matter.Body.setPosition(player, history.position); Matter.Body.setPosition(player, history.position);
Matter.Body.setVelocity(player, { x: history.velocity.x, y: history.velocity.y }); Matter.Body.setVelocity(player, { x: history.velocity.x, y: history.velocity.y });
// move bots to follow player
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
Matter.Body.setPosition(bullet[i], Vector.add(player.position, {
x: 250 * (Math.random() - 0.5),
y: 250 * (Math.random() - 0.5)
}));
Matter.Body.setVelocity(bullet[i], {
x: 0,
y: 0
});
}
}
mech.energy = Math.max(mech.energy - steps, 0.01) mech.energy = Math.max(mech.energy - steps, 0.01)
mech.immuneCycle = mech.cycle + mod.collisionImmuneCycles; //player is immune to collision damage for 30 cycles mech.immuneCycle = mech.cycle + mod.collisionImmuneCycles; //player is immune to collision damage for 30 cycles
@@ -504,6 +535,7 @@ const mech = {
mech.draw(); mech.draw();
} }
ctx.restore(); ctx.restore();
mech.resetHistory()
} }
} }
}; };

View File

@@ -36,6 +36,7 @@ const powerUps = {
build.pauseGrid(true) build.pauseGrid(true)
}, },
endDraft() { endDraft() {
if (mod.isCancelDuplication) mod.cancelCount++
if (mod.manyWorlds && powerUps.reroll.rerolls < 1) { if (mod.manyWorlds && powerUps.reroll.rerolls < 1) {
powerUps.spawn(mech.pos.x, mech.pos.y, "reroll"); powerUps.spawn(mech.pos.x, mech.pos.y, "reroll");
} }
@@ -70,7 +71,7 @@ const powerUps = {
b.randomBot() b.randomBot()
if (mod.renormalization) { if (mod.renormalization) {
for (let i = 0; i < limit; i++) { for (let i = 0; i < limit; i++) {
if (Math.random() < 0.37) { if (Math.random() < 0.42) {
mech.fieldCDcycle = mech.cycle + 30; mech.fieldCDcycle = mech.cycle + 30;
powerUps.spawn(mech.pos.x, mech.pos.y, "reroll"); powerUps.spawn(mech.pos.x, mech.pos.y, "reroll");
} }
@@ -81,7 +82,7 @@ const powerUps = {
if (mod.isDeathAvoid && document.getElementById("mod-anthropic")) { if (mod.isDeathAvoid && document.getElementById("mod-anthropic")) {
document.getElementById("mod-anthropic").innerHTML = `-${powerUps.reroll.rerolls}` document.getElementById("mod-anthropic").innerHTML = `-${powerUps.reroll.rerolls}`
} }
if (mod.renormalization && Math.random() < 0.37 && amount < 0) { if (mod.renormalization && Math.random() < 0.42 && amount < 0) {
powerUps.spawn(mech.pos.x, mech.pos.y, "reroll"); powerUps.spawn(mech.pos.x, mech.pos.y, "reroll");
} }
if (mod.isRerollHaste) { if (mod.isRerollHaste) {
@@ -602,7 +603,7 @@ const powerUps = {
(!game.isNoPowerUps || (target === 'reroll' || target === 'heal' || target === 'ammo')) (!game.isNoPowerUps || (target === 'reroll' || target === 'heal' || target === 'ammo'))
) { ) {
powerUps.directSpawn(x, y, target, moving, mode, size) powerUps.directSpawn(x, y, target, moving, mode, size)
if (mod.duplicateChance && Math.random() < mod.duplicateChance) { if (Math.random() < mod.duplicationChance()) {
powerUps.directSpawn(x, y, target, moving, mode) powerUps.directSpawn(x, y, target, moving, mode)
powerUp[powerUp.length - 1].isBonus = true powerUp[powerUp.length - 1].isBonus = true
} }

View File

@@ -1,7 +1,14 @@
*********** NEXT PATCH *********** *********** NEXT PATCH ***********
4 new mods: perpetual ammo/rerolls/heals - get that power up at the start of each level all bot upgrade mods are improved by about 33%
also perpetual stun: stuns all mobs for 8 seconds at the start mod superdeterminism - spawns 6 mods (was 3)
mod: futures exchange - canceling power ups increases duplication chance by 4%
mod: monte carlo experiment - spawn 2 mods, but you have a 50% chance to lose a random mod
requires duplication mods, not available in custom
mod: exchange symmetry - spawn 1 mod with double your normal duplication chance
requires duplication mods, not available in custom
************** BUGS ************** ************** BUGS **************
@@ -23,8 +30,15 @@
************** TODO ************** ************** TODO **************
mod: canceling a mod gun or field increases your duplication chance for all power up by 4%
in custom make a top bar that is fixed
use media rules to make the layout look nice
bot that follows the players history bot that follows the players history
1st bot is at 5s, 2nd is at 4.5s, ... 1st bot is at 5s, 2nd is at 4.5s, ...
bots don't get too close to player
run smoothing on position update, don't update if close to player, based on ordering
effect: effect:
give player energy overfill give player energy overfill
damage mobs on contact damage mobs on contact
@@ -36,15 +50,15 @@ mob vision: look at player history
if mobs can't see player, they could check to see if they can find player in the past if mobs can't see player, they could check to see if they can find player in the past
https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding https://abitawake.com/news/articles/enemy-ai-chasing-a-player-without-navigation2d-or-a-star-pathfinding
mod negative mass field - mobs caught in the field take damage that increases with the relative velocity between the player and mob
wormhole - make it clear when the wormhole can and can't teleport to a location before the player clicks wormhole - make it clear when the wormhole can and can't teleport to a location before the player clicks
time dilation - slow down the game engine by 1/2, but run an extra player cycle to simulate slow motion time dilation - slow down the game engine by 1/2, but run an extra player cycle to simulate slow motion
flavor - your bullets destroy blocks flavor - your bullets destroy blocks
this isn't really a bonus, so maybe just add this as flavor to another mod/field/gun this isn't really a bonus, so maybe just add this as flavor to another mod/field/gun
a chance for destroyed blocks to drop ammo? a chance for destroyed blocks to drop stuff
power ups
spores
mod plasma : plasma length increases then decreases as you hold down the field button (like stabbing with a spear) mod plasma : plasma length increases then decreases as you hold down the field button (like stabbing with a spear)
grows to 1.5 longer after 0.3 seconds, then returns to normal length over 1 second, until field is pressed again grows to 1.5 longer after 0.3 seconds, then returns to normal length over 1 second, until field is pressed again