no reaction

reactor
  you can skip the fight, by not pressing the button and exiting
  sprayBoss spray mode is now triggered by health loss, it fires a bit slower
  power ups now spawn high up, but some fall off the edges
  bonus Bosses can now spawn on reactor

bug fixes
This commit is contained in:
landgreen
2022-04-17 10:31:04 -07:00
parent 2dc633d2da
commit aad1706969
6 changed files with 68 additions and 128 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -35,7 +35,7 @@ const level = {
// tech.giveTech("extruder") // tech.giveTech("extruder")
// m.immuneCycle = Infinity //you can't take damage // m.immuneCycle = Infinity //you can't take damage
// level.difficultyIncrease(30) //30 is near max on hard //60 is near max on why // level.difficultyIncrease(1) //30 is near max on hard //60 is near max on why
// simulation.enableConstructMode() //used to build maps in testing mode // simulation.enableConstructMode() //used to build maps in testing mode
// level.reactor(); // level.reactor();
// level.testing(); //not in rotation, used for testing // level.testing(); //not in rotation, used for testing
@@ -2683,16 +2683,7 @@ const level = {
spawn.mapRect(-1525, -2825, 1250, 4925); spawn.mapRect(-1525, -2825, 1250, 4925);
spawn.mapRect(-400, -2025, 625, 925); spawn.mapRect(-400, -2025, 625, 925);
spawn.mapRect(-400, -750, 625, 1200); spawn.mapRect(-400, -750, 625, 1200);
// spawn.mapVertex(200, 0, "-200 0 -100 -100 100 -100 200 0");
// spawn.bodyRect(225, -100, 100, 100, 0.5);
// spawn.bodyRect(225, -200, 75, 100, 0.5);
spawn.bodyRect(250, -70, 100, 70, 1); spawn.bodyRect(250, -70, 100, 70, 1);
// spawn.bodyRect(-275, -850, 75, 100, 0.4);
// spawn.bodyRect(1525, -100, 100, 100, 0.3);
// spawn.bodyRect(2325, -50, 125, 50, 0.3);
// spawn.bodyRect(2375, -100, 50, 50, 0.3);
spawn.mapRect(-425, 0, 4200, 2100); spawn.mapRect(-425, 0, 4200, 2100);
spawn.mapRect(175, -1250, 50, 300); spawn.mapRect(175, -1250, 50, 300);
spawn.mapRect(-475, -2825, 4250, 1025); spawn.mapRect(-475, -2825, 4250, 1025);
@@ -2706,82 +2697,56 @@ const level = {
spawn.mapRect(2750, -2150, 1025, 1775); spawn.mapRect(2750, -2150, 1025, 1775);
spawn.mapRect(2750, -475, 50, 300); spawn.mapRect(2750, -475, 50, 300);
// spawn.bodyRect(1540, -1110, 300, 25, 0.9);
// spawn.randomSmallMob(1300, -70);
// spawn.randomMob(2650, -975, 0.8);
// const doorIn = level.door(187, -450, 25, 250, 2) //x, y, width, height, distance, speed = 1
// doorIn.isClosing = false
// level.custom = () => {
// level.exit.drawAndCheck();
// // if (mob.length > 0) {
// // doorIn.isClosing = true
// // } else {
// // doorIn.isClosing = false
// // }
// doorIn.isClosing = !(mob.length > 0)
// doorIn.openClose();
const doorIn = level.door(187, -950, 25, 200, 190, 2) //x, y, width, height, distance, speed = 1 const doorIn = level.door(187, -950, 25, 200, 190, 2) //x, y, width, height, distance, speed = 1
const doorOut = level.door(2762, -175, 25, 200, 190, 2) //x, y, width, height, distance, speed = 1 const doorOut = level.door(2762, -175, 25, 200, 190, 2) //x, y, width, height, distance, speed = 1
doorOut.isClosing = true // doorOut.isClosing = true
let isDoorsLocked = false let isDoorsLocked = false
let isFightOver = false let isFightOver = false
let isSpawnedBoss = false let isSpawnedBoss = false
level.custom = () => { level.custom = () => {
// player.force.y -= player.mass * simulation.g * 0.4; //float player
if (isDoorsLocked) { if (isDoorsLocked) {
// if (mob.length > 0) {
// doorIn.isClosing = true
// doorOut.isClosing = true
// } else if (!isFightOver) {
// isFightOver = true
// doorIn.isClosing = false
// doorOut.isClosing = false
// powerUps.spawnBossPowerUp(2900, -200)
// }
if (player.position.x < 0) { //if player gets trapped inside starting room open up again if (player.position.x < 0) { //if player gets trapped inside starting room open up again
isDoorsLocked = false isDoorsLocked = false
doorIn.isClosing = false doorIn.isClosing = false
} }
} else if (player.position.x > 225) {
isDoorsLocked = true
doorIn.isClosing = true
doorOut.isClosing = true
} }
// else if (!isFightOver && player.position.x > 225) {
// isDoorsLocked = true
// doorIn.isClosing = true
// doorOut.isClosing = true
// }
doorIn.openClose(); doorIn.openClose();
doorOut.openClose(); doorOut.openClose();
ctx.fillStyle = "#d5ebef" ctx.fillStyle = "#d5ebef"
ctx.fillRect(2750, -375, 550, 375) ctx.fillRect(2750, -375, 550, 375)
level.enter.draw(); level.enter.draw();
level.exit.drawAndCheck(); level.exit.drawAndCheck();
button.draw(); button.draw();
if (button.isUp) { if (button.isUp) {
button.query(); button.query();
} else if (!isSpawnedBoss) { } else if (!isSpawnedBoss) {
for (let i = 0; i < 4; ++i) {
setTimeout(() => { powerUps.spawn(300 + 800 * Math.random(), -1700, "ammo") }, 10000 * Math.random());
}
for (let i = 0; i < 3; ++i) {
setTimeout(() => { powerUps.spawn(1800 + 800 * Math.random(), -1700, "ammo") }, 10000 * Math.random());
}
powerUps.spawn(300 + 800 * Math.random(), -1700, "heal");
powerUps.spawn(1800 + 800 * Math.random(), -1700, "heal");
isSpawnedBoss = true isSpawnedBoss = true
isDoorsLocked = true
doorIn.isClosing = true
doorOut.isClosing = true
for (let i = 0; i < 9; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "ammo")
for (let i = 0; i < 3; ++i) powerUps.spawn(1200 + 550 * Math.random(), -1700, "heal");
const scale = Math.pow(simulation.difficulty, 0.73) //hard around 30, why around 54 const scale = Math.pow(simulation.difficulty, 0.73) //hard around 30, why around 54
if (Math.random() < 0.3) { if (Math.random() < 0.07 && simulation.difficulty > 22) {
for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
} else if (Math.random() < 0.45) {
for (let i = 0, len = scale * 0.17; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
} else if (Math.random() < 0.9) {
for (let i = 0, len = scale * 0.23; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
} else {
for (let i = 0, len = scale * 0.1 / 3; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); for (let i = 0, len = scale * 0.1 / 3; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false);
for (let i = 0, len = scale * 0.17 / 3; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) for (let i = 0, len = scale * 0.17 / 3; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false)
for (let i = 0, len = scale * 0.23 / 3; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); for (let i = 0, len = scale * 0.23 / 3; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false);
} else {
if (Math.random() < 0.33) {
for (let i = 0, len = scale * 0.1; i < len; ++i) spawn.bounceBoss(1487 + 200 * i, -1525, 80, false); //spawn 1-2 at difficulty 15
} else if (Math.random() < 0.5) {
for (let i = 0, len = scale * 0.17; i < len; ++i) spawn.sprayBoss(1487 + 200 * i, -1525, 30, false) //spawn 2-3 at difficulty 15
} else {
for (let i = 0, len = scale * 0.23; i < len; ++i) spawn.mineBoss(1487 + 200 * i, -1525, 50, false); //spawn 3-4 at difficulty 15
} }
}
spawn.secondaryBossChance(2200, -800)
} else if (!isFightOver && !(simulation.cycle % 120)) { //once a second look for any bosses } else if (!isFightOver && !(simulation.cycle % 120)) { //once a second look for any bosses
let isFoundBoss = false let isFoundBoss = false
for (let i = 0; i < mob.length; i++) { for (let i = 0; i < mob.length; i++) {

View File

@@ -1046,7 +1046,7 @@ const powerUps = {
}, },
pauseEjectTech(index) { pauseEjectTech(index) {
if (tech.isPauseEjectTech || simulation.testing) { if (tech.isPauseEjectTech || simulation.testing) {
if (Math.random() < 0.1 || tech.tech[index].isFromAppliedScience) { if (Math.random() < 0.1 || tech.tech[index].isFromAppliedScience || (tech.tech[index].bonusResearch !== undefined && tech.tech[index].bonusResearch > powerUps.research.count)) {
tech.removeTech(index) tech.removeTech(index)
powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false); powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
} else { } else {

View File

@@ -3532,25 +3532,33 @@ const spawn = {
let me = mob[mob.length - 1]; let me = mob[mob.length - 1];
me.isBoss = true; me.isBoss = true;
me.inertia = Infinity; //no rotation me.inertia = Infinity; //no rotation
// me.accelMag = 0.00008 + 0.00007 * simulation.accelScale; me.burstFireFreq = 18 + Math.floor(14 * simulation.CDScale)
me.burstFireFreq = 18 + Math.floor(18 * simulation.CDScale) me.burstTotalPhases = 3 + Math.floor(2 / simulation.CDScale)
me.burstTotalPhases = 4 + Math.floor(2 / simulation.CDScale)
me.noFireTotalCycles = 360
me.frictionStatic = 0; me.frictionStatic = 0;
me.friction = 0; me.friction = 0;
me.frictionAir = 0; me.frictionAir = 0;
me.restitution = 1 me.restitution = 1
spawn.spawnOrbitals(me, radius + 50 + 200 * Math.random(), 1) spawn.spawnOrbitals(me, radius + 50 + 150 * Math.random(), 1)
Matter.Body.setDensity(me, 0.0022 + 0.0002 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger Matter.Body.setDensity(me, 0.0022 + 0.0001 * Math.sqrt(simulation.difficulty)); //extra dense //normal is 0.001 //makes effective life much larger
me.damageReduction = 0.09 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1) me.damageReduction = 0.09 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1)
me.startingDamageReduction = me.damageReduction me.startingDamageReduction = me.damageReduction
me.isInvulnerable = false me.isInvulnerable = false
me.nextHealthThreshold = 0.75
me.onDeath = function() { me.onDeath = function() {
if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y) if (isSpawnBossPowerUp) powerUps.spawnBossPowerUp(this.position.x, this.position.y)
}; };
me.onDamage = function() {}; me.onDamage = function() {
if (this.health < this.nextHealthThreshold) {
this.health = this.nextHealthThreshold - 0.01
this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
this.phaseCycle = -2
this.do = this.burstFire
this.frictionAir = 1
this.isInvulnerable = true
this.damageReduction = 0
}
};
//draw radial lines from verticies showing future bullet paths? //draw radial lines from verticies showing future bullet paths?
me.radialLines = function() { me.radialLines = function() {
@@ -3559,7 +3567,6 @@ const spawn = {
ctx.moveTo(this.vertices[i].x, this.vertices[i].y) ctx.moveTo(this.vertices[i].x, this.vertices[i].y)
const unit = Vector.add(Vector.mult(Vector.normalise(Vector.sub(this.vertices[i], this.position)), 1000), this.vertices[i]) const unit = Vector.add(Vector.mult(Vector.normalise(Vector.sub(this.vertices[i], this.position)), 1000), this.vertices[i])
ctx.lineTo(unit.x, unit.y) ctx.lineTo(unit.x, unit.y)
// console.log(unit, this.vertices, this.position)
} }
ctx.lineWidth = 10 ctx.lineWidth = 10
ctx.strokeStyle = "rgb(200,0,200,0.03)" ctx.strokeStyle = "rgb(200,0,200,0.03)"
@@ -3568,8 +3575,6 @@ const spawn = {
me.phaseCycle = 0 me.phaseCycle = 0
me.normalDoStuff = function() { me.normalDoStuff = function() {
// this.seePlayerByHistory();
// this.attraction();
this.checkStatus(); this.checkStatus();
me.seePlayer.recall = 1 me.seePlayer.recall = 1
//maintain speed //faster in the vertical to help avoid repeating patterns //maintain speed //faster in the vertical to help avoid repeating patterns
@@ -3580,18 +3585,6 @@ const spawn = {
if (Math.abs(this.velocity.x) < 10) Matter.Body.setVelocity(this, { x: this.velocity.x * 1.07, y: this.velocity.y }); if (Math.abs(this.velocity.x) < 10) Matter.Body.setVelocity(this, { x: this.velocity.x * 1.07, y: this.velocity.y });
} }
} }
me.noFire = function() {
this.normalDoStuff();
this.phaseCycle++
if (this.phaseCycle > this.noFireTotalCycles) { //start burst fire mode
this.phaseCycle = -2
this.do = this.burstFire
this.frictionAir = 1
this.isInvulnerable = true
this.damageReduction = 0
// if (!this.isShielded) spawn.shield(this, this.position.x, this.position.y, 1);
}
};
me.burstFire = function() { me.burstFire = function() {
this.normalDoStuff(); this.normalDoStuff();
this.radialLines() this.radialLines()
@@ -3608,8 +3601,8 @@ const spawn = {
if (!(simulation.cycle % this.burstFireFreq)) { if (!(simulation.cycle % this.burstFireFreq)) {
this.phaseCycle++ this.phaseCycle++
if (this.phaseCycle > this.burstTotalPhases) { //start spiral fire mode if (this.phaseCycle > this.burstTotalPhases) { //start spiral fire mode
this.phaseCycle = -7 // this.phaseCycle = -7
this.do = this.noFire this.do = this.normalDoStuff
this.frictionAir = 0; this.frictionAir = 0;
this.isInvulnerable = false this.isInvulnerable = false
this.damageReduction = this.startingDamageReduction this.damageReduction = this.startingDamageReduction
@@ -3633,7 +3626,7 @@ const spawn = {
} }
} }
}; };
me.do = me.noFire me.do = me.normalDoStuff
Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }); Matter.Body.setVelocity(me, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) });
}, },
mineBoss(x, y, radius = 120, isSpawnBossPowerUp = true) { mineBoss(x, y, radius = 120, isSpawnBossPowerUp = true) {

View File

@@ -442,6 +442,8 @@ const tech = {
count: 0, count: 0,
frequency: 1, frequency: 1,
frequencyDefault: 1, frequencyDefault: 1,
isNonRefundable: true,
isBadRandomOption: true,
allowed() { allowed() {
return b.inventory.length < b.guns.length - 5 //(tech.isDamageForGuns || tech.isFireRateForGuns) && return b.inventory.length < b.guns.length - 5 //(tech.isDamageForGuns || tech.isFireRateForGuns) &&
}, },
@@ -451,12 +453,12 @@ const tech = {
for (let i = 0; i < 8; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun"); for (let i = 0; i < 8; i++) powerUps.spawn(m.pos.x + 10 * Math.random(), m.pos.y + 10 * Math.random(), "gun");
}, },
remove() { remove() {
if (tech.isGunCycle) { // if (tech.isGunCycle) {
for (let i = 0; i < 8; i++) { // for (let i = 0; i < 8; i++) {
if (b.inventory.length) b.removeGun(b.guns[b.inventory[b.inventory.length - 1]].name) //remove your last gun // if (b.inventory.length) b.removeGun(b.guns[b.inventory[b.inventory.length - 1]].name) //remove your last gun
} // }
tech.isGunCycle = false; // tech.isGunCycle = false;
} // }
} }
}, },
{ {
@@ -2857,7 +2859,7 @@ const tech = {
{ {
name: "Ψ(t) collapse", name: "Ψ(t) collapse",
link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Wave_function_collapse' class="link">Ψ(t) collapse</a>`, link: `<a target="_blank" href='https://en.wikipedia.org/wiki/Wave_function_collapse' class="link">Ψ(t) collapse</a>`,
description: `enter an <strong class='alt'>alternate reality</strong> after you <strong class='color-r'>research</strong><br>spawn ${powerUps.orb.research(21)}`, description: `enter an <strong class='alt'>alternate reality</strong> after you <strong class='color-r'>research</strong><br>spawn ${powerUps.orb.research(14)}`,
maxCount: 1, maxCount: 1,
count: 0, count: 0,
frequency: 1, frequency: 1,
@@ -2866,12 +2868,14 @@ const tech = {
return !tech.isSwitchReality && !tech.isCollisionRealitySwitch && !tech.isJunkResearch return !tech.isSwitchReality && !tech.isCollisionRealitySwitch && !tech.isJunkResearch
}, },
requires: "not many-worlds, non-unitary, pseudoscience", requires: "not many-worlds, non-unitary, pseudoscience",
bonusResearch: 14,
effect() { effect() {
tech.isResearchReality = true; tech.isResearchReality = true;
for (let i = 0; i < 16; i++) powerUps.spawn(m.pos.x + Math.random() * 60, m.pos.y + Math.random() * 60, "research", false); for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + Math.random() * 60, m.pos.y + Math.random() * 60, "research", false);
}, },
remove() { remove() {
tech.isResearchReality = false; tech.isResearchReality = false;
if (this.count > 0) powerUps.research.changeRerolls(-this.bonusResearch)
} }
}, },
{ {
@@ -2885,9 +2889,10 @@ const tech = {
return !tech.isSuperDeterminism return !tech.isSuperDeterminism
}, },
requires: "not superdeterminism", requires: "not superdeterminism",
bonusResearch: 9,
effect() { effect() {
tech.isBanish = true tech.isBanish = true
for (let i = 0; i < 9; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false); for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
}, },
remove() { remove() {
if (tech.isBanish) { if (tech.isBanish) {
@@ -2896,8 +2901,9 @@ const tech = {
for (let i = 0; i < tech.tech.length; i++) { for (let i = 0; i < tech.tech.length; i++) {
if (tech.tech[i].isBanished) tech.tech[i].isBanished = false if (tech.tech[i].isBanished) tech.tech[i].isBanished = false
} }
// powerUps.research.changeRerolls(-10) powerUps.research.changeRerolls(-this.bonusResearch)
} }
tech.isBanish = false
} }
}, },
{ {
@@ -3028,12 +3034,9 @@ const tech = {
requires: "not determinism", requires: "not determinism",
effect: () => { effect: () => {
tech.isExtraGunField = true; tech.isExtraGunField = true;
// 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);
}, },
remove() { remove() {
tech.isExtraGunField = false; tech.isExtraGunField = false;
// if (this.count > 0) powerUps.research.changeRerolls(-2)
} }
}, },
{ {
@@ -3135,14 +3138,15 @@ const tech = {
return true return true
}, },
requires: "", requires: "",
bonusResearch: 6,
effect() { effect() {
tech.isPauseSwitchField = true; tech.isPauseSwitchField = true;
for (let i = 0; i < 6; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false); for (let i = 0; i < this.bonusResearch; i++) powerUps.spawn(m.pos.x + 40 * (Math.random() - 0.5), m.pos.y + 40 * (Math.random() - 0.5), "research", false);
}, },
remove() { remove() {
if (tech.isPauseSwitchField) { if (tech.isPauseSwitchField) {
tech.isPauseSwitchField = false; tech.isPauseSwitchField = false;
powerUps.research.changeRerolls(-6) powerUps.research.changeRerolls(-this.bonusResearch)
} }
} }
}, },
@@ -3587,7 +3591,7 @@ const tech = {
requires: "NOT EXPERIMENT MODE, some duplication, not super determinism", requires: "NOT EXPERIMENT MODE, some duplication, not super determinism",
effect: () => { effect: () => {
powerUps.research.changeRerolls(-2) powerUps.research.changeRerolls(-2)
simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-r'>research</span> <span class='color-symbol'>-=</span> 2<br>${powerUps.research.count}`) simulation.makeTextLog(`<span class='color-var'>m</span>.<span class='color-r'>research</span> <span class='color-symbol'>-=</span> 2`)
powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); powerUps.directSpawn(m.pos.x, m.pos.y, "tech");
if (Math.random() < tech.duplicationChance() * 2) powerUps.directSpawn(m.pos.x + 10, m.pos.y + 5, "tech"); if (Math.random() < tech.duplicationChance() * 2) powerUps.directSpawn(m.pos.x + 10, m.pos.y + 5, "tech");
}, },

View File

@@ -1,34 +1,12 @@
******************************************************** NEXT PATCH ************************************************** ******************************************************** NEXT PATCH **************************************************
automonous navigation -> path integration
sends spores and worms and drones to the next level with you
MIRV gives 10->12% smaller radius and damage
laser tech slow light has 33% less spacing
tech exciton gives 70%->88% damage
discrete optimization: 40%->35% damage and fire delay
degenerate matter 60->66% harm reduction while field is active
virtual particles 15% duplication is now allowed for time dilation
railgun no longer uses extra ammo when firing multiple bullets with smelting
smelting now costs more ammo with railgun
plasma torch, ball, extruder all use 33% less energy, do 15% more damage
bremsstrahlung does 15% more damage
standing wave field gives 50 energy
it's cooldown for blocking shields in now 0.5->0.33 s
reactor reactor
fight now starts when you press a button, so you can prep you can skip the fight, by not pressing the button and exiting
spawns more ammo 4->7, heals 0->2 sprayBoss spray mode is now triggered by health loss, it fires a bit slower
will no longer show up on levels 2,3,4 power ups now spawn high up, but some fall off the edges
fewer bosses spawn at high difficulty levels bonus Bosses can now spawn on reactor
has a small chance to spawn all 3 boss types
sprayBoss is 25% slower, but it goes immune while spraying instead of shielding
community maps have a short message onload giving credit to the author bug fixes
new level element balance - it's basically spinners and rotors combined
I'm replacing all rotors to fix potential BUGS
sewers, house, perplex, vats
requirement text bug fixes
******************************************************** TODO ******************************************************** ******************************************************** TODO ********************************************************