forked from sent/waves
1595 lines
93 KiB
JavaScript
1595 lines
93 KiB
JavaScript
let powerUp = [];
|
|
|
|
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
|
|
});
|
|
},
|
|
healGiveMaxEnergy: false, //for tech 1st ionization energy
|
|
orb: {
|
|
research(num = 1) {
|
|
switch (num) {
|
|
case 1:
|
|
return `<div class="research-circle"></div> `
|
|
case 2:
|
|
return `<span style="position:relative;">
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:0;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:7px;"></div>
|
|
</span> `
|
|
case 3:
|
|
return `<span style="position:relative;">
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:0;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:8px;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:16px;"></div>
|
|
</span>   `
|
|
case 4:
|
|
return `<span style="position:relative;">
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:0;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:8px;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:16px;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:24px;"></div>
|
|
</span> `
|
|
case 5:
|
|
return `<span style="position:relative;">
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:0;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:8px;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:16px;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:24px;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:32px;"></div>
|
|
</span> `
|
|
case 6:
|
|
return `<span style="position:relative;">
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:0;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:8px;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:16px;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:24px;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:32px;"></div>
|
|
<div class="research-circle" style="position:absolute; top:1.5px; left:40px;"></div>
|
|
</span> `
|
|
}
|
|
let text = '<span style="position:relative;">'
|
|
for (let i = 0; i < num; i++) {
|
|
text += `<div class="research-circle" style="position:absolute; top:1.5px; left:${i * 8}px;"></div>`
|
|
}
|
|
text += '</span> '
|
|
for (let i = 0; i < num; i++) {
|
|
text += ' '
|
|
}
|
|
return text
|
|
},
|
|
ammo(num = 1) {
|
|
switch (num) {
|
|
case 1:
|
|
return `<div class="ammo-circle"></div>`
|
|
}
|
|
let text = '<span style="position:relative;">'
|
|
for (let i = 0; i < num; i++) {
|
|
text += `<div class="ammo-circle" style="position:absolute; top:1.5px; left:${i * 8}px;"></div>`
|
|
}
|
|
text += '</span> '
|
|
for (let i = 0; i < num; i++) {
|
|
text += ' '
|
|
}
|
|
return text
|
|
},
|
|
heal(num = 1) {
|
|
if (powerUps.healGiveMaxEnergy) {
|
|
switch (num) {
|
|
case 1:
|
|
return `<div class="heal-circle-energy"></div>`
|
|
}
|
|
let text = '<span style="position:relative;">'
|
|
for (let i = 0; i < num; i++) {
|
|
text += `<div class="heal-circle-energy" style="position:absolute; top:1px; left:${i * 10}px;"></div>`
|
|
}
|
|
text += '</span> '
|
|
for (let i = 0; i < num; i++) {
|
|
text += ' '
|
|
}
|
|
return text
|
|
} else {
|
|
switch (num) {
|
|
case 1:
|
|
return `<div class="heal-circle"></div>`
|
|
}
|
|
let text = '<span style="position:relative;">'
|
|
for (let i = 0; i < num; i++) {
|
|
text += `<div class="heal-circle" style="position:absolute; top:1px; left:${i * 10}px;"></div>`
|
|
}
|
|
text += '</span> '
|
|
for (let i = 0; i < num; i++) {
|
|
text += ' '
|
|
}
|
|
return text
|
|
}
|
|
},
|
|
tech(num = 1) {
|
|
return `<div class="tech-circle"></div>`
|
|
},
|
|
coupling(num = 1) {
|
|
switch (num) {
|
|
case 1:
|
|
return `<div class="coupling-circle"></div>`
|
|
}
|
|
let text = '<span style="position:relative;">'
|
|
for (let i = 0; i < num; i++) {
|
|
text += `<div class="coupling-circle" style="position:absolute; top:1.5px; left:${i * 6}px;"></div>`
|
|
}
|
|
text += '</span> '
|
|
for (let i = 0; i < num; i++) {
|
|
text += '  '
|
|
}
|
|
return text
|
|
},
|
|
boost(num = 1) {
|
|
switch (num) {
|
|
case 1:
|
|
return `<div class="boost-circle"></div>`
|
|
}
|
|
let text = '<span style="position:relative;">'
|
|
for (let i = 0; i < num; i++) {
|
|
text += `<div class="boost-circle" style="position:absolute; top:1.5px; left:${i * 8}px;"></div>`
|
|
}
|
|
text += '</span> '
|
|
for (let i = 0; i < num; i++) {
|
|
text += ' '
|
|
}
|
|
return text
|
|
},
|
|
},
|
|
totalPowerUps: 0, //used for tech that count power ups at the end of a level
|
|
do() { },
|
|
setPowerUpMode() {
|
|
if (tech.duplicationChance() > 0 || tech.isAnthropicTech) {
|
|
powerUps.draw = powerUps.drawDup
|
|
if (tech.isPowerUpsVanish) {
|
|
if (tech.isHealAttract) {
|
|
powerUps.do = () => {
|
|
powerUps.dupExplode();
|
|
powerUps.draw();
|
|
powerUps.attractHeal();
|
|
}
|
|
} else {
|
|
powerUps.do = () => {
|
|
powerUps.dupExplode();
|
|
powerUps.draw();
|
|
}
|
|
}
|
|
} else if (tech.isHealAttract) {
|
|
powerUps.do = () => {
|
|
powerUps.draw();
|
|
powerUps.attractHeal();
|
|
}
|
|
} else {
|
|
powerUps.do = () => powerUps.draw();
|
|
}
|
|
tech.maxDuplicationEvent() //check to see if hitting 100% duplication
|
|
} else {
|
|
powerUps.draw = powerUps.drawCircle
|
|
if (tech.isHealAttract) {
|
|
powerUps.do = () => {
|
|
powerUps.draw();
|
|
powerUps.attractHeal();
|
|
}
|
|
} else {
|
|
powerUps.do = powerUps.draw
|
|
}
|
|
}
|
|
},
|
|
draw() { },
|
|
drawCircle() {
|
|
ctx.globalAlpha = 0.4 * Math.sin(simulation.cycle * 0.15) + 0.6;
|
|
for (let i = 0, len = powerUp.length; i < len; ++i) {
|
|
ctx.beginPath();
|
|
ctx.arc(powerUp[i].position.x, powerUp[i].position.y, powerUp[i].size, 0, 2 * Math.PI);
|
|
ctx.fillStyle = powerUp[i].color;
|
|
ctx.fill();
|
|
}
|
|
ctx.globalAlpha = 1;
|
|
},
|
|
drawDup() {
|
|
ctx.globalAlpha = 0.4 * Math.sin(simulation.cycle * 0.15) + 0.6;
|
|
for (let i = 0, len = powerUp.length; i < len; ++i) {
|
|
ctx.beginPath();
|
|
if (powerUp[i].isDuplicated) {
|
|
let vertices = powerUp[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);
|
|
} else {
|
|
ctx.arc(powerUp[i].position.x, powerUp[i].position.y, powerUp[i].size, 0, 2 * Math.PI);
|
|
}
|
|
ctx.fillStyle = powerUp[i].color;
|
|
ctx.fill();
|
|
}
|
|
ctx.globalAlpha = 1;
|
|
},
|
|
attractHeal() {
|
|
for (let i = 0; i < powerUp.length; i++) { //attract heal power ups to player
|
|
if (powerUp[i].name === "heal") {
|
|
let attract = Vector.mult(Vector.normalise(Vector.sub(m.pos, powerUp[i].position)), 0.015 * powerUp[i].mass)
|
|
powerUp[i].force.x += attract.x;
|
|
powerUp[i].force.y += attract.y - powerUp[i].mass * simulation.g; //negate gravity
|
|
Matter.Body.setVelocity(powerUp[i], Vector.mult(powerUp[i].velocity, 0.7));
|
|
}
|
|
}
|
|
},
|
|
dupExplode() {
|
|
for (let i = 0, len = powerUp.length; i < len; ++i) {
|
|
if (powerUp[i].isDuplicated) {
|
|
if (Math.random() < 0.003) { // (1-0.003)^240 = chance to be removed after 4 seconds, 240 = 4 seconds * 60 cycles per second
|
|
b.explosion(powerUp[i].position, 175 + (11 + 3 * Math.random()) * powerUp[i].size);
|
|
Matter.Composite.remove(engine.world, powerUp[i]);
|
|
powerUp.splice(i, 1);
|
|
break
|
|
}
|
|
if (Math.random() < 0.3) { //draw electricity
|
|
const mag = 4 + powerUp[i].size / 5
|
|
let unit = Vector.rotate({ x: mag, y: mag }, 2 * Math.PI * Math.random())
|
|
let path = { x: powerUp[i].position.x + unit.x, y: powerUp[i].position.y + unit.y }
|
|
ctx.beginPath();
|
|
ctx.moveTo(path.x, path.y);
|
|
for (let i = 0; i < 6; i++) {
|
|
unit = Vector.rotate(unit, 4 * (Math.random() - 0.5))
|
|
path = Vector.add(path, unit)
|
|
ctx.lineTo(path.x, path.y);
|
|
}
|
|
ctx.lineWidth = 0.5 + 2 * Math.random();
|
|
ctx.strokeStyle = "#000"
|
|
ctx.stroke();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
choose(type, index) {
|
|
if (type === "gun") {
|
|
b.giveGuns(index)
|
|
let text = `b.giveGuns("<span class='color-text'>${b.guns[index].name}</span>")`
|
|
if (b.inventory.length === 1) text += `<br>input.key.gun<span class='color-symbol'>:</span> ["<span class='color-text'>MouseLeft</span>"]`
|
|
if (b.inventory.length === 2) text += `
|
|
<br>input.key.nextGun<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.nextGun}</span>","<span class='color-text'>MouseWheel</span>"]
|
|
<br>input.key.previousGun<span class='color-symbol'>:</span> ["<span class='color-text'>${input.key.previousGun}</span>","<span class='color-text'>MouseWheel</span>"]`
|
|
simulation.makeTextLog(text);
|
|
} else if (type === "field") {
|
|
m.setField(index)
|
|
} else if (type === "tech") {
|
|
// if (tech.isBanish && tech.tech[index].isBanished) tech.tech[index].isBanished = false
|
|
simulation.makeTextLog(`<span class='color-var'>tech</span>.giveTech("<span class='color-text'>${tech.tech[index].name}</span>")`);
|
|
tech.giveTech(index)
|
|
}
|
|
powerUps.endDraft(type);
|
|
},
|
|
showDraft() {
|
|
//disable clicking for 1/2 a second to prevent mistake clicks
|
|
document.getElementById("choose-grid").style.pointerEvents = "none";
|
|
document.body.style.cursor = "none";
|
|
setTimeout(() => {
|
|
// if (!tech.isNoDraftPause)
|
|
document.body.style.cursor = "auto";
|
|
document.getElementById("choose-grid").style.pointerEvents = "auto";
|
|
document.getElementById("choose-grid").style.transitionDuration = "0s";
|
|
}, 400);
|
|
simulation.isChoosing = true; //stops p from un pausing on key down
|
|
|
|
if (!simulation.paused) {
|
|
if (tech.isNoDraftPause) {
|
|
document.getElementById("choose-grid").style.opacity = "1"
|
|
} else {
|
|
simulation.paused = true;
|
|
document.getElementById("choose-grid").style.opacity = "1"
|
|
}
|
|
document.getElementById("choose-grid").style.transitionDuration = "0.5s"; //how long is the fade in on
|
|
document.getElementById("choose-grid").style.visibility = "visible"
|
|
|
|
requestAnimationFrame(() => {
|
|
ctx.fillStyle = `rgba(150,150,150,0.9)`; //`rgba(221,221,221,0.6)`;
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
});
|
|
// document.getElementById("pause-grid-right").style.opacity = "0.7"
|
|
// document.getElementById("pause-grid-left").style.opacity = "0.7"
|
|
}
|
|
// build.pauseGrid()
|
|
},
|
|
endDraft(type, isCanceled = false) { //type should be a gun, tech, or field
|
|
if (isCanceled) {
|
|
if (tech.isCancelTech && Math.random() < 0.85 && type !== "entanglement") {
|
|
// powerUps.research.use('tech')
|
|
powerUps[type].effect();
|
|
return
|
|
}
|
|
if (tech.isCancelDuplication) {
|
|
tech.duplication += 0.041
|
|
tech.maxDuplicationEvent()
|
|
simulation.makeTextLog(`tech.duplicationChance() <span class='color-symbol'>+=</span> ${0.043}`)
|
|
simulation.circleFlare(0.043);
|
|
}
|
|
if (tech.isCancelRerolls) {
|
|
for (let i = 0, len = 5 + 5 * Math.random(); i < len; i++) {
|
|
let spawnType
|
|
if (Math.random() < 0.4 && !tech.isEnergyNoAmmo) {
|
|
spawnType = "ammo"
|
|
} else if (Math.random() < 0.33 && !tech.isSuperDeterminism) {
|
|
spawnType = "research"
|
|
} else {
|
|
spawnType = "heal"
|
|
}
|
|
powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), spawnType, false);
|
|
}
|
|
}
|
|
if (tech.isCancelCouple) powerUps.spawnDelay("coupling", 5)
|
|
// if (tech.isCancelTech && Math.random() < 0.3) {
|
|
// powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "tech", false);
|
|
// simulation.makeTextLog(`<strong>options exchange</strong>: returns 1 <strong class='color-m'>tech</strong>`)
|
|
// }
|
|
// if (tech.isBanish && type === 'tech') { // banish researched tech by adding them to the list of banished tech
|
|
// const banishLength = tech.isDeterminism ? 1 : 3 + tech.extraChoices * 2
|
|
// for (let i = 0; i < banishLength; i++) {
|
|
// const index = powerUps.tech.choiceLog.length - i - 1
|
|
// if (powerUps.tech.choiceLog[index] && tech.tech[powerUps.tech.choiceLog[index]]) {
|
|
// tech.tech[powerUps.tech.choiceLog[index]].isBanished = true
|
|
// }
|
|
// }
|
|
// simulation.makeTextLog(`powerUps.tech.length: ${Math.max(0,powerUps.tech.lastTotalChoices - banishLength)}`)
|
|
// }
|
|
}
|
|
if (tech.isAnsatz && powerUps.research.count < 1) {
|
|
for (let i = 0; i < 2; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
|
|
}
|
|
// document.getElementById("choose-grid").style.display = "none"
|
|
document.getElementById("choose-grid").style.visibility = "hidden"
|
|
document.getElementById("choose-grid").style.opacity = "0"
|
|
|
|
document.body.style.cursor = "none";
|
|
// document.body.style.overflow = "hidden"
|
|
// if (m.alive){}
|
|
if (simulation.paused) requestAnimationFrame(cycle);
|
|
if (m.alive) simulation.paused = false;
|
|
simulation.isChoosing = false; //stops p from un pausing on key down
|
|
build.unPauseGrid()
|
|
if (m.immuneCycle < m.cycle + 15) m.immuneCycle = m.cycle + 15; //player is immune to damage for 30 cycles
|
|
if (m.holdingTarget) m.drop();
|
|
},
|
|
coupling: {
|
|
name: "coupling",
|
|
color: "#0ae", //"#0cf",
|
|
size() {
|
|
return 13;
|
|
},
|
|
effect() {
|
|
m.couplingChange(1)
|
|
},
|
|
// spawnDelay(num) {
|
|
// let count = num
|
|
// let respawnDrones = () => {
|
|
// if (count > 0) {
|
|
// requestAnimationFrame(respawnDrones);
|
|
// if (!simulation.paused && !simulation.isChoosing) { //&& !(simulation.cycle % 2)
|
|
// count--
|
|
// const where = { x: m.pos.x + 50 * (Math.random() - 0.5), y: m.pos.y + 50 * (Math.random() - 0.5) }
|
|
// powerUps.spawn(where.x, where.y, "coupling");
|
|
// }
|
|
// }
|
|
// }
|
|
// requestAnimationFrame(respawnDrones);
|
|
// }
|
|
},
|
|
boost: {
|
|
name: "boost",
|
|
color: "#f55", //"#0cf",
|
|
size() {
|
|
return 11;
|
|
},
|
|
endCycle: 0,
|
|
duration: null, //set by "tech: band gap"
|
|
damage: null, //set by "tech: band gap"
|
|
effect() {
|
|
powerUps.boost.endCycle = m.cycle + Math.floor(Math.max(0, powerUps.boost.endCycle - m.cycle) * 0.6) + powerUps.boost.duration //duration+seconds plus 2/3 of current time left
|
|
},
|
|
draw() {
|
|
// console.log(this.endCycle)
|
|
if (powerUps.boost.endCycle > m.cycle) {
|
|
ctx.strokeStyle = "rgba(255,0,0,0.8)" //m.fieldMeterColor; //"rgba(255,255,0,0.2)" //ctx.strokeStyle = `rgba(0,0,255,${0.5+0.5*Math.random()})`
|
|
ctx.beginPath();
|
|
const arc = (powerUps.boost.endCycle - m.cycle) / powerUps.boost.duration
|
|
ctx.arc(m.pos.x, m.pos.y, 28, m.angle - Math.PI * arc, m.angle + Math.PI * arc); //- Math.PI / 2
|
|
ctx.lineWidth = 4
|
|
ctx.stroke();
|
|
}
|
|
},
|
|
},
|
|
research: {
|
|
count: 0,
|
|
name: "research",
|
|
color: "#f7b",
|
|
size() {
|
|
return 20;
|
|
},
|
|
effect() {
|
|
powerUps.research.changeRerolls(1)
|
|
},
|
|
isMakingBots: false, //to prevent bot fabrication from running 2 sessions at once
|
|
changeRerolls(amount) {
|
|
if (amount !== 0) powerUps.research.count += amount
|
|
if (tech.isRerollBots && !this.isMakingBots) {
|
|
let cycle = () => {
|
|
const cost = 2 + Math.floor(0.2 * b.totalBots())
|
|
if (m.alive && powerUps.research.count >= cost) {
|
|
requestAnimationFrame(cycle);
|
|
this.isMakingBots = true
|
|
} else {
|
|
this.isMakingBots = false
|
|
}
|
|
if (!simulation.paused && !simulation.isChoosing && !(simulation.cycle % 60)) {
|
|
powerUps.research.count -= cost
|
|
b.randomBot()
|
|
if (tech.renormalization) {
|
|
for (let i = 0; i < cost; i++) {
|
|
if (Math.random() < 0.46) {
|
|
m.fieldCDcycle = m.cycle + 20;
|
|
powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
requestAnimationFrame(cycle);
|
|
}
|
|
if (tech.isDeathAvoid && document.getElementById("tech-anthropic")) {
|
|
document.getElementById("tech-anthropic").innerHTML = `-${powerUps.research.count}`
|
|
}
|
|
if (tech.renormalization && Math.random() < 0.46 && amount < 0) {
|
|
for (let i = 0, len = -amount; i < len; i++) powerUps.spawn(m.pos.x, m.pos.y, "research");
|
|
}
|
|
if (tech.isRerollHaste) {
|
|
if (powerUps.research.count === 0) {
|
|
tech.researchHaste = 0.66;
|
|
b.setFireCD();
|
|
} else {
|
|
tech.researchHaste = 1;
|
|
b.setFireCD();
|
|
}
|
|
}
|
|
},
|
|
currentRerollCount: 0,
|
|
use(type) { //runs when you actually research a list of selections, type can be field, gun, or tech
|
|
if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) {
|
|
tech.addJunkTechToPool(tech.junkResearchNumber * 0.01)
|
|
} else {
|
|
powerUps.research.changeRerolls(-1)
|
|
}
|
|
powerUps.research.currentRerollCount++
|
|
// if (tech.isBanish && type === 'tech') { // banish researched tech
|
|
// const banishLength = tech.isDeterminism ? 1 : 3 + tech.extraChoices * 2
|
|
// for (let i = 0; i < banishLength; i++) {
|
|
// const index = powerUps.tech.choiceLog.length - i - 1
|
|
// if (powerUps.tech.choiceLog[index] && tech.tech[powerUps.tech.choiceLog[index]]) tech.tech[powerUps.tech.choiceLog[index]].isBanished = true
|
|
// }
|
|
// simulation.makeTextLog(`powerUps.tech.length: ${Math.max(0,powerUps.tech.lastTotalChoices - banishLength)}`)
|
|
// }
|
|
if (tech.isResearchReality) {
|
|
m.switchWorlds()
|
|
simulation.trails()
|
|
simulation.makeTextLog(`simulation.amplitude <span class='color-symbol'>=</span> ${Math.random()}`);
|
|
}
|
|
powerUps[type].effect();
|
|
},
|
|
},
|
|
heal: {
|
|
name: "heal",
|
|
color: "#0eb",
|
|
size() {
|
|
return Math.sqrt(0.1 + 0.25) * 40 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals * (tech.isHalfHeals ? 0.5 : 1)) * (tech.isFlipFlopOn && tech.isFlipFlopHealth ? Math.sqrt(2) : 1); //(simulation.healScale ** 0.25) gives a smaller radius as heal scale goes down
|
|
},
|
|
effect() {
|
|
if (!tech.isEnergyHealth && m.alive) {
|
|
let heal = (this.size / 40 / (simulation.healScale ** 0.25)) ** 2 //simulation.healScale is undone here because heal scale is already properly affected on m.addHealth()
|
|
// console.log("size = " + this.size, "heal = " + heal)
|
|
if (heal > 0) {
|
|
const overHeal = m.health + heal * simulation.healScale - m.maxHealth //used with tech.isOverHeal
|
|
const healOutput = Math.min(m.maxHealth - m.health, heal) * simulation.healScale
|
|
m.addHealth(heal);
|
|
if (healOutput > 0) simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>+=</span> ${(healOutput).toFixed(3)}`) // <br>${m.health.toFixed(3)}
|
|
if (tech.isOverHeal && overHeal > 0) { //tech quenching
|
|
const scaledOverHeal = overHeal // * 0.9
|
|
m.damage(scaledOverHeal);
|
|
simulation.makeTextLog(`<span class='color-var'>m</span>.health <span class='color-symbol'>-=</span> ${(scaledOverHeal).toFixed(3)}`) // <br>${m.health.toFixed(3)}
|
|
simulation.drawList.push({ //add dmg to draw queue
|
|
x: m.pos.x,
|
|
y: m.pos.y,
|
|
radius: scaledOverHeal * 500 * simulation.healScale,
|
|
color: simulation.mobDmgColor,
|
|
time: simulation.drawTime
|
|
});
|
|
tech.extraMaxHealth += scaledOverHeal * simulation.healScale //increase max health
|
|
m.setMaxHealth();
|
|
} else if (overHeal > 0.1) {
|
|
requestAnimationFrame(() => {
|
|
powerUps.directSpawn(this.position.x, this.position.y, "heal", true, null, overHeal * 40 * (simulation.healScale ** 0.25))// directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) {
|
|
});
|
|
}
|
|
if (tech.isHealBrake) {
|
|
const totalTime = 900
|
|
//check if you already have this effect
|
|
let foundActiveEffect = false
|
|
for (let i = 0; i < simulation.ephemera.length; i++) {
|
|
if (simulation.ephemera[i].name === "healPush") {
|
|
foundActiveEffect = true
|
|
simulation.ephemera[i].count = 0.5 * simulation.ephemera[i].count + totalTime //add time
|
|
simulation.ephemera[i].scale = 0.5 * (simulation.ephemera[i].scale + Math.min(Math.max(0.6, heal * 6), 2.3)) //take average of scale
|
|
}
|
|
}
|
|
if (!foundActiveEffect) {
|
|
simulation.ephemera.push({
|
|
name: "healPush",
|
|
count: totalTime, //cycles before it self removes
|
|
range: 0,
|
|
scale: Math.min(Math.max(0.7, heal * 4), 2.2), //typically heal is 0.35
|
|
do() {
|
|
this.count--
|
|
if (this.count < 0) simulation.removeEphemera(this.name)
|
|
this.range = this.range * 0.99 + 0.01 * (300 * this.scale + 100 * Math.sin(m.cycle * 0.022))
|
|
if (this.count < 120) this.range -= 5 * this.scale
|
|
this.range = Math.max(this.range, 1) //don't go negative
|
|
// const range = 300 + 100 * Math.sin(m.cycle * 0.022)
|
|
for (let i = 0; i < mob.length; i++) {
|
|
const distance = Vector.magnitude(Vector.sub(m.pos, mob[i].position))
|
|
if (distance < this.range) {
|
|
const cap = mob[i].isShielded ? 3 : 1
|
|
if (mob[i].speed > cap && Vector.dot(mob[i].velocity, Vector.sub(m.pos, mob[i].position)) > 0) { // if velocity is directed towards player
|
|
Matter.Body.setVelocity(mob[i], Vector.mult(Vector.normalise(mob[i].velocity), cap)); //set velocity to cap, but keep the direction
|
|
}
|
|
}
|
|
}
|
|
ctx.beginPath();
|
|
ctx.arc(m.pos.x, m.pos.y, this.range, 0, 2 * Math.PI);
|
|
ctx.fillStyle = "hsla(200,50%,61%,0.18)";
|
|
ctx.fill();
|
|
},
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (powerUps.healGiveMaxEnergy) {
|
|
tech.healMaxEnergyBonus += 0.08 * tech.largerHeals * (tech.isHalfHeals ? 0.5 : 1)
|
|
m.setMaxEnergy();
|
|
}
|
|
},
|
|
spawn(x, y, size) { //used to spawn a heal with a specific size / heal amount, not normally used
|
|
powerUps.directSpawn(x, y, "heal", false, null, size)
|
|
if (Math.random() < tech.duplicationChance()) {
|
|
powerUps.directSpawn(x, y, "heal", false, null, size)
|
|
powerUp[powerUp.length - 1].isDuplicated = true
|
|
}
|
|
}
|
|
},
|
|
ammo: {
|
|
name: "ammo",
|
|
color: "#467",
|
|
size() {
|
|
return 17;
|
|
},
|
|
effect() {
|
|
if (b.inventory.length > 0) {
|
|
if (tech.isAmmoForGun && b.activeGun !== null) { //give extra ammo to one gun only with tech logistics
|
|
const target = b.guns[b.activeGun]
|
|
if (target.ammo !== Infinity) {
|
|
if (tech.ammoCap) {
|
|
const ammoAdded = Math.ceil(target.ammoPack * 0.7 * tech.ammoCap * 0.8) //0.7 is average
|
|
target.ammo = ammoAdded
|
|
// simulation.makeTextLog(`${target.name}.<span class='color-g'>ammo</span> <span class='color-symbol'>=</span> ${ammoAdded}`)
|
|
} else {
|
|
const ammoAdded = Math.ceil((0.7 * Math.random() + 0.7 * Math.random()) * target.ammoPack * 0.8)
|
|
target.ammo += ammoAdded
|
|
// simulation.makeTextLog(`${target.name}.<span class='color-g'>ammo</span> <span class='color-symbol'>+=</span> ${ammoAdded}`)
|
|
}
|
|
}
|
|
} else { //give ammo to all guns in inventory
|
|
// let textLog = ""
|
|
for (let i = 0, len = b.inventory.length; i < len; i++) {
|
|
const target = b.guns[b.inventory[i]]
|
|
if (target.ammo !== Infinity) {
|
|
if (tech.ammoCap) {
|
|
const ammoAdded = Math.ceil(target.ammoPack * 0.45 * tech.ammoCap) //0.45 is average
|
|
target.ammo = ammoAdded
|
|
// textLog += `${target.name}.<span class='color-g'>ammo</span> <span class='color-symbol'>=</span> ${ammoAdded}<br>`
|
|
} else {
|
|
const ammoAdded = Math.ceil((0.45 * Math.random() + 0.45 * Math.random()) * target.ammoPack) //Math.ceil(Math.random() * target.ammoPack)
|
|
target.ammo += ammoAdded
|
|
// textLog += `${target.name}.<span class='color-g'>ammo</span> <span class='color-symbol'>+=</span> ${ammoAdded}<br>`
|
|
}
|
|
}
|
|
}
|
|
// simulation.makeTextLog(textLog)
|
|
}
|
|
// } else { //give ammo to all guns in inventory
|
|
// for (let i = 0, len = b.inventory.length; i < len; i++) {
|
|
// const target = b.guns[b.inventory[i]]
|
|
// if (target.ammo !== Infinity) {
|
|
// if (tech.ammoCap) {
|
|
// const ammoAdded = Math.ceil(target.ammoPack * 0.45 * tech.ammoCap) //0.45 is average
|
|
// target.ammo = ammoAdded
|
|
// simulation.makeTextLog(`${target.name}.<span class='color-g'>ammo</span> <span class='color-symbol'>=</span> ${ammoAdded}`)
|
|
// } else {
|
|
// const ammoAdded = Math.ceil((0.45 * Math.random() + 0.45 * Math.random()) * target.ammoPack) //Math.ceil(Math.random() * target.ammoPack)
|
|
// target.ammo += ammoAdded
|
|
// simulation.makeTextLog(`${target.name}.<span class='color-g'>ammo</span> <span class='color-symbol'>+=</span> ${ammoAdded}`)
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
simulation.updateGunHUD();
|
|
}
|
|
}
|
|
},
|
|
cancelText(type) {
|
|
// if (localSettings.isHideImages) { }
|
|
|
|
if (tech.isSuperDeterminism) {
|
|
return `<div></div>`
|
|
} else if (tech.isCancelTech) {
|
|
return `<div class='cancel-card' onclick='powerUps.endDraft("${type}",true)' style="width: 115px;">randomize</div>`
|
|
} else {
|
|
return `<div class='cancel-card' onclick='powerUps.endDraft("${type}",true)' style="width: 85px;">cancel</div>`
|
|
}
|
|
},
|
|
researchText(type) {
|
|
let text = ""
|
|
if (type === "entanglement") {
|
|
text += `<div class='choose-grid-module entanglement flipX' onclick='powerUps.endDraft("${type}",true)'>entanglement</div>`
|
|
} else if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) {
|
|
text += `<div onclick="powerUps.research.use('${type}')" class='research-card'>` // style = "margin-left: 192px; margin-right: -192px;"
|
|
tech.junkResearchNumber = Math.ceil(4 * Math.random())
|
|
text += `<div><div> <span style="position:relative;">`
|
|
for (let i = 0; i < tech.junkResearchNumber; i++) {
|
|
text += `<div class="circle-grid junk" style="position:absolute; top:0; left:${15 * i}px ;opacity:0.8; border: 1px #fff solid;width: 1.15em;height: 1.15em;"></div>`
|
|
}
|
|
text += `</span> <span class='research-select'>pseudoscience</span></div></div></div>`
|
|
} else if (powerUps.research.count > 0) {
|
|
text += `<div onclick="powerUps.research.use('${type}')" class='research-card' >` // style = "margin-left: 192px; margin-right: -192px;"
|
|
text += `<div><div><span style="position:relative;">`
|
|
for (let i = 0, len = Math.min(powerUps.research.count, 30); i < len; i++) text += `<div class="circle-grid research" style="font-size:0.82em; position:absolute; top:0; left:${(18 - len * 0.21) * i}px ;opacity:0.8; border: 1px #fff solid;"></div>`
|
|
text += `</span> <span class='research-select'>${tech.isResearchReality ? "<span class='alt'>alternate reality</span>" : "research"}</span></div></div></div>`
|
|
} else {
|
|
text += `<div></div>`
|
|
}
|
|
return text
|
|
},
|
|
researchAndCancelText(type) {
|
|
let text = `<div class='research-cancel'>`
|
|
if (type === "entanglement") {
|
|
text += `<span class='research-card entanglement flipX' style="width: 275px;" onclick='powerUps.endDraft("${type}",true)'><span style="letter-spacing: 6px;">entanglement</span></span>` //‌
|
|
} else if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) {
|
|
text += `<span onclick="powerUps.research.use('${type}')" class='research-card' style="width: 275px;float: left;">` // style = "margin-left: 192px; margin-right: -192px;"
|
|
tech.junkResearchNumber = Math.ceil(4 * Math.random())
|
|
text += `<div><div><span style="position:relative;">`
|
|
for (let i = 0, len = tech.junkResearchNumber; i < len; i++) {
|
|
text += `<div class="circle-grid junk" style="position:absolute; top:0; left:${15 * i}px ;opacity:0.8; border: 1px #fff solid;width: 1.15em;height: 1.15em;"></div>`
|
|
}
|
|
text += `</span> <span class='research-select'>${tech.isResearchReality ? "<span class='alt'>alternate reality</span>" : "research"}</span></div></div></span>`
|
|
} else if (powerUps.research.count > 0) {
|
|
text += `<span onclick="powerUps.research.use('${type}')" class='research-card' style="width: 275px;float: left;">` // style = "margin-left: 192px; margin-right: -192px;"
|
|
text += `<div><div><span style="position:relative;">`
|
|
let researchCap = 18
|
|
if (tech.isCancelTech) researchCap -= 2
|
|
if (canvas.width < 1951) researchCap -= 3
|
|
if (canvas.width < 1711) researchCap -= 4
|
|
for (let i = 0, len = Math.min(powerUps.research.count, researchCap); i < len; i++) {
|
|
text += `<div class="circle-grid research" style="font-size:0.82em; position:absolute; top:0; left:${(18 - len * 0.21) * i}px ;opacity:0.8; border: 1px #fff solid;"></div>`
|
|
}
|
|
text += `</span> <span class='research-select'>${tech.isResearchReality ? "<span class='alt'>alternate reality</span>" : "research"}</span></div></div></span>`
|
|
} else {
|
|
text += `<span class='research-card' style="width: 275px;float: right; background-color: #aaa;color:#888;">research</span>` //‌
|
|
}
|
|
if (tech.isSuperDeterminism) {
|
|
text += `<span class='cancel-card' style="width: 95px;float: right;background-color: #aaa;color:#888;">cancel</span>`
|
|
} else if (tech.isCancelTech) {
|
|
text += `<span class='cancel-card' onclick='powerUps.endDraft("${type}",true)' style="width: 115px;float: right;font-size:0.9em;padding-top:5px">randomize</span>`
|
|
} else {
|
|
text += `<span class='cancel-card' onclick='powerUps.endDraft("${type}",true)' style="width: 95px;float: right;">cancel</span>`
|
|
}
|
|
|
|
return text + "</div>"
|
|
},
|
|
buildColumns(totalChoices, type) {
|
|
let width
|
|
if (canvas.width < 1710) {
|
|
width = "285px"
|
|
} else if (canvas.width < 1950) {
|
|
width = "340px"
|
|
} else {
|
|
width = "384px"
|
|
}
|
|
|
|
let text = ""
|
|
if (localSettings.isHideImages) {
|
|
document.getElementById("choose-grid").style.gridTemplateColumns = width
|
|
text += powerUps.researchAndCancelText(type)
|
|
} else if (totalChoices === 1 || canvas.width < 1200) {
|
|
document.getElementById("choose-grid").style.gridTemplateColumns = width
|
|
text += powerUps.researchAndCancelText(type)
|
|
// console.log('hi')
|
|
// text += powerUps.cancelText(type)
|
|
// text += powerUps.researchText(type)
|
|
} else if (totalChoices === 2) {
|
|
document.getElementById("choose-grid").style.gridTemplateColumns = `repeat(2, ${width})`
|
|
text += powerUps.researchText(type)
|
|
text += powerUps.cancelText(type)
|
|
} else {
|
|
document.getElementById("choose-grid").style.gridTemplateColumns = `repeat(3, ${width})`
|
|
text += "<div></div>"
|
|
text += powerUps.researchText(type)
|
|
text += powerUps.cancelText(type)
|
|
}
|
|
return text
|
|
},
|
|
// researchAndCancelText(type) {
|
|
// let text = "<div class= 'choose-grid-module'>"
|
|
// if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) {
|
|
// text += `<div onclick="powerUps.research.use('${type}')" class='choose-grid-module research-card'>` // style = "margin-left: 192px; margin-right: -192px;"
|
|
// tech.junkResearchNumber = Math.ceil(4 * Math.random())
|
|
// text += `<div><div> <span style="position:relative;">`
|
|
// for (let i = 0; i < tech.junkResearchNumber; i++) text += `<div class="circle-grid junk" style="position:absolute; top:0; left:${15*i}px ;opacity:0.8; border: 1px #fff solid;"></div>`
|
|
// text += `</span> <span class='research-select'>pseudoscience</span></div></div></div>`
|
|
// } else if (powerUps.research.count > 0) {
|
|
// text += `<div onclick="powerUps.research.use('${type}')" class='choose-grid-module research-card' >` // style = "margin-left: 192px; margin-right: -192px;"
|
|
// text += `<div><div><span style="position:relative;">`
|
|
// for (let i = 0, len = Math.min(powerUps.research.count, 30); i < len; i++) text += `<div class="circle-grid research" style="position:absolute; top:0; left:${(18 - len*0.21)*i}px ;opacity:0.8; border: 1px #fff solid;"></div>`
|
|
// text += `</span> <span class='research-select'>${tech.isResearchReality?"<span class='alt'>alternate reality</span>": "research"}</span></div></div></div>`
|
|
// } else {
|
|
// text += `<div></div>`
|
|
// }
|
|
// return text + '</div>'
|
|
// },
|
|
hideStyle: `style="height:auto; border: none; background-color: transparent;"`,
|
|
gunText(choose, click) {
|
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/gun/${b.guns[choose].name}.webp');"`
|
|
return `<div class="choose-grid-module card-background" onclick="${click}" onauxclick="${click}" ${style}>
|
|
<div class="card-text">
|
|
<div class="grid-title"><div class="circle-grid gun"></div> ${b.guns[choose].name}</div>
|
|
${b.guns[choose].description}</div></div>`
|
|
},
|
|
fieldText(choose, click) {
|
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/field/${m.fieldUpgrades[choose].name}${choose === 0 ? Math.floor(Math.random() * 10) : ""}.webp');"`
|
|
return `<div class="choose-grid-module card-background" onclick="${click}" onauxclick="${click}"${style}>
|
|
<div class="card-text">
|
|
<div class="grid-title"><div class="circle-grid field"></div> ${m.fieldUpgrades[choose].name}</div>
|
|
${m.fieldUpgrades[choose].description}</div></div>`
|
|
},
|
|
techText(choose, click) {
|
|
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
|
const style = localSettings.isHideImages || tech.tech[choose].isLore ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
|
return `<div class="choose-grid-module card-background" onclick="${click}" onauxclick="${click}"${style}>
|
|
<div class="card-text">
|
|
<div class="grid-title"><div class="circle-grid tech"></div> ${tech.tech[choose].name} ${techCountText}</div>
|
|
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
|
},
|
|
skinTechText(choose, click) {
|
|
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
|
return `<div class="choose-grid-module card-background" onclick="${click}" onauxclick="${click}"${style}>
|
|
<div class="card-text">
|
|
<div class="grid-title">
|
|
<span style="position:relative;">
|
|
<div class="circle-grid-skin"></div>
|
|
<div class="circle-grid-skin-eye"></div>
|
|
</span>
|
|
${tech.tech[choose].name} ${techCountText}</div>
|
|
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
|
},
|
|
fieldTechText(choose, click) {
|
|
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
|
return `<div class="choose-grid-module card-background" onclick="${click}" onauxclick="${click}"${style}>
|
|
<div class="card-text">
|
|
<div class="grid-title">
|
|
<span style="position:relative;">
|
|
<div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
|
|
<div class="circle-grid field" style="position:absolute; top:0; left:10px;opacity:0.65;"></div>
|
|
</span>
|
|
${tech.tech[choose].name} ${techCountText}</div>
|
|
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
|
},
|
|
gunTechText(choose, click) {
|
|
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
|
return `<div class="choose-grid-module card-background" onclick="${click}" onauxclick="${click}"${style}>
|
|
<div class="card-text">
|
|
<div class="grid-title">
|
|
<span style="position:relative;">
|
|
<div class="circle-grid tech" style="position:absolute; top:0; left:0;opacity:0.8;"></div>
|
|
<div class="circle-grid gun" style="position:absolute; top:0; left:10px; opacity:0.65;"></div>
|
|
</span>
|
|
${tech.tech[choose].name} ${techCountText}</div>
|
|
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
|
},
|
|
junkTechText(choose, click) {
|
|
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-size: contain;background-repeat: no-repeat;background-image: url('img/junk.webp');"`
|
|
if (!localSettings.isHideImages) {
|
|
setTimeout(() => { //delay so that the html element exists
|
|
if (tech.tech[choose].url === undefined) { //if on url has been set yet
|
|
const url = "https://images.search.yahoo.com/search/images?p=" + tech.tech[choose].name;
|
|
fetch(url, { signal: AbortSignal.timeout(1000) }) //give up if it takes over 1 second
|
|
.then((response) => response.text())
|
|
.then((html) => {
|
|
const parser = new DOMParser();
|
|
const doc = parser.parseFromString(html, "text/html");
|
|
const elements = doc.getElementsByClassName("ld");
|
|
// console.log(i, elements[i].getAttribute("data"), JSON.parse(elements[i].getAttribute("data")).iurl)
|
|
const index = Math.floor(Math.random() * 4) //randomly choose from the first 4 images
|
|
if (parseInt(JSON.parse(elements[index].getAttribute("data")).s.slice(0, -2)) < 500) { //make sure it isn't too big
|
|
tech.tech[choose].url = JSON.parse(elements[index].getAttribute("data")).iurl //store the url
|
|
document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')` //make the url the background image
|
|
} else if (parseInt(JSON.parse(elements[index + 1].getAttribute("data")).s.slice(0, -2)) < 500) { //try a different images and see if it is smaller
|
|
tech.tech[choose].url = JSON.parse(elements[index + 1].getAttribute("data")).iurl
|
|
document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')`
|
|
} else if (parseInt(JSON.parse(elements[index + 2].getAttribute("data")).s.slice(0, -2)) < 500) { //try a different images and see if it is smaller
|
|
tech.tech[choose].url = JSON.parse(elements[index + 2].getAttribute("data")).iurl
|
|
document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')`
|
|
}
|
|
});
|
|
} else {
|
|
document.getElementById(`junk-${choose}`).style.backgroundImage = `url('${tech.tech[choose].url}')`
|
|
}
|
|
}, 1);
|
|
}
|
|
return `<div id = "junk-${choose}" class="choose-grid-module card-background" onclick="${click}" onauxclick="${click}"${style}>
|
|
<div class="card-text">
|
|
<div class="grid-title"><div class="circle-grid junk"></div> ${tech.tech[choose].name} ${techCountText}</div>
|
|
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
|
},
|
|
incoherentTechText(choose, click) {
|
|
// text += `<div class="choose-grid-module" style = "background-color: #efeff5; border: 0px; opacity:0.5; font-size: 60%; line-height: 130%; margin: 1px; padding-top: 6px; padding-bottom: 6px;"><div class="grid-title">${tech.tech[choose].name} <span style = "color: #aaa;font-weight: normal;font-size:80%;">- incoherent</span></div></div>`
|
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
|
return `<div class="choose-grid-module card-background" ${style}>
|
|
<div class="card-text" style = "background-color: #efeff5;">
|
|
<div class="grid-title" style = "color: #ddd;font-weight: normal;">incoherent</div> <br> <br>
|
|
</div></div>`
|
|
},
|
|
gun: {
|
|
name: "gun",
|
|
color: "#26a",
|
|
size() {
|
|
return 35;
|
|
},
|
|
effect() {
|
|
if (m.alive) {
|
|
let options = [];
|
|
for (let i = 0; i < b.guns.length; i++) {
|
|
if (!b.guns[i].have) options.push(i);
|
|
}
|
|
let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2 + tech.extraChoices + 2 * (m.fieldMode === 8)))
|
|
if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
|
|
function removeOption(index) {
|
|
for (let i = 0; i < options.length; i++) {
|
|
if (options[i] === index) {
|
|
options.splice(i, 1) //remove a previous choice from option pool
|
|
return
|
|
}
|
|
}
|
|
}
|
|
//check for guns that were a choice last time and remove them
|
|
for (let i = 0; i < b.guns.length; i++) {
|
|
if (options.length - 1 < totalChoices) break //you have to repeat choices if there are not enough choices left to display
|
|
if (b.guns[i].isRecentlyShown) removeOption(i)
|
|
}
|
|
for (let i = 0; i < b.guns.length; i++) b.guns[i].isRecentlyShown = false //reset recently shown back to zero
|
|
if (options.length > 0) {
|
|
let text = powerUps.buildColumns(totalChoices, "gun")
|
|
for (let i = 0; i < totalChoices; i++) {
|
|
const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
|
|
// text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${choose})"><div class="grid-title"><div class="circle-grid gun"></div> ${b.guns[choose].name}</div> ${b.guns[choose].description}</div>`
|
|
text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`)
|
|
|
|
b.guns[choose].isRecentlyShown = true
|
|
removeOption(choose)
|
|
if (options.length < 1) break
|
|
}
|
|
if (tech.isExtraBotOption) {
|
|
const botTech = [] //make an array of bot options
|
|
for (let i = 0, len = tech.tech.length; i < len; i++) {
|
|
if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i)
|
|
}
|
|
if (botTech.length > 0) { //pick random bot tech
|
|
// const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
|
// const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : "";
|
|
// text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"> <span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
|
|
const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
|
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
|
text += `<div class="choose-grid-module card-background" onclick="powerUps.choose('tech',${choose})" ${style}>
|
|
<div class="card-text">
|
|
<div class="grid-title"><span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${techCountText}</div>
|
|
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
|
}
|
|
}
|
|
if (tech.isOneGun && b.inventory.length > 0) text += `<div style = "color: #f24">replaces your current gun</div>`
|
|
document.getElementById("choose-grid").innerHTML = text
|
|
powerUps.showDraft();
|
|
}
|
|
}
|
|
},
|
|
},
|
|
field: {
|
|
name: "field",
|
|
color: "#0cf",
|
|
size() {
|
|
return 45;
|
|
},
|
|
effect() {
|
|
if (m.alive) {
|
|
let options = [];
|
|
for (let i = 1; i < m.fieldUpgrades.length; i++) { //skip field emitter
|
|
if (i !== m.fieldMode) options.push(i);
|
|
}
|
|
let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2 + tech.extraChoices + 2 * (m.fieldMode === 8)))
|
|
if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
|
|
|
|
function removeOption(index) {
|
|
for (let i = 0; i < options.length; i++) {
|
|
if (options[i] === index) {
|
|
options.splice(i, 1) //remove a previous choice from option pool
|
|
return
|
|
}
|
|
}
|
|
}
|
|
//check for fields that were a choice last time and remove them
|
|
for (let i = 0; i < m.fieldUpgrades.length; i++) {
|
|
if (options.length - 1 < totalChoices) break //you have to repeat choices if there are not enough choices left to display
|
|
if (m.fieldUpgrades[i].isRecentlyShown) removeOption(i)
|
|
}
|
|
for (let i = 0; i < m.fieldUpgrades.length; i++) m.fieldUpgrades[i].isRecentlyShown = false //reset recently shown back to zero
|
|
|
|
if (options.length > 0 || tech.isExtraBotOption) {
|
|
let text = powerUps.buildColumns(totalChoices, "field")
|
|
for (let i = 0; i < totalChoices; i++) {
|
|
const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
|
|
//text += `<div class="choose-grid-module" onclick="powerUps.choose('field',${choose})"><div class="grid-title"><div class="circle-grid field"></div> ${m.fieldUpgrades[choose].name}</div> ${m.fieldUpgrades[choose].description}</div>` //default
|
|
text += powerUps.fieldText(choose, `powerUps.choose('field',${choose})`)
|
|
m.fieldUpgrades[choose].isRecentlyShown = true
|
|
removeOption(choose)
|
|
if (options.length < 1) break
|
|
}
|
|
if (tech.isExtraBotOption) {
|
|
const botTech = [] //make an array of bot options
|
|
for (let i = 0, len = tech.tech.length; i < len; i++) {
|
|
if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed()) botTech.push(i)
|
|
}
|
|
if (botTech.length > 0) { //pick random bot tech
|
|
// const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
|
// const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : "";
|
|
// text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"> <span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
|
|
const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
|
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
|
text += `<div class="choose-grid-module card-background" onclick="powerUps.choose('tech',${choose})" ${style}>
|
|
<div class="card-text">
|
|
<div class="grid-title"><span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${techCountText}</div>
|
|
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
|
}
|
|
}
|
|
document.getElementById("choose-grid").innerHTML = text
|
|
powerUps.showDraft();
|
|
}
|
|
}
|
|
},
|
|
},
|
|
tech: {
|
|
name: "tech",
|
|
color: "hsl(246,100%,77%)", //"#a8f",
|
|
size() {
|
|
return 42;
|
|
},
|
|
effect() {
|
|
if (m.alive) {
|
|
let junkCount = 0 //used for junk estimation
|
|
let totalCount = 0 //used for junk estimation
|
|
let options = []; //generate all options
|
|
optionLengthNoDuplicates = 0
|
|
for (let i = 0; i < tech.tech.length; i++) {
|
|
if (tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isBanished) {
|
|
totalCount += tech.tech[i].frequency
|
|
if (tech.tech[i].isJunk) junkCount += tech.tech[i].frequency
|
|
if (tech.tech[i].frequency > 0) optionLengthNoDuplicates++
|
|
for (let j = 0, len = tech.tech[i].frequency; j < len; j++) options.push(i);
|
|
}
|
|
}
|
|
function removeOption(index) {
|
|
for (let i = options.length - 1; i > -1; i--) {
|
|
if (index === options[i]) {
|
|
options.splice(i, 1) //remove all copies of that option form the options array (some tech are in the options array multiple times because of frequency)
|
|
optionLengthNoDuplicates--
|
|
}
|
|
if (options.length < 1) return;
|
|
}
|
|
}
|
|
//set total choices
|
|
let totalChoices = (tech.isDeterminism ? 1 : 3 + tech.extraChoices + 2 * (m.fieldMode === 8))
|
|
if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay
|
|
if (optionLengthNoDuplicates < totalChoices + 1) { //if not enough options for all the choices
|
|
totalChoices = optionLengthNoDuplicates
|
|
if (tech.isBanish) { //when you run out of options eject banish
|
|
for (let i = 0, len = tech.tech.length; i < len; i++) {
|
|
if (tech.tech[i].name === "decoherence") powerUps.ejectTech(i, true)
|
|
}
|
|
simulation.makeTextLog(`decoherence <span class='color-var'>tech</span> ejected`)
|
|
simulation.makeTextLog(`options reset`)
|
|
}
|
|
}
|
|
if (tech.tooManyTechChoices) {
|
|
tech.tooManyTechChoices = false
|
|
totalChoices = optionLengthNoDuplicates
|
|
}
|
|
if (optionLengthNoDuplicates > totalChoices) { //check for tech that were a choice last time and remove them
|
|
for (let i = 0; i < tech.tech.length; i++) {
|
|
if (optionLengthNoDuplicates > totalChoices) {
|
|
if (tech.tech[i].isRecentlyShown) removeOption(i)
|
|
} else {
|
|
break //you have to repeat choices if there are not enough choices left to display
|
|
}
|
|
|
|
}
|
|
}
|
|
for (let i = 0; i < tech.tech.length; i++) tech.tech[i].isRecentlyShown = false //reset recently shown back to zero
|
|
if (options.length > 0) {
|
|
let text = powerUps.buildColumns(totalChoices, "tech")
|
|
for (let i = 0; i < totalChoices; i++) {
|
|
if (options.length < 1) break
|
|
const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options
|
|
if (tech.isBanish) {
|
|
tech.tech[choose].isBanished = true
|
|
if (i === 0) simulation.makeTextLog(`options.length = ${optionLengthNoDuplicates}`)
|
|
}
|
|
removeOption(choose) //move from future options pool to avoid repeats on this selection
|
|
tech.tech[choose].isRecentlyShown = true //this flag prevents this option from being shown the next time you pick up a tech power up
|
|
const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
|
if (tech.tech[choose].isFieldTech) {
|
|
text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`)
|
|
} else if (tech.tech[choose].isGunTech) {
|
|
text += powerUps.gunTechText(choose, `powerUps.choose('tech',${choose})`)
|
|
} else if (tech.tech[choose].isJunk) {
|
|
text += powerUps.junkTechText(choose, `powerUps.choose('tech',${choose})`)
|
|
} else if (tech.tech[choose].isSkin) {
|
|
text += powerUps.skinTechText(choose, `powerUps.choose('tech',${choose})`)
|
|
} else { //normal tech
|
|
text += powerUps.techText(choose, `powerUps.choose('tech',${choose})`)
|
|
}
|
|
if (options.length < 1) break
|
|
}
|
|
if (tech.isExtraBotOption) {
|
|
const botTech = [] //make an array of bot options
|
|
for (let i = 0, len = tech.tech.length; i < len; i++) {
|
|
if (tech.tech[i].isBotTech && tech.tech[i].count < tech.tech[i].maxCount && tech.tech[i].allowed() && !tech.tech[i].isRecentlyShown) botTech.push(i)
|
|
}
|
|
if (botTech.length > 0) { //pick random bot tech
|
|
// const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
|
// const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : "";
|
|
// text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title"> <span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${isCount}</div> ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
|
|
const choose = botTech[Math.floor(Math.random() * botTech.length)];
|
|
const techCountText = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
|
text += `<div class="choose-grid-module card-background" onclick="powerUps.choose('tech',${choose})" ${style}>
|
|
<div class="card-text">
|
|
<div class="grid-title"><span style = "font-size: 150%;font-family: 'Courier New', monospace;">⭓▸●■</span> ${tech.tech[choose].name} ${techCountText}</div>
|
|
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
|
}
|
|
}
|
|
if (tech.isMassProduction) {
|
|
// const techOptions = [] //make an array of bot options
|
|
// for (let i = 0, len = tech.tech.length; i < len; i++) {
|
|
// if (tech.tech[i].isMassProduction) techOptions.push(i)
|
|
// }
|
|
// if (techOptions.length > 0) { //pick random bot tech
|
|
// const choose = techOptions[Math.floor(Math.random() * techOptions.length)];
|
|
// const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"`
|
|
// text += `<div class="choose-grid-module card-background" onclick="powerUps.choose('tech',${choose})" ${style}>
|
|
// <div class="card-text">
|
|
// <div class="grid-title">${tech.tech[choose].name}</div>
|
|
// ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div></div>`
|
|
// }
|
|
for (let i = 0, len = tech.tech.length; i < len; i++) {
|
|
if (tech.tech[i].isMassProduction) {
|
|
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[i].name}.webp');"`
|
|
text += `<div class="choose-grid-module card-background" onclick="powerUps.choose('tech',${i})" ${style}>
|
|
<div class="card-text">
|
|
<div class="grid-title">${tech.tech[i].name}</div>
|
|
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() : tech.tech[i].description}</div></div>`
|
|
}
|
|
}
|
|
}
|
|
if (tech.isExtraGunField) {
|
|
if (Math.random() > 0.5 && b.inventory.length < b.guns.length) {
|
|
let gunOptions = [];
|
|
for (let i = 0; i < b.guns.length; i++) {
|
|
if (!b.guns[i].have) gunOptions.push(i);
|
|
}
|
|
const pick = gunOptions[Math.floor(Math.seededRandom(0, gunOptions.length))] //pick an element from the array of options
|
|
// text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${pick})"><div class="grid-title"><div class="circle-grid gun"></div> ${b.guns[pick].name}</div> ${b.guns[pick].description}</div>`
|
|
text += powerUps.gunText(pick, `powerUps.choose('gun',${pick})`)
|
|
} else {
|
|
let fieldOptions = [];
|
|
for (let i = 1; i < m.fieldUpgrades.length; i++) { //skip field emitter
|
|
if (i !== m.fieldMode) fieldOptions.push(i);
|
|
}
|
|
const pick = fieldOptions[Math.floor(Math.seededRandom(0, fieldOptions.length))] //pick an element from the array of options
|
|
// text += `<div class="choose-grid-module" onclick="powerUps.choose('field',${pick})"><div class="grid-title"><div class="circle-grid field"></div> ${m.fieldUpgrades[pick].name}</div> ${m.fieldUpgrades[pick].description}</div>`
|
|
text += powerUps.fieldText(pick, `powerUps.choose('field',${pick})`)
|
|
}
|
|
}
|
|
// if (tech.isMicroTransactions && powerUps.research.count > 0) {
|
|
// const skins = [] //find skins
|
|
// for (let i = 0; i < tech.tech.length; i++) {
|
|
// if (tech.tech[i].isSkin) skins.push(i)
|
|
// }
|
|
// const choose = skins[Math.floor(Math.seededRandom(0, skins.length))] //pick an element from the array of options
|
|
|
|
// text += `<div class="choose-grid-module" onclick="tech.giveTech(${choose});powerUps.research.changeRerolls(-1);powerUps.endDraft('tech');powerUps.tech.effect();"><div class="grid-title"><div class="circle-grid research"></div> <span style = 'font-size:90%; font-weight: 100; letter-spacing: -1.5px;'>microtransaction:</span> ${tech.tech[choose].name}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
|
|
// }
|
|
if (tech.isBrainstorm && !tech.isBrainstormActive && !simulation.isChoosing) {
|
|
tech.isBrainstormActive = true
|
|
|
|
let count = 1
|
|
let timeStart = performance.now()
|
|
const cycle = (timestamp) => {
|
|
// if (timeStart === undefined) timeStart = timestamp
|
|
// console.log(timestamp, timeStart)
|
|
if (timestamp - timeStart > tech.brainStormDelay * count && simulation.isChoosing) {
|
|
count++
|
|
powerUps.tech.effect();
|
|
document.getElementById("choose-grid").style.pointerEvents = "auto"; //turn off the normal 500ms delay
|
|
document.body.style.cursor = "auto";
|
|
document.getElementById("choose-grid").style.transitionDuration = "0s";
|
|
}
|
|
if (count < 5 && simulation.isChoosing) {
|
|
requestAnimationFrame(cycle);
|
|
} else {
|
|
tech.isBrainstormActive = false
|
|
}
|
|
}
|
|
requestAnimationFrame(cycle);
|
|
|
|
// count++
|
|
// if (count < tech.brainStormDelay * 5 && simulation.isChoosing) {
|
|
// if (!(count % tech.brainStormDelay)) {
|
|
// powerUps.tech.effect();
|
|
// document.getElementById("choose-grid").style.pointerEvents = "auto"; //turn off the normal 500ms delay
|
|
// document.body.style.cursor = "auto";
|
|
// document.getElementById("choose-grid").style.transitionDuration = "0s";
|
|
// }
|
|
// requestAnimationFrame(cycle);
|
|
// } else {
|
|
// tech.isBrainstormActive = false
|
|
// }
|
|
}
|
|
// if (localSettings.isHideImages) text += powerUps.researchText('tech')
|
|
document.getElementById("choose-grid").innerHTML = text
|
|
powerUps.showDraft();
|
|
|
|
//fade in all circles
|
|
// requestAnimationFrame(() => {
|
|
// var elements = document.getElementsByClassName('circle-grid');
|
|
// for (var i in elements) {
|
|
// if (elements.hasOwnProperty(i)) {
|
|
// elements[i].style.opacity = '1';
|
|
// }
|
|
// }
|
|
// });
|
|
}
|
|
}
|
|
},
|
|
},
|
|
entanglement: {
|
|
name: "entanglement",
|
|
color: "#fff", //"hsl(248,100%,65%)",
|
|
size() {
|
|
return 40
|
|
},
|
|
effect() {
|
|
if (m.alive && localSettings.entanglement) {
|
|
// let text = ""
|
|
// document.getElementById("choose-grid").style.gridTemplateColumns = "384px 384px 384px"
|
|
let text = powerUps.buildColumns(3, "entanglement")
|
|
|
|
// text += powerUps.researchText('tech')
|
|
// text += "<div></div>"
|
|
// text += "<div class='choose-grid-module entanglement flipX'>entanglement</div>"
|
|
// text += `<div class='choose-grid-module' onclick='powerUps.endDraft("tech",true)' style="width: 82px; text-align: center;font-size: 1.1em;font-weight: 100;justify-self: end;">cancel</div>` //powerUps.cancelText('tech')
|
|
if (localSettings.entanglement.fieldIndex && localSettings.entanglement.fieldIndex !== m.fieldMode) {
|
|
const choose = localSettings.entanglement.fieldIndex //add field
|
|
text += powerUps.fieldText(choose, `powerUps.choose('field',${choose})`)
|
|
}
|
|
for (let i = 0; i < localSettings.entanglement.gunIndexes.length; i++) { //add guns
|
|
const choose = localSettings.entanglement.gunIndexes[i]
|
|
//check if you always have this gun
|
|
let alreadyHasGun = false
|
|
for (let j = 0; j < b.inventory.length; j++) {
|
|
if (b.inventory[j] === choose) alreadyHasGun = true
|
|
}
|
|
// text += `<div class="choose-grid-module" onclick="powerUps.choose('gun',${gun})"><div class="grid-title"><div class="circle-grid gun"></div> ${b.guns[gun].name}</div> ${b.guns[gun].description}</div>`
|
|
if (!alreadyHasGun) text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`)
|
|
}
|
|
for (let i = 0; i < localSettings.entanglement.techIndexes.length; i++) { //add tech
|
|
let choose = localSettings.entanglement.techIndexes[i]
|
|
const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count + 1}x)` : "";
|
|
|
|
if (choose === null || tech.tech[choose].count + 1 > tech.tech[choose].maxCount || !tech.tech[choose].allowed()) {
|
|
// text += `<div class="choose-grid-module" style = "background-color: #efeff5; border: 0px; opacity:0.5; font-size: 60%; line-height: 130%; margin: 1px; padding-top: 6px; padding-bottom: 6px;"><div class="grid-title">${tech.tech[choose].name} <span style = "color: #aaa;font-weight: normal;font-size:80%;">- incoherent</span></div></div>`
|
|
text += powerUps.incoherentTechText(choose)
|
|
} else {
|
|
if (tech.tech[choose].isFieldTech) {
|
|
text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`)
|
|
} else if (tech.tech[choose].isGunTech) {
|
|
text += powerUps.gunTechText(choose, `powerUps.choose('tech',${choose})`)
|
|
} else if (tech.tech[choose].isLore) {
|
|
text += `<div class="choose-grid-module" onclick="powerUps.choose('tech',${choose})"><div class="grid-title lore-text"><div class="circle-grid lore"></div> ${tech.tech[choose].name} ${isCount}</div>${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}</div>`
|
|
} else if (tech.tech[choose].isJunk) {
|
|
text += powerUps.junkTechText(choose, `powerUps.choose('tech',${choose})`)
|
|
} else if (tech.tech[choose].isSkin) {
|
|
text += powerUps.skinTechText(choose, `powerUps.choose('tech',${choose})`)
|
|
} else { //normal tech
|
|
text += powerUps.techText(choose, `powerUps.choose('tech',${choose})`)
|
|
}
|
|
}
|
|
}
|
|
// document.getElementById("choose-grid").classList.add("flipX");
|
|
document.getElementById("choose-grid").innerHTML = text
|
|
powerUps.showDraft();
|
|
localSettings.entanglement = undefined
|
|
if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage
|
|
}
|
|
},
|
|
},
|
|
spawnDelay(type, num) {
|
|
let count = num
|
|
let cycle = () => {
|
|
if (count > 0) {
|
|
if (m.alive) requestAnimationFrame(cycle);
|
|
if (!simulation.paused && !simulation.isChoosing) { //&& !(simulation.cycle % 2)
|
|
count--
|
|
const where = {
|
|
x: m.pos.x + 50 * (Math.random() - 0.5),
|
|
y: m.pos.y + 50 * (Math.random() - 0.5)
|
|
}
|
|
powerUps.spawn(where.x, where.y, type);
|
|
}
|
|
}
|
|
}
|
|
requestAnimationFrame(cycle);
|
|
},
|
|
onPickUp(who) {
|
|
powerUps.research.currentRerollCount = 0
|
|
if (tech.isTechDamage && who.name === "tech") m.damage(0.1)
|
|
if (tech.isMassEnergy) m.energy += 2;
|
|
if (tech.isMineDrop && bullet.length < 150 && Math.random() < 0.5) {
|
|
if (tech.isLaserMine && input.down) {
|
|
b.laserMine(who.position)
|
|
} else {
|
|
b.mine(who.position, { x: 0, y: 0 }, 0)
|
|
}
|
|
}
|
|
if (tech.isRelay) {
|
|
if (tech.isFlipFlopOn) {
|
|
tech.isFlipFlopOn = false
|
|
if (document.getElementById("tech-switch")) document.getElementById("tech-switch").innerHTML = ` = <strong>OFF</strong>`
|
|
m.eyeFillColor = 'transparent'
|
|
} else {
|
|
tech.isFlipFlopOn = true //immune to damage this hit, lose immunity for next hit
|
|
if (document.getElementById("tech-switch")) document.getElementById("tech-switch").innerHTML = ` = <strong>ON</strong>`
|
|
m.eyeFillColor = m.fieldMeterColor //'#0cf'
|
|
}
|
|
if (tech.isRelayEnergy) m.setMaxEnergy();
|
|
}
|
|
},
|
|
spawnRandomPowerUp(x, y) { //mostly used after mob dies, doesn't always return a power up
|
|
if (!tech.isEnergyHealth && (Math.random() * Math.random() - 0.3 > Math.sqrt(m.health)) || Math.random() < 0.04) { //spawn heal chance is higher at low health
|
|
powerUps.spawn(x, y, "heal");
|
|
return;
|
|
}
|
|
if (Math.random() < 0.15 && b.inventory.length > 0) {
|
|
powerUps.spawn(x, y, "ammo");
|
|
return;
|
|
}
|
|
if (Math.random() < 0.0007 * (3 - b.inventory.length)) { //a new gun has a low chance for each not acquired gun up to 3
|
|
powerUps.spawn(x, y, "gun");
|
|
return;
|
|
}
|
|
// if (Math.random() < 0.0027 * (22 - tech.totalCount)) { //a new tech has a low chance for each not acquired tech up to 25
|
|
if (Math.random() < 0.005 * (10 - level.levelsCleared)) { //a new tech has a low chance that decreases in later levels
|
|
powerUps.spawn(x, y, "tech");
|
|
return;
|
|
}
|
|
if (Math.random() < 0.0015) {
|
|
powerUps.spawn(x, y, "field");
|
|
return;
|
|
}
|
|
if (tech.isCouplingPowerUps && Math.random() < 0.17) {
|
|
powerUps.spawn(x, y, "coupling");
|
|
return;
|
|
}
|
|
if (tech.isBoostPowerUps && Math.random() < 0.14) {
|
|
powerUps.spawn(x, y, "boost");
|
|
return;
|
|
}
|
|
// if (Math.random() < 0.01) {
|
|
// powerUps.spawn(x, y, "research");
|
|
// return;
|
|
// }
|
|
},
|
|
randomPowerUpCounter: 0,
|
|
isFieldSpawned: false, //makes it so a field spawns once but not more times
|
|
spawnBossPowerUp(x, y) { //boss spawns field and gun tech upgrades
|
|
if (level.levels[level.onLevel] !== "final") {
|
|
// if (level.levelsCleared === 1) powerUps.spawn(x, y, "field")
|
|
// if (m.fieldMode === 0 && !m.coupling) {
|
|
if (!powerUps.isFieldSpawned) {
|
|
powerUps.isFieldSpawned = true
|
|
powerUps.spawn(x, y, "field")
|
|
} else {
|
|
powerUps.randomPowerUpCounter++;
|
|
powerUpChance(Math.max(level.levelsCleared, 10) * 0.1)
|
|
}
|
|
if (!(simulation.difficulty > spawn.secondaryBossThreshold)) {
|
|
powerUps.randomPowerUpCounter += 0.6;
|
|
powerUpChance(Math.max(level.levelsCleared, 6) * 0.1)
|
|
}
|
|
|
|
function powerUpChance(chanceToFail) {
|
|
if (Math.random() * chanceToFail < powerUps.randomPowerUpCounter) {
|
|
powerUps.randomPowerUpCounter = 0;
|
|
if (Math.random() < 0.97) {
|
|
powerUps.spawn(x, y, "tech")
|
|
} else {
|
|
powerUps.spawn(x, y, "gun")
|
|
}
|
|
} else {
|
|
if (m.health < 0.65 && !tech.isEnergyHealth) {
|
|
powerUps.spawn(x, y, "heal");
|
|
powerUps.spawn(x, y, "heal");
|
|
} else {
|
|
powerUps.spawn(x, y, "ammo");
|
|
powerUps.spawn(x, y, "ammo");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris
|
|
if (Math.random() < 0.5) {
|
|
powerUps.spawn(x, y, "heal", false);
|
|
} else {
|
|
powerUps.spawn(x, y, "ammo", false);
|
|
}
|
|
},
|
|
addResearchToLevel() { //add a random power up to a location that has a mob, mostly used to give each level one randomly placed research
|
|
if (mob.length && Math.random() < 0.45 - 0.3 * (simulation.difficultyMode > 5)) { //lower chance on why difficulty
|
|
const index = Math.floor(Math.random() * mob.length)
|
|
powerUps.spawn(mob[index].position.x, mob[index].position.y, "research");
|
|
}
|
|
},
|
|
spawnStartingPowerUps(x, y) { //used for map specific power ups, mostly to give player a starting gun
|
|
if (level.levelsCleared < 4) { //runs on first 4 levels on all difficulties
|
|
if (level.levelsCleared > 1) powerUps.spawn(x, y, "tech")
|
|
if (b.inventory.length === 0) {
|
|
powerUps.spawn(x, y, "gun", false); //first gun
|
|
} else if (tech.totalCount === 0) { //first tech
|
|
powerUps.spawn(x, y, "tech", false);
|
|
} else if (b.inventory.length === 1) { //second gun or extra ammo
|
|
if (Math.random() < 0.4) {
|
|
powerUps.spawn(x, y, "gun", false);
|
|
} else {
|
|
for (let i = 0; i < 5; i++) powerUps.spawn(x, y, "ammo", false);
|
|
}
|
|
} else {
|
|
for (let i = 0; i < 4; i++) powerUps.spawnRandomPowerUp(x, y);
|
|
}
|
|
} else { //after the first 4 levels just spawn a random power up
|
|
for (let i = 0; i < 3; i++) powerUps.spawnRandomPowerUp(x, y);
|
|
}
|
|
},
|
|
ejectTech(choose = 'random', isOverride = false) {
|
|
if (!simulation.isChoosing || isOverride) {
|
|
// console.log(tech.tech[choose].name, tech.tech[choose].count, tech.tech[choose].isNonRefundable)
|
|
//find which tech you have
|
|
if (choose === 'random') {
|
|
const have = []
|
|
for (let i = 0; i < tech.tech.length; i++) {
|
|
if (tech.tech[i].count > 0 && !tech.tech[i].isNonRefundable) have.push(i)
|
|
}
|
|
// if (have.length === 0) {
|
|
// for (let i = 0; i < tech.tech.length; i++) {
|
|
// if (tech.tech[i].count > 0) have.push(i)
|
|
// }
|
|
// }
|
|
|
|
if (have.length) {
|
|
choose = have[Math.floor(Math.random() * have.length)]
|
|
simulation.makeTextLog(`<span class='color-var'>tech</span>.remove("<span class='color-text'>${tech.tech[choose].name}</span>")`)
|
|
|
|
for (let i = 0; i < tech.tech[choose].count; i++) {
|
|
powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
|
|
// powerUp[powerUp.length - 1].isDuplicated = true
|
|
}
|
|
// remove a random tech from the list of tech you have
|
|
tech.tech[choose].remove();
|
|
tech.tech[choose].count = 0;
|
|
tech.tech[choose].isLost = true;
|
|
simulation.updateTechHUD();
|
|
m.fieldCDcycle = m.cycle + 30; //disable field so you can't pick up the ejected tech
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
} else if (tech.tech[choose].count && !tech.tech[choose].isNonRefundable) {
|
|
simulation.makeTextLog(`<span class='color-var'>tech</span>.remove("<span class='color-text'>${tech.tech[choose].name}</span>")`)
|
|
|
|
for (let i = 0; i < tech.tech[choose].count; i++) {
|
|
powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
|
|
powerUp[powerUp.length - 1].isDuplicated = true
|
|
}
|
|
// remove a random tech from the list of tech you have
|
|
tech.tech[choose].remove();
|
|
tech.tech[choose].count = 0;
|
|
tech.tech[choose].isLost = true;
|
|
simulation.updateTechHUD();
|
|
m.fieldCDcycle = m.cycle + 30; //disable field so you can't pick up the ejected tech
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
},
|
|
pauseEjectTech(index) {
|
|
if ((tech.isPauseEjectTech || simulation.testing) && !simulation.isChoosing && !tech.tech[index].isNonRefundable) {
|
|
if (Math.random() < 0.2 || tech.tech[index].isFromAppliedScience || (tech.tech[index].bonusResearch !== undefined && tech.tech[index].bonusResearch > powerUps.research.count)) {
|
|
tech.removeTech(index)
|
|
// powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
|
|
} else {
|
|
powerUps.ejectTech(index)
|
|
}
|
|
document.getElementById(`${index}-pause-tech`).style.textDecoration = "line-through"
|
|
document.getElementById(`${index}-pause-tech`).style.animation = ""
|
|
document.getElementById(`${index}-pause-tech`).onclick = null
|
|
}
|
|
},
|
|
// removeRandomTech() {
|
|
// const have = [] //find which tech you have
|
|
// for (let i = 0; i < tech.tech.length; i++) {
|
|
// if (tech.tech[i].count > 0) have.push(i)
|
|
// }
|
|
// if (have.length) {
|
|
// const choose = have[Math.floor(Math.random() * have.length)]
|
|
// simulation.makeTextLog(`<span class='color-var'>tech</span>.removeTech("<span class='color-text'>${tech.tech[choose].name}</span>")`)
|
|
// const totalRemoved = tech.tech[choose].count
|
|
// tech.tech[choose].count = 0;
|
|
// tech.tech[choose].remove(); // remove a random tech form the list of tech you have
|
|
// tech.tech[choose].isLost = true
|
|
// simulation.updateTechHUD();
|
|
// return totalRemoved
|
|
// }
|
|
// return 0
|
|
// },
|
|
randomize(where) { //makes a random power up convert into a random different power up
|
|
//put 10 power ups close together
|
|
const len = Math.min(10, powerUp.length)
|
|
for (let i = 0; i < len; i++) { //collide the first 10 power ups
|
|
const unit = Vector.rotate({ x: 1, y: 0 }, 6.28 * Math.random())
|
|
Matter.Body.setPosition(powerUp[i], Vector.add(where, Vector.mult(unit, 20 + 25 * Math.random())));
|
|
Matter.Body.setVelocity(powerUp[i], Vector.mult(unit, 20));
|
|
}
|
|
|
|
//count big power ups and small power ups
|
|
let options = ["heal", "research", "ammo"]
|
|
if (m.coupling) options.push("coupling")
|
|
if (tech.isBoostPowerUps) options.push("boost")
|
|
let bigIndexes = []
|
|
let smallIndexes = []
|
|
for (let i = 0; i < powerUp.length; i++) {
|
|
if (powerUp[i].name === "tech" || powerUp[i].name === "gun" || powerUp[i].name === "field") {
|
|
bigIndexes.push(i)
|
|
} else {
|
|
smallIndexes.push(i)
|
|
}
|
|
}
|
|
if (bigIndexes.length > 0) {
|
|
// console.log("at least 1 big will always spilt")
|
|
const index = bigIndexes[Math.floor(Math.random() * bigIndexes.length)]
|
|
for (let i = 0; i < 3; i++) powerUps.directSpawn(where.x, where.y, options[Math.floor(Math.random() * options.length)], false)
|
|
|
|
Matter.Composite.remove(engine.world, powerUp[index]);
|
|
powerUp.splice(index, 1);
|
|
} else if (smallIndexes.length > 2 && Math.random() < 0.33) {
|
|
// console.log("no big, at least 3 small can combine")
|
|
for (let j = 0; j < 3; j++) {
|
|
for (let i = 0; i < powerUp.length; i++) {
|
|
if (powerUp[i].name === "heal" || powerUp[i].name === "research" || powerUp[i].name === "ammo" || powerUp[i].name === "coupling" || powerUp[i].name === "boost") {
|
|
Matter.Composite.remove(engine.world, powerUp[i]);
|
|
powerUp.splice(i, 1);
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
options = ["tech", "gun", "field"]
|
|
powerUps.directSpawn(where.x, where.y, options[Math.floor(Math.random() * options.length)], false)
|
|
} else if (smallIndexes.length > 0) {
|
|
// console.log("no big, at least 1 small will swap flavors")
|
|
const index = Math.floor(Math.random() * powerUp.length)
|
|
options = options.filter(e => e !== powerUp[index].name); //don't repeat the current power up type
|
|
powerUps.directSpawn(where.x, where.y, options[Math.floor(Math.random() * options.length)], false)
|
|
Matter.Composite.remove(engine.world, powerUp[index]);
|
|
powerUp.splice(index, 1);
|
|
}
|
|
},
|
|
directSpawn(x, y, target, moving = true, mode = null, size = powerUps[target].size(), isDuplicated = false) {
|
|
let index = powerUp.length;
|
|
let properties = {
|
|
density: 0.001,
|
|
frictionAir: 0.03,
|
|
restitution: 0.85,
|
|
collisionFilter: {
|
|
group: 0,
|
|
category: cat.powerUp,
|
|
mask: cat.map | cat.powerUp
|
|
},
|
|
color: powerUps[target].color,
|
|
effect: powerUps[target].effect,
|
|
name: powerUps[target].name,
|
|
size: size
|
|
}
|
|
let polygonSides
|
|
if (isDuplicated) {
|
|
polygonSides = tech.isPowerUpsVanish ? 3 : Math.floor(4 + 2 * Math.random())
|
|
properties.isDuplicated = true
|
|
} else {
|
|
properties.inertia = Infinity //prevents rotation for circles only
|
|
polygonSides = 0
|
|
}
|
|
powerUp[index] = Matter.Bodies.polygon(x, y, polygonSides, size, properties);
|
|
if (mode) powerUp[index].mode = mode
|
|
if (moving) Matter.Body.setVelocity(powerUp[index], { x: (Math.random() - 0.5) * 15, y: Math.random() * -9 - 3 });
|
|
Composite.add(engine.world, powerUp[index]);
|
|
},
|
|
spawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) {
|
|
if (
|
|
(!tech.isSuperDeterminism || (target !== 'research')) &&
|
|
!(tech.isEnergyNoAmmo && target === 'ammo')
|
|
) {
|
|
if (tech.isBoostReplaceAmmo && target === 'ammo') target = 'boost'
|
|
powerUps.directSpawn(x, y, target, moving, mode, size)
|
|
if (Math.random() < tech.duplicationChance()) {
|
|
powerUps.directSpawn(x, y, target, moving, mode, size, true)
|
|
powerUp[powerUp.length - 1].isDuplicated = true
|
|
// if (tech.isPowerUpsVanish) powerUp[powerUp.length - 1].endCycle = simulation.cycle + 300
|
|
}
|
|
}
|
|
},
|
|
}; |