diff --git a/.DS_Store b/.DS_Store index ccd53dc..b6a3ab9 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/img/1s half-life.webp b/img/1s half-life.webp new file mode 100644 index 0000000..e6e3919 Binary files /dev/null and b/img/1s half-life.webp differ diff --git a/img/1st ionization energy.webp b/img/1st ionization energy.webp new file mode 100644 index 0000000..95e17b1 Binary files /dev/null and b/img/1st ionization energy.webp differ diff --git a/img/6s half-life.webp b/img/6s half-life.webp new file mode 100644 index 0000000..5ecd2c3 Binary files /dev/null and b/img/6s half-life.webp differ diff --git a/img/Bayesian statistics.webp b/img/Bayesian statistics.webp new file mode 100644 index 0000000..8dd3651 Binary files /dev/null and b/img/Bayesian statistics.webp differ diff --git a/img/Bessemer process.webp b/img/Bessemer process.webp new file mode 100644 index 0000000..bca9b04 Binary files /dev/null and b/img/Bessemer process.webp differ diff --git a/img/Bitter electromagnet.webp b/img/Bitter electromagnet.webp new file mode 100644 index 0000000..9d325d3 Binary files /dev/null and b/img/Bitter electromagnet.webp differ diff --git a/img/Born rule.webp b/img/Born rule.webp new file mode 100644 index 0000000..dac853b Binary files /dev/null and b/img/Born rule.webp differ diff --git a/img/CPT symmetry.webp b/img/CPT symmetry.webp new file mode 100644 index 0000000..b0f2623 Binary files /dev/null and b/img/CPT symmetry.webp differ diff --git a/img/Gibbs free energy.webp b/img/Gibbs free energy.webp new file mode 100644 index 0000000..321c317 Binary files /dev/null and b/img/Gibbs free energy.webp differ diff --git a/img/Higgs mechanism.webp b/img/Higgs mechanism.webp new file mode 100644 index 0000000..9edf37b Binary files /dev/null and b/img/Higgs mechanism.webp differ diff --git a/img/Hilbert space.webp b/img/Hilbert space.webp new file mode 100644 index 0000000..676ec7a Binary files /dev/null and b/img/Hilbert space.webp differ diff --git a/img/Hilbert spaces.webp b/img/Hilbert spaces.webp new file mode 100644 index 0000000..4a99cf6 Binary files /dev/null and b/img/Hilbert spaces.webp differ diff --git a/img/ICBM.webp b/img/ICBM.webp new file mode 100644 index 0000000..ac2f753 Binary files /dev/null and b/img/ICBM.webp differ diff --git a/img/K-selection.webp b/img/K-selection.webp new file mode 100644 index 0000000..79250f3 Binary files /dev/null and b/img/K-selection.webp differ diff --git a/img/Lorentz transformation.webp b/img/Lorentz transformation.webp new file mode 100644 index 0000000..c7c52e8 Binary files /dev/null and b/img/Lorentz transformation.webp differ diff --git a/img/MACHO.webp b/img/MACHO.webp new file mode 100644 index 0000000..8570ee0 Binary files /dev/null and b/img/MACHO.webp differ diff --git a/img/MIRV.webp b/img/MIRV.webp new file mode 100644 index 0000000..32db296 Binary files /dev/null and b/img/MIRV.webp differ diff --git a/img/Maxwells demon.webp b/img/Maxwells demon.webp new file mode 100644 index 0000000..9152cad Binary files /dev/null and b/img/Maxwells demon.webp differ diff --git a/img/Meissner effect.webp b/img/Meissner effect.webp new file mode 100644 index 0000000..329bc13 Binary files /dev/null and b/img/Meissner effect.webp differ diff --git a/img/Monte Carlo method.webp b/img/Monte Carlo method.webp new file mode 100644 index 0000000..017fb09 Binary files /dev/null and b/img/Monte Carlo method.webp differ diff --git a/img/NAND gate.webp b/img/NAND gate.webp new file mode 100644 index 0000000..0525c8b Binary files /dev/null and b/img/NAND gate.webp differ diff --git a/img/NOR gate.webp b/img/NOR gate.webp new file mode 100644 index 0000000..bd71ef3 Binary files /dev/null and b/img/NOR gate.webp differ diff --git a/img/Newtons 1st law.webp b/img/Newtons 1st law.webp new file mode 100644 index 0000000..28dc360 Binary files /dev/null and b/img/Newtons 1st law.webp differ diff --git a/img/Newtons 2nd law.webp b/img/Newtons 2nd law.webp new file mode 100644 index 0000000..478236d Binary files /dev/null and b/img/Newtons 2nd law.webp differ diff --git a/img/Newtons 3rd law.webp b/img/Newtons 3rd law.webp new file mode 100644 index 0000000..1634991 Binary files /dev/null and b/img/Newtons 3rd law.webp differ diff --git a/img/Noether violation.webp b/img/Noether violation.webp new file mode 100644 index 0000000..884d5d2 Binary files /dev/null and b/img/Noether violation.webp differ diff --git a/img/Occams razor.webp b/img/Occams razor.webp new file mode 100644 index 0000000..cf6a4d3 Binary files /dev/null and b/img/Occams razor.webp differ diff --git a/img/Pauli exclusion.webp b/img/Pauli exclusion.webp new file mode 100644 index 0000000..589abb5 Binary files /dev/null and b/img/Pauli exclusion.webp differ diff --git a/img/UHMWPE.webp b/img/UHMWPE.webp new file mode 100644 index 0000000..b893961 Binary files /dev/null and b/img/UHMWPE.webp differ diff --git a/img/WIMPs.webp b/img/WIMPs.webp new file mode 100644 index 0000000..66ba2fb Binary files /dev/null and b/img/WIMPs.webp differ diff --git a/img/Zenos paradox.webp b/img/Zenos paradox.webp new file mode 100644 index 0000000..c328496 Binary files /dev/null and b/img/Zenos paradox.webp differ diff --git a/img/abiogenesis.webp b/img/abiogenesis.webp new file mode 100644 index 0000000..1e36cbf Binary files /dev/null and b/img/abiogenesis.webp differ diff --git a/img/ablative drones.webp b/img/ablative drones.webp new file mode 100644 index 0000000..78f4c4a Binary files /dev/null and b/img/ablative drones.webp differ diff --git a/img/acetone peroxide.webp b/img/acetone peroxide.webp new file mode 100644 index 0000000..8889d4b Binary files /dev/null and b/img/acetone peroxide.webp differ diff --git a/img/active cooling.webp b/img/active cooling.webp new file mode 100644 index 0000000..0c05fbe Binary files /dev/null and b/img/active cooling.webp differ diff --git a/img/ad hoc.webp b/img/ad hoc.webp new file mode 100644 index 0000000..44a62e3 Binary files /dev/null and b/img/ad hoc.webp differ diff --git a/img/adiabatic healing.webp b/img/adiabatic healing.webp new file mode 100644 index 0000000..0e25359 Binary files /dev/null and b/img/adiabatic healing.webp differ diff --git a/img/aerogel.webp b/img/aerogel.webp new file mode 100644 index 0000000..a3b9e83 Binary files /dev/null and b/img/aerogel.webp differ diff --git a/img/affine connection.webp b/img/affine connection.webp new file mode 100644 index 0000000..fb05fd0 Binary files /dev/null and b/img/affine connection.webp differ diff --git a/img/alternator.webp b/img/alternator.webp new file mode 100644 index 0000000..ef2098d Binary files /dev/null and b/img/alternator.webp differ diff --git a/img/ammonium nitrate.webp b/img/ammonium nitrate.webp new file mode 100644 index 0000000..e2fe4e0 Binary files /dev/null and b/img/ammonium nitrate.webp differ diff --git a/img/amplitude.webp b/img/amplitude.webp new file mode 100644 index 0000000..6e4e39b Binary files /dev/null and b/img/amplitude.webp differ diff --git a/img/annihilation.webp b/img/annihilation.webp new file mode 100644 index 0000000..4a37c35 Binary files /dev/null and b/img/annihilation.webp differ diff --git a/img/ansatz.webp b/img/ansatz.webp new file mode 100644 index 0000000..3b9a4d7 Binary files /dev/null and b/img/ansatz.webp differ diff --git a/img/anthropic principle.webp b/img/anthropic principle.webp new file mode 100644 index 0000000..28035f9 Binary files /dev/null and b/img/anthropic principle.webp differ diff --git a/img/anti-shear topology.webp b/img/anti-shear topology.webp new file mode 100644 index 0000000..61dcda6 Binary files /dev/null and b/img/anti-shear topology.webp differ diff --git a/img/anticorrelation.webp b/img/anticorrelation.webp new file mode 100644 index 0000000..2d6a05e Binary files /dev/null and b/img/anticorrelation.webp differ diff --git a/img/antiscience.webp b/img/antiscience.webp new file mode 100644 index 0000000..057e650 Binary files /dev/null and b/img/antiscience.webp differ diff --git a/img/apomixis.webp b/img/apomixis.webp new file mode 100644 index 0000000..1aa7128 Binary files /dev/null and b/img/apomixis.webp differ diff --git a/img/applied science.webp b/img/applied science.webp new file mode 100644 index 0000000..aecde79 Binary files /dev/null and b/img/applied science.webp differ diff --git a/img/arsenal.webp b/img/arsenal.webp new file mode 100644 index 0000000..3a22e85 Binary files /dev/null and b/img/arsenal.webp differ diff --git a/img/autocannon.webp b/img/autocannon.webp new file mode 100644 index 0000000..c8823d1 Binary files /dev/null and b/img/autocannon.webp differ diff --git a/img/axial flux motor.webp b/img/axial flux motor.webp new file mode 100644 index 0000000..7065251 Binary files /dev/null and b/img/axial flux motor.webp differ diff --git a/img/axion.webp b/img/axion.webp new file mode 100644 index 0000000..3e79c12 Binary files /dev/null and b/img/axion.webp differ diff --git a/img/band gap.webp b/img/band gap.webp new file mode 100644 index 0000000..0427cd4 Binary files /dev/null and b/img/band gap.webp differ diff --git a/img/beta radiation.webp b/img/beta radiation.webp new file mode 100644 index 0000000..24970c6 Binary files /dev/null and b/img/beta radiation.webp differ diff --git a/img/booby trap.webp b/img/booby trap.webp new file mode 100644 index 0000000..f06502f Binary files /dev/null and b/img/booby trap.webp differ diff --git a/img/boom-bot upgrade.webp b/img/boom-bot upgrade.webp new file mode 100644 index 0000000..127b91d Binary files /dev/null and b/img/boom-bot upgrade.webp differ diff --git a/img/boom-bot.webp b/img/boom-bot.webp new file mode 100644 index 0000000..76ee2fd Binary files /dev/null and b/img/boom-bot.webp differ diff --git a/img/boson composite.webp b/img/boson composite.webp new file mode 100644 index 0000000..3f0daa9 Binary files /dev/null and b/img/boson composite.webp differ diff --git a/img/bot fabrication.webp b/img/bot fabrication.webp new file mode 100644 index 0000000..8e4efae Binary files /dev/null and b/img/bot fabrication.webp differ diff --git a/img/bot manufacturing.webp b/img/bot manufacturing.webp new file mode 100644 index 0000000..930875f Binary files /dev/null and b/img/bot manufacturing.webp differ diff --git a/img/bot prototypes.webp b/img/bot prototypes.webp new file mode 100644 index 0000000..431a668 Binary files /dev/null and b/img/bot prototypes.webp differ diff --git a/img/bound state.webp b/img/bound state.webp new file mode 100644 index 0000000..f134f44 Binary files /dev/null and b/img/bound state.webp differ diff --git a/img/brainstorming.webp b/img/brainstorming.webp new file mode 100644 index 0000000..d7d327f Binary files /dev/null and b/img/brainstorming.webp differ diff --git a/img/bremsstrahlung.webp b/img/bremsstrahlung.webp new file mode 100644 index 0000000..d7fe0fc Binary files /dev/null and b/img/bremsstrahlung.webp differ diff --git a/img/brushless motor.webp b/img/brushless motor.webp new file mode 100644 index 0000000..c3b7648 Binary files /dev/null and b/img/brushless motor.webp differ diff --git a/img/bubble fusion.webp b/img/bubble fusion.webp new file mode 100644 index 0000000..c45a179 Binary files /dev/null and b/img/bubble fusion.webp differ diff --git a/img/buckling.webp b/img/buckling.webp new file mode 100644 index 0000000..17f10fe Binary files /dev/null and b/img/buckling.webp differ diff --git a/img/bulk modulus.webp b/img/bulk modulus.webp new file mode 100644 index 0000000..736fe5b Binary files /dev/null and b/img/bulk modulus.webp differ diff --git a/img/cache.webp b/img/cache.webp new file mode 100644 index 0000000..d0dcbdc Binary files /dev/null and b/img/cache.webp differ diff --git a/img/capacitor bank.webp b/img/capacitor bank.webp new file mode 100644 index 0000000..2f631d6 Binary files /dev/null and b/img/capacitor bank.webp differ diff --git a/img/catabolism.webp b/img/catabolism.webp new file mode 100644 index 0000000..3fbfea3 Binary files /dev/null and b/img/catabolism.webp differ diff --git a/img/causality bombs.webp b/img/causality bombs.webp new file mode 100644 index 0000000..2b78996 Binary files /dev/null and b/img/causality bombs.webp differ diff --git a/img/causality bots.webp b/img/causality bots.webp new file mode 100644 index 0000000..26c9b03 Binary files /dev/null and b/img/causality bots.webp differ diff --git a/img/ceramics.webp b/img/ceramics.webp new file mode 100644 index 0000000..6cdd6e6 Binary files /dev/null and b/img/ceramics.webp differ diff --git a/img/chain reaction.webp b/img/chain reaction.webp new file mode 100644 index 0000000..3ab476f Binary files /dev/null and b/img/chain reaction.webp differ diff --git a/img/charmed baryons.webp b/img/charmed baryons.webp new file mode 100644 index 0000000..79b6d26 Binary files /dev/null and b/img/charmed baryons.webp differ diff --git a/img/cherenkov radiation.webp b/img/cherenkov radiation.webp new file mode 100644 index 0000000..23c6296 Binary files /dev/null and b/img/cherenkov radiation.webp differ diff --git a/img/clock gating.webp b/img/clock gating.webp new file mode 100644 index 0000000..03bdc91 Binary files /dev/null and b/img/clock gating.webp differ diff --git a/img/colony.webp b/img/colony.webp new file mode 100644 index 0000000..5a6cfee Binary files /dev/null and b/img/colony.webp differ diff --git a/img/combinatorial optimization.webp b/img/combinatorial optimization.webp new file mode 100644 index 0000000..532c597 Binary files /dev/null and b/img/combinatorial optimization.webp differ diff --git a/img/commodities exchange.webp b/img/commodities exchange.webp new file mode 100644 index 0000000..edad9af Binary files /dev/null and b/img/commodities exchange.webp differ diff --git a/img/compound lens.webp b/img/compound lens.webp new file mode 100644 index 0000000..1357aef Binary files /dev/null and b/img/compound lens.webp differ diff --git a/img/corona discharge.webp b/img/corona discharge.webp new file mode 100644 index 0000000..196505b Binary files /dev/null and b/img/corona discharge.webp differ diff --git a/img/correlated damage.webp b/img/correlated damage.webp new file mode 100644 index 0000000..cd93b2c Binary files /dev/null and b/img/correlated damage.webp differ diff --git a/img/cosmic string.webp b/img/cosmic string.webp new file mode 100644 index 0000000..51338eb Binary files /dev/null and b/img/cosmic string.webp differ diff --git a/img/cross-disciplinary.webp b/img/cross-disciplinary.webp new file mode 100644 index 0000000..31c94f4 Binary files /dev/null and b/img/cross-disciplinary.webp differ diff --git a/img/cruise missile.webp b/img/cruise missile.webp new file mode 100644 index 0000000..d1e9e44 Binary files /dev/null and b/img/cruise missile.webp differ diff --git a/img/cryodesiccation.webp b/img/cryodesiccation.webp new file mode 100644 index 0000000..f36e272 Binary files /dev/null and b/img/cryodesiccation.webp differ diff --git a/img/crystallizer.webp b/img/crystallizer.webp new file mode 100644 index 0000000..8539db9 Binary files /dev/null and b/img/crystallizer.webp differ diff --git a/img/dark patterns.webp b/img/dark patterns.webp new file mode 100644 index 0000000..f147c9e Binary files /dev/null and b/img/dark patterns.webp differ diff --git a/img/dazzler.webp b/img/dazzler.webp new file mode 100644 index 0000000..7ae326c Binary files /dev/null and b/img/dazzler.webp differ diff --git a/img/dead reckoning.webp b/img/dead reckoning.webp new file mode 100644 index 0000000..aca40a0 Binary files /dev/null and b/img/dead reckoning.webp differ diff --git a/img/decoherence.webp b/img/decoherence.webp new file mode 100644 index 0000000..82b4650 Binary files /dev/null and b/img/decoherence.webp differ diff --git a/img/decorrelation.webp b/img/decorrelation.webp new file mode 100644 index 0000000..8abd942 Binary files /dev/null and b/img/decorrelation.webp differ diff --git a/img/decoupling.webp b/img/decoupling.webp new file mode 100644 index 0000000..6776cc3 Binary files /dev/null and b/img/decoupling.webp differ diff --git a/img/degenerate matter.webp b/img/degenerate matter.webp new file mode 100644 index 0000000..de58216 Binary files /dev/null and b/img/degenerate matter.webp differ diff --git a/img/delivery drone.webp b/img/delivery drone.webp new file mode 100644 index 0000000..91c7477 Binary files /dev/null and b/img/delivery drone.webp differ diff --git a/img/desublimated ammunition.webp b/img/desublimated ammunition.webp new file mode 100644 index 0000000..fab54cf Binary files /dev/null and b/img/desublimated ammunition.webp differ diff --git a/img/determinism.webp b/img/determinism.webp new file mode 100644 index 0000000..02b07fb Binary files /dev/null and b/img/determinism.webp differ diff --git a/img/diffraction grating.webp b/img/diffraction grating.webp new file mode 100644 index 0000000..53fed27 Binary files /dev/null and b/img/diffraction grating.webp differ diff --git a/img/diffuse beam.webp b/img/diffuse beam.webp new file mode 100644 index 0000000..5402793 Binary files /dev/null and b/img/diffuse beam.webp differ diff --git a/img/drone repair.webp b/img/drone repair.webp new file mode 100644 index 0000000..bc4ee46 Binary files /dev/null and b/img/drone repair.webp differ diff --git a/img/dye laser.webp b/img/dye laser.webp new file mode 100644 index 0000000..3a9cf69 Binary files /dev/null and b/img/dye laser.webp differ diff --git a/img/dynamic equilibrium.webp b/img/dynamic equilibrium.webp new file mode 100644 index 0000000..c26522b Binary files /dev/null and b/img/dynamic equilibrium.webp differ diff --git a/img/dynamical systems.webp b/img/dynamical systems.webp new file mode 100644 index 0000000..825d7fd Binary files /dev/null and b/img/dynamical systems.webp differ diff --git a/img/dynamo-bot upgrade.webp b/img/dynamo-bot upgrade.webp new file mode 100644 index 0000000..15b3d61 Binary files /dev/null and b/img/dynamo-bot upgrade.webp differ diff --git a/img/dynamo-bot.webp b/img/dynamo-bot.webp new file mode 100644 index 0000000..71f5d05 Binary files /dev/null and b/img/dynamo-bot.webp differ diff --git a/img/eddy current brake.webp b/img/eddy current brake.webp new file mode 100644 index 0000000..9d95e5a Binary files /dev/null and b/img/eddy current brake.webp differ diff --git a/img/electric armor.webp b/img/electric armor.webp new file mode 100644 index 0000000..2ee7dc0 Binary files /dev/null and b/img/electric armor.webp differ diff --git a/img/electric generator.webp b/img/electric generator.webp new file mode 100644 index 0000000..9c23ad3 Binary files /dev/null and b/img/electric generator.webp differ diff --git a/img/electronegativity.webp b/img/electronegativity.webp new file mode 100644 index 0000000..99c0822 Binary files /dev/null and b/img/electronegativity.webp differ diff --git a/img/electrostatic induction.webp b/img/electrostatic induction.webp new file mode 100644 index 0000000..8d1b018 Binary files /dev/null and b/img/electrostatic induction.webp differ diff --git a/img/elephants toothpaste.webp b/img/elephants toothpaste.webp new file mode 100644 index 0000000..3e94597 Binary files /dev/null and b/img/elephants toothpaste.webp differ diff --git a/img/emergence.webp b/img/emergence.webp new file mode 100644 index 0000000..f7d87e0 Binary files /dev/null and b/img/emergence.webp differ diff --git a/img/energy conservation.webp b/img/energy conservation.webp new file mode 100644 index 0000000..9b52335 Binary files /dev/null and b/img/energy conservation.webp differ diff --git a/img/enthalpy.webp b/img/enthalpy.webp new file mode 100644 index 0000000..c663288 Binary files /dev/null and b/img/enthalpy.webp differ diff --git a/img/ergodicity.webp b/img/ergodicity.webp new file mode 100644 index 0000000..6e82295 Binary files /dev/null and b/img/ergodicity.webp differ diff --git a/img/ersatz bots.webp b/img/ersatz bots.webp new file mode 100644 index 0000000..3074c07 Binary files /dev/null and b/img/ersatz bots.webp differ diff --git a/img/eternalism.webp b/img/eternalism.webp new file mode 100644 index 0000000..08df1ea Binary files /dev/null and b/img/eternalism.webp differ diff --git a/img/exchange symmetry.webp b/img/exchange symmetry.webp new file mode 100644 index 0000000..15a2c09 Binary files /dev/null and b/img/exchange symmetry.webp differ diff --git a/img/exciton.webp b/img/exciton.webp new file mode 100644 index 0000000..d6a99ba Binary files /dev/null and b/img/exciton.webp differ diff --git a/img/exothermic process.webp b/img/exothermic process.webp new file mode 100644 index 0000000..a75216f Binary files /dev/null and b/img/exothermic process.webp differ diff --git a/img/expansion.webp b/img/expansion.webp new file mode 100644 index 0000000..a4645c6 Binary files /dev/null and b/img/expansion.webp differ diff --git a/img/extruder.webp b/img/extruder.webp new file mode 100644 index 0000000..eb14af0 Binary files /dev/null and b/img/extruder.webp differ diff --git a/img/fault tolerance.webp b/img/fault tolerance.webp new file mode 100644 index 0000000..359b392 Binary files /dev/null and b/img/fault tolerance.webp differ diff --git a/img/field coupling.webp b/img/field coupling.webp new file mode 100644 index 0000000..06376a9 Binary files /dev/null and b/img/field coupling.webp differ diff --git a/img/field/field emitter0.webp b/img/field/field emitter0.webp new file mode 100644 index 0000000..3ab87f6 Binary files /dev/null and b/img/field/field emitter0.webp differ diff --git a/img/field/field emitter1.webp b/img/field/field emitter1.webp new file mode 100644 index 0000000..f92a41c Binary files /dev/null and b/img/field/field emitter1.webp differ diff --git a/img/field/field emitter2.webp b/img/field/field emitter2.webp new file mode 100644 index 0000000..e6ac350 Binary files /dev/null and b/img/field/field emitter2.webp differ diff --git a/img/field/field emitter3.webp b/img/field/field emitter3.webp new file mode 100644 index 0000000..dd85734 Binary files /dev/null and b/img/field/field emitter3.webp differ diff --git a/img/field/field emitter4.webp b/img/field/field emitter4.webp new file mode 100644 index 0000000..8bff016 Binary files /dev/null and b/img/field/field emitter4.webp differ diff --git a/img/field/field emitter5.webp b/img/field/field emitter5.webp new file mode 100644 index 0000000..ef1a667 Binary files /dev/null and b/img/field/field emitter5.webp differ diff --git a/img/field/field emitter6.webp b/img/field/field emitter6.webp new file mode 100644 index 0000000..144313a Binary files /dev/null and b/img/field/field emitter6.webp differ diff --git a/img/field/field emitter7.webp b/img/field/field emitter7.webp new file mode 100644 index 0000000..baad4a3 Binary files /dev/null and b/img/field/field emitter7.webp differ diff --git a/img/field/field emitter8.webp b/img/field/field emitter8.webp new file mode 100644 index 0000000..4ed2781 Binary files /dev/null and b/img/field/field emitter8.webp differ diff --git a/img/field/field emitter9.webp b/img/field/field emitter9.webp new file mode 100644 index 0000000..7b9a847 Binary files /dev/null and b/img/field/field emitter9.webp differ diff --git a/img/field/metamaterial cloaking.webp b/img/field/metamaterial cloaking.webp new file mode 100644 index 0000000..2273eab Binary files /dev/null and b/img/field/metamaterial cloaking.webp differ diff --git a/img/field/molecular assembler.webp b/img/field/molecular assembler.webp new file mode 100644 index 0000000..0478e95 Binary files /dev/null and b/img/field/molecular assembler.webp differ diff --git a/img/field/negative mass.webp b/img/field/negative mass.webp new file mode 100644 index 0000000..f6f94dd Binary files /dev/null and b/img/field/negative mass.webp differ diff --git a/img/field/perfect diamagnetism.webp b/img/field/perfect diamagnetism.webp new file mode 100644 index 0000000..82a5f1f Binary files /dev/null and b/img/field/perfect diamagnetism.webp differ diff --git a/img/field/pilot wave.webp b/img/field/pilot wave.webp new file mode 100644 index 0000000..b8b54ae Binary files /dev/null and b/img/field/pilot wave.webp differ diff --git a/img/field/plasma torch.webp b/img/field/plasma torch.webp new file mode 100644 index 0000000..95cbaef Binary files /dev/null and b/img/field/plasma torch.webp differ diff --git a/img/field/quantum immortality.webp b/img/field/quantum immortality.webp new file mode 100644 index 0000000..6e730bf Binary files /dev/null and b/img/field/quantum immortality.webp differ diff --git a/img/field/squirrel-cage rotor.webp b/img/field/squirrel-cage rotor.webp new file mode 100644 index 0000000..87209ad Binary files /dev/null and b/img/field/squirrel-cage rotor.webp differ diff --git a/img/field/standing wave.webp b/img/field/standing wave.webp new file mode 100644 index 0000000..5f237b6 Binary files /dev/null and b/img/field/standing wave.webp differ diff --git a/img/field/time dilation.webp b/img/field/time dilation.webp new file mode 100644 index 0000000..e7c0cc1 Binary files /dev/null and b/img/field/time dilation.webp differ diff --git a/img/field/wormhole.webp b/img/field/wormhole.webp new file mode 100644 index 0000000..ec2fab4 Binary files /dev/null and b/img/field/wormhole.webp differ diff --git a/img/fine-structure constant.webp b/img/fine-structure constant.webp new file mode 100644 index 0000000..d070faa Binary files /dev/null and b/img/fine-structure constant.webp differ diff --git a/img/fireworks.webp b/img/fireworks.webp new file mode 100644 index 0000000..b73b126 Binary files /dev/null and b/img/fireworks.webp differ diff --git a/img/first derivative.webp b/img/first derivative.webp new file mode 100644 index 0000000..f32d1bd Binary files /dev/null and b/img/first derivative.webp differ diff --git a/img/flagella.webp b/img/flagella.webp new file mode 100644 index 0000000..130ca50 Binary files /dev/null and b/img/flagella.webp differ diff --git a/img/flame test.webp b/img/flame test.webp new file mode 100644 index 0000000..c9f5013 Binary files /dev/null and b/img/flame test.webp differ diff --git a/img/flash freeze.webp b/img/flash freeze.webp new file mode 100644 index 0000000..bb5d0a0 Binary files /dev/null and b/img/flash freeze.webp differ diff --git a/img/flip-flop.webp b/img/flip-flop.webp new file mode 100644 index 0000000..9c0d494 Binary files /dev/null and b/img/flip-flop.webp differ diff --git a/img/fluoroantimonic acid.webp b/img/fluoroantimonic acid.webp new file mode 100644 index 0000000..23918ed Binary files /dev/null and b/img/fluoroantimonic acid.webp differ diff --git a/img/flux pinning.webp b/img/flux pinning.webp new file mode 100644 index 0000000..aa2baa0 Binary files /dev/null and b/img/flux pinning.webp differ diff --git a/img/flywheel.webp b/img/flywheel.webp new file mode 100644 index 0000000..953e9f2 Binary files /dev/null and b/img/flywheel.webp differ diff --git a/img/foam fractionation.webp b/img/foam fractionation.webp new file mode 100644 index 0000000..46b24ab Binary files /dev/null and b/img/foam fractionation.webp differ diff --git a/img/foam-bot upgrade.webp b/img/foam-bot upgrade.webp new file mode 100644 index 0000000..5b729cb Binary files /dev/null and b/img/foam-bot upgrade.webp differ diff --git a/img/foam-bot.webp b/img/foam-bot.webp new file mode 100644 index 0000000..b6a49b7 Binary files /dev/null and b/img/foam-bot.webp differ diff --git a/img/foam-shot.webp b/img/foam-shot.webp new file mode 100644 index 0000000..f7ecda9 Binary files /dev/null and b/img/foam-shot.webp differ diff --git a/img/fracture analysis.webp b/img/fracture analysis.webp new file mode 100644 index 0000000..0988e9e Binary files /dev/null and b/img/fracture analysis.webp differ diff --git a/img/fragmentation.webp b/img/fragmentation.webp new file mode 100644 index 0000000..ea6c04b Binary files /dev/null and b/img/fragmentation.webp differ diff --git a/img/frame-dragging.webp b/img/frame-dragging.webp new file mode 100644 index 0000000..09b90ba Binary files /dev/null and b/img/frame-dragging.webp differ diff --git a/img/free-electron laser.webp b/img/free-electron laser.webp new file mode 100644 index 0000000..236492f Binary files /dev/null and b/img/free-electron laser.webp differ diff --git a/img/freezer burn.webp b/img/freezer burn.webp new file mode 100644 index 0000000..57750a4 Binary files /dev/null and b/img/freezer burn.webp differ diff --git a/img/frequency.webp b/img/frequency.webp new file mode 100644 index 0000000..b8b26a2 Binary files /dev/null and b/img/frequency.webp differ diff --git a/img/futures exchange.webp b/img/futures exchange.webp new file mode 100644 index 0000000..8d492ac Binary files /dev/null and b/img/futures exchange.webp differ diff --git a/img/gauge.webp b/img/gauge.webp new file mode 100644 index 0000000..d5c4df4 Binary files /dev/null and b/img/gauge.webp differ diff --git a/img/generalist.webp b/img/generalist.webp new file mode 100644 index 0000000..802cbb2 Binary files /dev/null and b/img/generalist.webp differ diff --git a/img/geodesics.webp b/img/geodesics.webp new file mode 100644 index 0000000..4cb475b Binary files /dev/null and b/img/geodesics.webp differ diff --git a/img/grappling hook.webp b/img/grappling hook.webp new file mode 100644 index 0000000..4b54ade Binary files /dev/null and b/img/grappling hook.webp differ diff --git a/img/ground state.webp b/img/ground state.webp new file mode 100644 index 0000000..5e6ba80 Binary files /dev/null and b/img/ground state.webp differ diff --git a/img/gun turret.webp b/img/gun turret.webp new file mode 100644 index 0000000..ca8bc6c Binary files /dev/null and b/img/gun turret.webp differ diff --git a/img/gun/drones.webp b/img/gun/drones.webp new file mode 100644 index 0000000..6429896 Binary files /dev/null and b/img/gun/drones.webp differ diff --git a/img/gun/foam.webp b/img/gun/foam.webp new file mode 100644 index 0000000..69944a5 Binary files /dev/null and b/img/gun/foam.webp differ diff --git a/img/gun/grenades.webp b/img/gun/grenades.webp new file mode 100644 index 0000000..6b5e3d1 Binary files /dev/null and b/img/gun/grenades.webp differ diff --git a/img/gun/harpoon.webp b/img/gun/harpoon.webp new file mode 100644 index 0000000..fcf8bed Binary files /dev/null and b/img/gun/harpoon.webp differ diff --git a/img/gun/laser.webp b/img/gun/laser.webp new file mode 100644 index 0000000..694a711 Binary files /dev/null and b/img/gun/laser.webp differ diff --git a/img/gun/mine.webp b/img/gun/mine.webp new file mode 100644 index 0000000..dc49e3c Binary files /dev/null and b/img/gun/mine.webp differ diff --git a/img/gun/missiles.webp b/img/gun/missiles.webp new file mode 100644 index 0000000..2e822b5 Binary files /dev/null and b/img/gun/missiles.webp differ diff --git a/img/gun/nail gun.webp b/img/gun/nail gun.webp new file mode 100644 index 0000000..c8b1743 Binary files /dev/null and b/img/gun/nail gun.webp differ diff --git a/img/gun/shotgun.webp b/img/gun/shotgun.webp new file mode 100644 index 0000000..6714812 Binary files /dev/null and b/img/gun/shotgun.webp differ diff --git a/img/gun/spores.webp b/img/gun/spores.webp new file mode 100644 index 0000000..3fa7c04 Binary files /dev/null and b/img/gun/spores.webp differ diff --git a/img/gun/super balls.webp b/img/gun/super balls.webp new file mode 100644 index 0000000..1daa387 Binary files /dev/null and b/img/gun/super balls.webp differ diff --git a/img/gun/wave.webp b/img/gun/wave.webp new file mode 100644 index 0000000..fb115db Binary files /dev/null and b/img/gun/wave.webp differ diff --git a/img/heat engine.webp b/img/heat engine.webp new file mode 100644 index 0000000..7394708 Binary files /dev/null and b/img/heat engine.webp differ diff --git a/img/heuristics.webp b/img/heuristics.webp new file mode 100644 index 0000000..1d2db74 Binary files /dev/null and b/img/heuristics.webp differ diff --git a/img/homeostasis.webp b/img/homeostasis.webp new file mode 100644 index 0000000..9d107d3 Binary files /dev/null and b/img/homeostasis.webp differ diff --git a/img/ice crystal nucleation.webp b/img/ice crystal nucleation.webp new file mode 100644 index 0000000..160876b Binary files /dev/null and b/img/ice crystal nucleation.webp differ diff --git a/img/ice-shot.webp b/img/ice-shot.webp new file mode 100644 index 0000000..4f3169e Binary files /dev/null and b/img/ice-shot.webp differ diff --git a/img/ideal gas law.webp b/img/ideal gas law.webp new file mode 100644 index 0000000..e00129a Binary files /dev/null and b/img/ideal gas law.webp differ diff --git a/img/incendiary ammunition.webp b/img/incendiary ammunition.webp new file mode 100644 index 0000000..643248d Binary files /dev/null and b/img/incendiary ammunition.webp differ diff --git a/img/induction furnace.webp b/img/induction furnace.webp new file mode 100644 index 0000000..af1aac8 Binary files /dev/null and b/img/induction furnace.webp differ diff --git a/img/inductive charging.webp b/img/inductive charging.webp new file mode 100644 index 0000000..e3765ea Binary files /dev/null and b/img/inductive charging.webp differ diff --git a/img/inertial mass.webp b/img/inertial mass.webp new file mode 100644 index 0000000..0630900 Binary files /dev/null and b/img/inertial mass.webp differ diff --git a/img/inflation.webp b/img/inflation.webp new file mode 100644 index 0000000..1f4374e Binary files /dev/null and b/img/inflation.webp differ diff --git a/img/infrared diode.webp b/img/infrared diode.webp new file mode 100644 index 0000000..e6a0d5a Binary files /dev/null and b/img/infrared diode.webp differ diff --git a/img/integrated armament.webp b/img/integrated armament.webp new file mode 100644 index 0000000..b876da6 Binary files /dev/null and b/img/integrated armament.webp differ diff --git a/img/integrated circuit.webp b/img/integrated circuit.webp new file mode 100644 index 0000000..3feb4a4 Binary files /dev/null and b/img/integrated circuit.webp differ diff --git a/img/invariant.webp b/img/invariant.webp new file mode 100644 index 0000000..9092bed Binary files /dev/null and b/img/invariant.webp differ diff --git a/img/iridescence.webp b/img/iridescence.webp new file mode 100644 index 0000000..4bdb1e1 Binary files /dev/null and b/img/iridescence.webp differ diff --git a/img/iridium-192.webp b/img/iridium-192.webp new file mode 100644 index 0000000..bd58949 Binary files /dev/null and b/img/iridium-192.webp differ diff --git a/img/irradiated drones.webp b/img/irradiated drones.webp new file mode 100644 index 0000000..d3f2db5 Binary files /dev/null and b/img/irradiated drones.webp differ diff --git a/img/irradiated nails.webp b/img/irradiated nails.webp new file mode 100644 index 0000000..7ce6e2c Binary files /dev/null and b/img/irradiated nails.webp differ diff --git a/img/isotropic.webp b/img/isotropic.webp new file mode 100644 index 0000000..ef8984b Binary files /dev/null and b/img/isotropic.webp differ diff --git a/img/junk DNA.webp b/img/junk DNA.webp new file mode 100644 index 0000000..c8029c6 Binary files /dev/null and b/img/junk DNA.webp differ diff --git a/img/kinetic bombardment.webp b/img/kinetic bombardment.webp new file mode 100644 index 0000000..f7cd8b5 Binary files /dev/null and b/img/kinetic bombardment.webp differ diff --git a/img/laser-bot upgrade.webp b/img/laser-bot upgrade.webp new file mode 100644 index 0000000..6df8d4e Binary files /dev/null and b/img/laser-bot upgrade.webp differ diff --git a/img/laser-bot.webp b/img/laser-bot.webp new file mode 100644 index 0000000..1e82e9a Binary files /dev/null and b/img/laser-bot.webp differ diff --git a/img/laser-mines.webp b/img/laser-mines.webp new file mode 100644 index 0000000..639f6ca Binary files /dev/null and b/img/laser-mines.webp differ diff --git a/img/launch system.webp b/img/launch system.webp new file mode 100644 index 0000000..8c10eab Binary files /dev/null and b/img/launch system.webp differ diff --git a/img/lens.webp b/img/lens.webp new file mode 100644 index 0000000..1ad4e50 Binary files /dev/null and b/img/lens.webp differ diff --git a/img/liquid cooling.webp b/img/liquid cooling.webp new file mode 100644 index 0000000..1f9fb98 Binary files /dev/null and b/img/liquid cooling.webp differ diff --git a/img/lithium-ion.webp b/img/lithium-ion.webp new file mode 100644 index 0000000..73ae0e7 Binary files /dev/null and b/img/lithium-ion.webp differ diff --git a/img/logistics.webp b/img/logistics.webp new file mode 100644 index 0000000..1b31696 Binary files /dev/null and b/img/logistics.webp differ diff --git a/img/maintenance.webp b/img/maintenance.webp new file mode 100644 index 0000000..c6b1da8 Binary files /dev/null and b/img/maintenance.webp differ diff --git a/img/many-worlds.webp b/img/many-worlds.webp new file mode 100644 index 0000000..d3028e4 Binary files /dev/null and b/img/many-worlds.webp differ diff --git a/img/mass driver.webp b/img/mass driver.webp new file mode 100644 index 0000000..fe943e3 Binary files /dev/null and b/img/mass driver.webp differ diff --git a/img/mass-energy equivalence.webp b/img/mass-energy equivalence.webp new file mode 100644 index 0000000..b00a85b Binary files /dev/null and b/img/mass-energy equivalence.webp differ diff --git a/img/mechanical resonance.webp b/img/mechanical resonance.webp new file mode 100644 index 0000000..c609231 Binary files /dev/null and b/img/mechanical resonance.webp differ diff --git a/img/meta-analysis.webp b/img/meta-analysis.webp new file mode 100644 index 0000000..3fe80d8 Binary files /dev/null and b/img/meta-analysis.webp differ diff --git a/img/metastability.webp b/img/metastability.webp new file mode 100644 index 0000000..2a4e8b1 Binary files /dev/null and b/img/metastability.webp differ diff --git a/img/microstates.webp b/img/microstates.webp new file mode 100644 index 0000000..f3794f2 Binary files /dev/null and b/img/microstates.webp differ diff --git a/img/missile-bot.webp b/img/missile-bot.webp new file mode 100644 index 0000000..d465f09 Binary files /dev/null and b/img/missile-bot.webp differ diff --git a/img/mutualism.webp b/img/mutualism.webp new file mode 100644 index 0000000..e1fb494 Binary files /dev/null and b/img/mutualism.webp differ diff --git a/img/mycelial fragmentation.webp b/img/mycelial fragmentation.webp new file mode 100644 index 0000000..7c8f807 Binary files /dev/null and b/img/mycelial fragmentation.webp differ diff --git a/img/nail-bot upgrade.webp b/img/nail-bot upgrade.webp new file mode 100644 index 0000000..fc3518a Binary files /dev/null and b/img/nail-bot upgrade.webp differ diff --git a/img/nail-bot.webp b/img/nail-bot.webp new file mode 100644 index 0000000..1b0da80 Binary files /dev/null and b/img/nail-bot.webp differ diff --git a/img/nail-shot.webp b/img/nail-shot.webp new file mode 100644 index 0000000..d9743f9 Binary files /dev/null and b/img/nail-shot.webp differ diff --git a/img/nanowires.webp b/img/nanowires.webp new file mode 100644 index 0000000..e7c6b61 Binary files /dev/null and b/img/nanowires.webp differ diff --git a/img/necrophage.webp b/img/necrophage.webp new file mode 100644 index 0000000..47f7fae Binary files /dev/null and b/img/necrophage.webp differ diff --git a/img/needle gun.webp b/img/needle gun.webp new file mode 100644 index 0000000..b976c12 Binary files /dev/null and b/img/needle gun.webp differ diff --git a/img/needle ice.webp b/img/needle ice.webp new file mode 100644 index 0000000..4235695 Binary files /dev/null and b/img/needle ice.webp differ diff --git a/img/negative entropy.webp b/img/negative entropy.webp new file mode 100644 index 0000000..734de05 Binary files /dev/null and b/img/negative entropy.webp differ diff --git a/img/negative feedback.webp b/img/negative feedback.webp new file mode 100644 index 0000000..e48783b Binary files /dev/null and b/img/negative feedback.webp differ diff --git a/img/nematodes.webp b/img/nematodes.webp new file mode 100644 index 0000000..3fba87f Binary files /dev/null and b/img/nematodes.webp differ diff --git a/img/network effect.webp b/img/network effect.webp new file mode 100644 index 0000000..1084a7e Binary files /dev/null and b/img/network effect.webp differ diff --git a/img/neutron bomb.webp b/img/neutron bomb.webp new file mode 100644 index 0000000..e5ea20f Binary files /dev/null and b/img/neutron bomb.webp differ diff --git a/img/neutronium.webp b/img/neutronium.webp new file mode 100644 index 0000000..fce6535 Binary files /dev/null and b/img/neutronium.webp differ diff --git a/img/nitroglycerin.webp b/img/nitroglycerin.webp new file mode 100644 index 0000000..55f5f2e Binary files /dev/null and b/img/nitroglycerin.webp differ diff --git a/img/no-cloning theorem.webp b/img/no-cloning theorem.webp new file mode 100644 index 0000000..25a5c43 Binary files /dev/null and b/img/no-cloning theorem.webp differ diff --git a/img/non-Newtonian armor.webp b/img/non-Newtonian armor.webp new file mode 100644 index 0000000..f7e3823 Binary files /dev/null and b/img/non-Newtonian armor.webp differ diff --git a/img/non-renewables.webp b/img/non-renewables.webp new file mode 100644 index 0000000..bd4843e Binary files /dev/null and b/img/non-renewables.webp differ diff --git a/img/nuclear transmutation.webp b/img/nuclear transmutation.webp new file mode 100644 index 0000000..ba6b3f9 Binary files /dev/null and b/img/nuclear transmutation.webp differ diff --git a/img/open-source.webp b/img/open-source.webp new file mode 100644 index 0000000..44b6a23 Binary files /dev/null and b/img/open-source.webp differ diff --git a/img/optical amplifier.webp b/img/optical amplifier.webp new file mode 100644 index 0000000..7fa8051 Binary files /dev/null and b/img/optical amplifier.webp differ diff --git a/img/options exchange.webp b/img/options exchange.webp new file mode 100644 index 0000000..6ff2c4f Binary files /dev/null and b/img/options exchange.webp differ diff --git a/img/orbital-bot upgrade.webp b/img/orbital-bot upgrade.webp new file mode 100644 index 0000000..010f6e1 Binary files /dev/null and b/img/orbital-bot upgrade.webp differ diff --git a/img/orbital-bot.webp b/img/orbital-bot.webp new file mode 100644 index 0000000..003029a Binary files /dev/null and b/img/orbital-bot.webp differ diff --git a/img/ordnance.webp b/img/ordnance.webp new file mode 100644 index 0000000..f28c241 Binary files /dev/null and b/img/ordnance.webp differ diff --git a/img/orthocyclic winding.webp b/img/orthocyclic winding.webp new file mode 100644 index 0000000..770461b Binary files /dev/null and b/img/orthocyclic winding.webp differ diff --git a/img/output coupler.webp b/img/output coupler.webp new file mode 100644 index 0000000..61670f8 Binary files /dev/null and b/img/output coupler.webp differ diff --git a/img/overcharge.webp b/img/overcharge.webp new file mode 100644 index 0000000..69f5712 Binary files /dev/null and b/img/overcharge.webp differ diff --git a/img/pair production.webp b/img/pair production.webp new file mode 100644 index 0000000..6e6d634 Binary files /dev/null and b/img/pair production.webp differ diff --git a/img/paradigm shift.webp b/img/paradigm shift.webp new file mode 100644 index 0000000..4955395 Binary files /dev/null and b/img/paradigm shift.webp differ diff --git a/img/parasitism.webp b/img/parasitism.webp new file mode 100644 index 0000000..dbab55b Binary files /dev/null and b/img/parasitism.webp differ diff --git a/img/parthenogenesis.webp b/img/parthenogenesis.webp new file mode 100644 index 0000000..e74f1c5 Binary files /dev/null and b/img/parthenogenesis.webp differ diff --git a/img/patch.webp b/img/patch.webp new file mode 100644 index 0000000..dd94f4d Binary files /dev/null and b/img/patch.webp differ diff --git a/img/path integral.webp b/img/path integral.webp new file mode 100644 index 0000000..a81389b Binary files /dev/null and b/img/path integral.webp differ diff --git a/img/path integration.webp b/img/path integration.webp new file mode 100644 index 0000000..7eeb22b Binary files /dev/null and b/img/path integration.webp differ diff --git a/img/perimeter defense.webp b/img/perimeter defense.webp new file mode 100644 index 0000000..a1b4c26 Binary files /dev/null and b/img/perimeter defense.webp differ diff --git a/img/perturbation theory.webp b/img/perturbation theory.webp new file mode 100644 index 0000000..6e68752 Binary files /dev/null and b/img/perturbation theory.webp differ diff --git a/img/phase velocity.webp b/img/phase velocity.webp new file mode 100644 index 0000000..35875c2 Binary files /dev/null and b/img/phase velocity.webp differ diff --git a/img/phonon.webp b/img/phonon.webp new file mode 100644 index 0000000..53f7afe Binary files /dev/null and b/img/phonon.webp differ diff --git a/img/piezoelectricity.webp b/img/piezoelectricity.webp new file mode 100644 index 0000000..25ec3fc Binary files /dev/null and b/img/piezoelectricity.webp differ diff --git a/img/pigeonhole principle.webp b/img/pigeonhole principle.webp new file mode 100644 index 0000000..6a825df Binary files /dev/null and b/img/pigeonhole principle.webp differ diff --git a/img/plasma ball.webp b/img/plasma ball.webp new file mode 100644 index 0000000..b705d71 Binary files /dev/null and b/img/plasma ball.webp differ diff --git a/img/plasma jet.webp b/img/plasma jet.webp new file mode 100644 index 0000000..e614269 Binary files /dev/null and b/img/plasma jet.webp differ diff --git a/img/plasma-bot.webp b/img/plasma-bot.webp new file mode 100644 index 0000000..9d71d50 Binary files /dev/null and b/img/plasma-bot.webp differ diff --git a/img/pneumatic actuator.webp b/img/pneumatic actuator.webp new file mode 100644 index 0000000..9bb5a7f Binary files /dev/null and b/img/pneumatic actuator.webp differ diff --git a/img/polyurethane foam.webp b/img/polyurethane foam.webp new file mode 100644 index 0000000..a875deb Binary files /dev/null and b/img/polyurethane foam.webp differ diff --git a/img/pressure vessel.webp b/img/pressure vessel.webp new file mode 100644 index 0000000..0feb70d Binary files /dev/null and b/img/pressure vessel.webp differ diff --git a/img/propagation.webp b/img/propagation.webp new file mode 100644 index 0000000..7f8fe3c Binary files /dev/null and b/img/propagation.webp differ diff --git a/img/propagator.webp b/img/propagator.webp new file mode 100644 index 0000000..733638b Binary files /dev/null and b/img/propagator.webp differ diff --git a/img/pseudoscience.webp b/img/pseudoscience.webp new file mode 100644 index 0000000..fdee13b Binary files /dev/null and b/img/pseudoscience.webp differ diff --git a/img/pulse.webp b/img/pulse.webp new file mode 100644 index 0000000..6225cde Binary files /dev/null and b/img/pulse.webp differ diff --git a/img/pyrotechnics.webp b/img/pyrotechnics.webp new file mode 100644 index 0000000..7d6457d Binary files /dev/null and b/img/pyrotechnics.webp differ diff --git a/img/quantum eraser.webp b/img/quantum eraser.webp new file mode 100644 index 0000000..fc86480 Binary files /dev/null and b/img/quantum eraser.webp differ diff --git a/img/quantum immortality.webp b/img/quantum immortality.webp new file mode 100644 index 0000000..fb07b3c Binary files /dev/null and b/img/quantum immortality.webp differ diff --git a/img/quasiparticles.webp b/img/quasiparticles.webp new file mode 100644 index 0000000..18d3bad Binary files /dev/null and b/img/quasiparticles.webp differ diff --git a/img/quenching.webp b/img/quenching.webp new file mode 100644 index 0000000..ecf7887 Binary files /dev/null and b/img/quenching.webp differ diff --git a/img/quintessence.webp b/img/quintessence.webp new file mode 100644 index 0000000..617bb16 Binary files /dev/null and b/img/quintessence.webp differ diff --git a/img/radiative equilibrium.webp b/img/radiative equilibrium.webp new file mode 100644 index 0000000..6fd3b3d Binary files /dev/null and b/img/radiative equilibrium.webp differ diff --git a/img/radioactive contamination.webp b/img/radioactive contamination.webp new file mode 100644 index 0000000..347dab4 Binary files /dev/null and b/img/radioactive contamination.webp differ diff --git a/img/railgun.webp b/img/railgun.webp new file mode 100644 index 0000000..d80883f Binary files /dev/null and b/img/railgun.webp differ diff --git a/img/reaction inhibitor.webp b/img/reaction inhibitor.webp new file mode 100644 index 0000000..de5a440 Binary files /dev/null and b/img/reaction inhibitor.webp differ diff --git a/img/recycling.webp b/img/recycling.webp new file mode 100644 index 0000000..775edc5 Binary files /dev/null and b/img/recycling.webp differ diff --git a/img/reduced tolerances.webp b/img/reduced tolerances.webp new file mode 100644 index 0000000..35b4ee8 Binary files /dev/null and b/img/reduced tolerances.webp differ diff --git a/img/refraction.webp b/img/refraction.webp new file mode 100644 index 0000000..4901c68 Binary files /dev/null and b/img/refraction.webp differ diff --git a/img/refractory metal.webp b/img/refractory metal.webp new file mode 100644 index 0000000..596e82a Binary files /dev/null and b/img/refractory metal.webp differ diff --git a/img/regression.webp b/img/regression.webp new file mode 100644 index 0000000..5102a32 Binary files /dev/null and b/img/regression.webp differ diff --git a/img/reinforcement learning.webp b/img/reinforcement learning.webp new file mode 100644 index 0000000..7711853 Binary files /dev/null and b/img/reinforcement learning.webp differ diff --git a/img/relativistic momentum.webp b/img/relativistic momentum.webp new file mode 100644 index 0000000..5542265 Binary files /dev/null and b/img/relativistic momentum.webp differ diff --git a/img/relay switch.webp b/img/relay switch.webp new file mode 100644 index 0000000..eff6139 Binary files /dev/null and b/img/relay switch.webp differ diff --git a/img/renormalization.webp b/img/renormalization.webp new file mode 100644 index 0000000..6b0391b Binary files /dev/null and b/img/renormalization.webp differ diff --git a/img/replication.webp b/img/replication.webp new file mode 100644 index 0000000..e15df43 Binary files /dev/null and b/img/replication.webp differ diff --git a/img/residual dipolar coupling.webp b/img/residual dipolar coupling.webp new file mode 100644 index 0000000..5fcb972 Binary files /dev/null and b/img/residual dipolar coupling.webp differ diff --git a/img/restitution.webp b/img/restitution.webp new file mode 100644 index 0000000..3ec9f61 Binary files /dev/null and b/img/restitution.webp differ diff --git a/img/retrocausality.webp b/img/retrocausality.webp new file mode 100644 index 0000000..17997c7 Binary files /dev/null and b/img/retrocausality.webp differ diff --git a/img/ricochet.webp b/img/ricochet.webp new file mode 100644 index 0000000..f970b30 Binary files /dev/null and b/img/ricochet.webp differ diff --git a/img/rivet gun.webp b/img/rivet gun.webp new file mode 100644 index 0000000..a94f4f6 Binary files /dev/null and b/img/rivet gun.webp differ diff --git a/img/robotics.webp b/img/robotics.webp new file mode 100644 index 0000000..feba476 Binary files /dev/null and b/img/robotics.webp differ diff --git a/img/rocket-propelled grenade.webp b/img/rocket-propelled grenade.webp new file mode 100644 index 0000000..1ef1b92 Binary files /dev/null and b/img/rocket-propelled grenade.webp differ diff --git a/img/rotary cannon.webp b/img/rotary cannon.webp new file mode 100644 index 0000000..69df5fc Binary files /dev/null and b/img/rotary cannon.webp differ diff --git a/img/scrap bots.webp b/img/scrap bots.webp new file mode 100644 index 0000000..9482b30 Binary files /dev/null and b/img/scrap bots.webp differ diff --git a/img/scrap refit.webp b/img/scrap refit.webp new file mode 100644 index 0000000..243fcc7 Binary files /dev/null and b/img/scrap refit.webp differ diff --git a/img/sentry.webp b/img/sentry.webp new file mode 100644 index 0000000..eac727d Binary files /dev/null and b/img/sentry.webp differ diff --git a/img/shape-memory alloy.webp b/img/shape-memory alloy.webp new file mode 100644 index 0000000..fc76420 Binary files /dev/null and b/img/shape-memory alloy.webp differ diff --git a/img/shaped charge.webp b/img/shaped charge.webp new file mode 100644 index 0000000..c1afd4f Binary files /dev/null and b/img/shaped charge.webp differ diff --git a/img/shear stress.webp b/img/shear stress.webp new file mode 100644 index 0000000..fb9a1e8 Binary files /dev/null and b/img/shear stress.webp differ diff --git a/img/shock wave.webp b/img/shock wave.webp new file mode 100644 index 0000000..ff4d945 Binary files /dev/null and b/img/shock wave.webp differ diff --git a/img/simulated annealing.webp b/img/simulated annealing.webp new file mode 100644 index 0000000..156dd96 Binary files /dev/null and b/img/simulated annealing.webp differ diff --git a/img/siphonaptera.webp b/img/siphonaptera.webp new file mode 100644 index 0000000..afb816d Binary files /dev/null and b/img/siphonaptera.webp differ diff --git a/img/slow light.webp b/img/slow light.webp new file mode 100644 index 0000000..8f98107 Binary files /dev/null and b/img/slow light.webp differ diff --git a/img/smelting.webp b/img/smelting.webp new file mode 100644 index 0000000..783d4df Binary files /dev/null and b/img/smelting.webp differ diff --git a/img/specular reflection.webp b/img/specular reflection.webp new file mode 100644 index 0000000..315f7cf Binary files /dev/null and b/img/specular reflection.webp differ diff --git a/img/spherical harmonics.webp b/img/spherical harmonics.webp new file mode 100644 index 0000000..e13f0ef Binary files /dev/null and b/img/spherical harmonics.webp differ diff --git a/img/spin-statistics.webp b/img/spin-statistics.webp new file mode 100644 index 0000000..2f2b470 Binary files /dev/null and b/img/spin-statistics.webp differ diff --git a/img/spin–statistics theorem.webp b/img/spin–statistics theorem.webp new file mode 100644 index 0000000..297a2db Binary files /dev/null and b/img/spin–statistics theorem.webp differ diff --git a/img/squirrel-cage rotor.webp b/img/squirrel-cage rotor.webp new file mode 100644 index 0000000..63c2c81 Binary files /dev/null and b/img/squirrel-cage rotor.webp differ diff --git a/img/stimulated emission.webp b/img/stimulated emission.webp new file mode 100644 index 0000000..1fa9f74 Binary files /dev/null and b/img/stimulated emission.webp differ diff --git a/img/strange attractor.webp b/img/strange attractor.webp new file mode 100644 index 0000000..983778f Binary files /dev/null and b/img/strange attractor.webp differ diff --git a/img/stress concentration.webp b/img/stress concentration.webp new file mode 100644 index 0000000..67b9722 Binary files /dev/null and b/img/stress concentration.webp differ diff --git a/img/strong anthropic principle.webp b/img/strong anthropic principle.webp new file mode 100644 index 0000000..ffbfd31 Binary files /dev/null and b/img/strong anthropic principle.webp differ diff --git a/img/super ball.webp b/img/super ball.webp new file mode 100644 index 0000000..9c7f945 Binary files /dev/null and b/img/super ball.webp differ diff --git a/img/super duper.webp b/img/super duper.webp new file mode 100644 index 0000000..d5e1f2a Binary files /dev/null and b/img/super duper.webp differ diff --git a/img/supercritical fission.webp b/img/supercritical fission.webp new file mode 100644 index 0000000..f727d20 Binary files /dev/null and b/img/supercritical fission.webp differ diff --git a/img/superdeterminism.webp b/img/superdeterminism.webp new file mode 100644 index 0000000..d07b9b0 Binary files /dev/null and b/img/superdeterminism.webp differ diff --git a/img/superfluidity.webp b/img/superfluidity.webp new file mode 100644 index 0000000..7f0bc3d Binary files /dev/null and b/img/superfluidity.webp differ diff --git a/img/supply chain.webp b/img/supply chain.webp new file mode 100644 index 0000000..29814ef Binary files /dev/null and b/img/supply chain.webp differ diff --git a/img/surface tension.webp b/img/surface tension.webp new file mode 100644 index 0000000..d736c0b Binary files /dev/null and b/img/surface tension.webp differ diff --git a/img/surfactant.webp b/img/surfactant.webp new file mode 100644 index 0000000..9ded9c8 Binary files /dev/null and b/img/surfactant.webp differ diff --git a/img/symbiosis.webp b/img/symbiosis.webp new file mode 100644 index 0000000..32b35db Binary files /dev/null and b/img/symbiosis.webp differ diff --git a/img/sympathetic resonance.webp b/img/sympathetic resonance.webp new file mode 100644 index 0000000..5f0a77d Binary files /dev/null and b/img/sympathetic resonance.webp differ diff --git a/img/technical debt.webp b/img/technical debt.webp new file mode 100644 index 0000000..7f5facb Binary files /dev/null and b/img/technical debt.webp differ diff --git a/img/tessellation.webp b/img/tessellation.webp new file mode 100644 index 0000000..4992624 Binary files /dev/null and b/img/tessellation.webp differ diff --git a/img/thermal runaway.webp b/img/thermal runaway.webp new file mode 100644 index 0000000..712ad84 Binary files /dev/null and b/img/thermal runaway.webp differ diff --git a/img/thermocouple.webp b/img/thermocouple.webp new file mode 100644 index 0000000..d669ea5 Binary files /dev/null and b/img/thermocouple.webp differ diff --git a/img/thermoelectric effect.webp b/img/thermoelectric effect.webp new file mode 100644 index 0000000..bc91ec2 Binary files /dev/null and b/img/thermoelectric effect.webp differ diff --git a/img/time crystals.webp b/img/time crystals.webp new file mode 100644 index 0000000..5b06557 Binary files /dev/null and b/img/time crystals.webp differ diff --git a/img/tokamak.webp b/img/tokamak.webp new file mode 100644 index 0000000..c9e4096 Binary files /dev/null and b/img/tokamak.webp differ diff --git a/img/torpor.webp b/img/torpor.webp new file mode 100644 index 0000000..cc1165f Binary files /dev/null and b/img/torpor.webp differ diff --git a/img/transdimensional worms.webp b/img/transdimensional worms.webp new file mode 100644 index 0000000..e01c780 Binary files /dev/null and b/img/transdimensional worms.webp differ diff --git a/img/transistor.webp b/img/transistor.webp new file mode 100644 index 0000000..f62e0c3 Binary files /dev/null and b/img/transistor.webp differ diff --git a/img/triple point.webp b/img/triple point.webp new file mode 100644 index 0000000..260cba6 Binary files /dev/null and b/img/triple point.webp differ diff --git a/img/tungsten carbide.webp b/img/tungsten carbide.webp new file mode 100644 index 0000000..ac6fda4 Binary files /dev/null and b/img/tungsten carbide.webp differ diff --git a/img/uncertainty principle.webp b/img/uncertainty principle.webp new file mode 100644 index 0000000..da73750 Binary files /dev/null and b/img/uncertainty principle.webp differ diff --git a/img/undefined.webp b/img/undefined.webp new file mode 100644 index 0000000..be435a0 Binary files /dev/null and b/img/undefined.webp differ diff --git a/img/unified field theory.webp b/img/unified field theory.webp new file mode 100644 index 0000000..43230ce Binary files /dev/null and b/img/unified field theory.webp differ diff --git a/img/vacuum bomb.webp b/img/vacuum bomb.webp new file mode 100644 index 0000000..50dc56c Binary files /dev/null and b/img/vacuum bomb.webp differ diff --git a/img/vacuum fluctuation.webp b/img/vacuum fluctuation.webp new file mode 100644 index 0000000..c712652 Binary files /dev/null and b/img/vacuum fluctuation.webp differ diff --git a/img/vacuum permittivity.webp b/img/vacuum permittivity.webp new file mode 100644 index 0000000..f81f900 Binary files /dev/null and b/img/vacuum permittivity.webp differ diff --git a/img/virtual particles.webp b/img/virtual particles.webp new file mode 100644 index 0000000..a02e99c Binary files /dev/null and b/img/virtual particles.webp differ diff --git a/img/waste heat recovery.webp b/img/waste heat recovery.webp new file mode 100644 index 0000000..e291aba Binary files /dev/null and b/img/waste heat recovery.webp differ diff --git a/img/water shielding.webp b/img/water shielding.webp new file mode 100644 index 0000000..3dc396e Binary files /dev/null and b/img/water shielding.webp differ diff --git a/img/weak anthropic principle.webp b/img/weak anthropic principle.webp new file mode 100644 index 0000000..c0ed499 Binary files /dev/null and b/img/weak anthropic principle.webp differ diff --git a/img/zero point energy.webp b/img/zero point energy.webp new file mode 100644 index 0000000..b538f77 Binary files /dev/null and b/img/zero point energy.webp differ diff --git a/img/zoospore vector.webp b/img/zoospore vector.webp new file mode 100644 index 0000000..8ea12a7 Binary files /dev/null and b/img/zoospore vector.webp differ diff --git a/img/Ψ(t) collapse.webp b/img/Ψ(t) collapse.webp new file mode 100644 index 0000000..4a99cf6 Binary files /dev/null and b/img/Ψ(t) collapse.webp differ diff --git a/index.html b/index.html index 887db96..7b27943 100644 --- a/index.html +++ b/index.html @@ -69,9 +69,13 @@
+ + +
+ @@ -126,6 +130,7 @@ + @@ -228,7 +233,7 @@ - Github hosts n-gon's 2.5MB source code.
It's written in JavaScript, CSS, and HTML and uses the matter.js 2-D physics library. + Github hosts n-gon's source code.
It's written in JavaScript, CSS, and HTML and uses the matter.js 2-D physics library. Images are generated mostly through midJourney. diff --git a/js/bullet.js b/js/bullet.js index ae671f7..9e5d1ac 100644 --- a/js/bullet.js +++ b/js/bullet.js @@ -547,7 +547,7 @@ const b = { y: where.y + range * Math.sin(angle) } ]; - const vertexCollision = function(v1, v1End, domain) { + const vertexCollision = function (v1, v1End, domain) { for (let i = 0; i < domain.length; ++i) { let vertices = domain[i].vertices; const len = vertices.length - 1; @@ -596,24 +596,24 @@ const b = { v1: null, v2: null }; - if (tech.isPulseAim && !input.down) { //find mobs in line of sight - let dist = 2200 - for (let i = 0, len = mob.length; i < len; i++) { - const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position)) - if ( - explosionRadius < newDist && - newDist < dist && - !mob[i].isBadTarget && - Matter.Query.ray(map, path[0], mob[i].position).length === 0 && - Matter.Query.ray(body, path[0], mob[i].position).length === 0 && - !mob[i].isInvulnerable - ) { - dist = newDist - best.who = mob[i] - path[path.length - 1] = mob[i].position - } - } - } + // if (tech.isPulseAim && !input.down) { //find mobs in line of sight + // let dist = 2200 + // for (let i = 0, len = mob.length; i < len; i++) { + // const newDist = Vector.magnitude(Vector.sub(path[0], mob[i].position)) + // if ( + // explosionRadius < newDist && + // newDist < dist && + // !mob[i].isBadTarget && + // Matter.Query.ray(map, path[0], mob[i].position).length === 0 && + // Matter.Query.ray(body, path[0], mob[i].position).length === 0 && + // !mob[i].isInvulnerable + // ) { + // dist = newDist + // best.who = mob[i] + // path[path.length - 1] = mob[i].position + // } + // } + // } if (!best.who) { vertexCollision(path[0], path[1], mob); vertexCollision(path[0], path[1], map); @@ -628,8 +628,14 @@ const b = { if (best.who) { b.explosion(path[1], explosionRadius) const off = explosionRadius * 1.2 - b.explosion({ x: path[1].x + off * (Math.random() - 0.5), y: path[1].y + off * (Math.random() - 0.5) }, explosionRadius) - b.explosion({ x: path[1].x + off * (Math.random() - 0.5), y: path[1].y + off * (Math.random() - 0.5) }, explosionRadius) + b.explosion({ + x: path[1].x + off * (Math.random() - 0.5), + y: path[1].y + off * (Math.random() - 0.5) + }, explosionRadius) + b.explosion({ + x: path[1].x + off * (Math.random() - 0.5), + y: path[1].y + off * (Math.random() - 0.5) + }, explosionRadius) } //draw laser beam ctx.beginPath(); @@ -779,11 +785,16 @@ const b = { fireworks(where, size) { //can occur after grenades detonate const cycle = () => { if (m.alive) { - if (simulation.paused || m.isBodiesAsleep) { requestAnimationFrame(cycle) } else { + if (simulation.paused || m.isBodiesAsleep) { + requestAnimationFrame(cycle) + } else { count++ if (count < 110) requestAnimationFrame(cycle); if (!(count % 10)) { - const unit = Vector.rotate({ x: 1, y: 0 }, 6.28 * Math.random()) + const unit = Vector.rotate({ + x: 1, + y: 0 + }, 6.28 * Math.random()) b.explosion(Vector.add(where, Vector.mult(unit, size * (count * 0.01 + 0.02 * Math.random()))), size * (0.4 + Math.random() * 0.35), `hsla(${360*Math.random()},100%,66%,0.6)`); //makes bullet do explosive damage at end } } @@ -796,11 +807,16 @@ const b = { const color = `hsla(${360*Math.random()},100%,66%,0.6)` const cycle = () => { if (m.alive) { - if (simulation.paused || m.isBodiesAsleep) { requestAnimationFrame(cycle) } else { + if (simulation.paused || m.isBodiesAsleep) { + requestAnimationFrame(cycle) + } else { count++ if (count < 21) requestAnimationFrame(cycle); if (count % 2) { - const unit = Vector.rotate({ x: 1, y: 0 }, curl * 6.28 * count / 18 + off) + const unit = Vector.rotate({ + x: 1, + y: 0 + }, curl * 6.28 * count / 18 + off) b.explosion(Vector.add(where, Vector.mult(unit, size * 0.75)), size * 0.7, color); //makes bullet do explosive damage at end } } @@ -816,7 +832,9 @@ const b = { const range = size * Math.sqrt(b.explosionRange()) const cycle = () => { if (m.alive) { - if (simulation.paused || m.isBodiesAsleep) { requestAnimationFrame(cycle) } else { + if (simulation.paused || m.isBodiesAsleep) { + requestAnimationFrame(cycle) + } else { if (count < 30 && m.alive) requestAnimationFrame(cycle); if (count === 0) { const color = `hsla(${360*Math.random()},100%,66%,0.6)` @@ -825,14 +843,20 @@ const b = { if (count === 8) { const color = `hsla(${360*Math.random()},100%,66%,0.6)` for (let i = 0, len = 6; i < len; i++) { - const unit = Vector.rotate({ x: 1, y: 0 }, 6.28 * i / len) + const unit = Vector.rotate({ + x: 1, + y: 0 + }, 6.28 * i / len) b.explosion(Vector.add(where, Vector.mult(unit, 1.1 * range)), size * 0.6, color); //makes bullet do explosive damage at end } } if (count === 16) { const color = `hsla(${360*Math.random()},100%,66%,0.6)` for (let i = 0, len = 10; i < len; i++) { - const unit = Vector.rotate({ x: 1, y: 0 }, 6.28 * i / len) + const unit = Vector.rotate({ + x: 1, + y: 0 + }, 6.28 * i / len) b.explosion(Vector.add(where, Vector.mult(unit, 1.4 * range)), size * 0.45, color); //makes bullet do explosive damage at end } } @@ -859,14 +883,17 @@ const b = { }, setGrenadeMode() { - grenadeDefault = function(where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, angle = m.angle, size = 1) { + grenadeDefault = function (where = { + x: m.pos.x + 30 * Math.cos(m.angle), + y: m.pos.y + 30 * Math.sin(m.angle) + }, angle = m.angle, size = 1) { const me = bullet.length; bullet[me] = Bodies.circle(where.x, where.y, 15, b.fireAttributes(angle, false)); Matter.Body.setDensity(bullet[me], 0.0003); bullet[me].explodeRad = 300 * size + 100 * tech.isBlockExplode; bullet[me].onEnd = b.grenadeEnd bullet[me].minDmgSpeed = 1; - bullet[me].beforeDmg = function() { + bullet[me].beforeDmg = function () { this.endCycle = 0; //bullet ends cycle after doing damage //this also triggers explosion }; speed = input.down ? 43 : 32 @@ -876,19 +903,22 @@ const b = { }); bullet[me].endCycle = simulation.cycle + Math.floor(input.down ? 120 : 80) * tech.isBulletsLastLonger; bullet[me].restitution = 0.4; - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0025; //extra gravity for harder arcs }; Composite.add(engine.world, bullet[me]); //add bullet to world } - grenadeRPG = function(where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, angle = m.angle, size = 1) { + grenadeRPG = function (where = { + x: m.pos.x + 30 * Math.cos(m.angle), + y: m.pos.y + 30 * Math.sin(m.angle) + }, angle = m.angle, size = 1) { const me = bullet.length; bullet[me] = Bodies.circle(where.x, where.y, 15, b.fireAttributes(angle, false)); Matter.Body.setDensity(bullet[me], 0.0003); bullet[me].explodeRad = 300 * size + 100 * tech.isBlockExplode; bullet[me].onEnd = b.grenadeEnd bullet[me].minDmgSpeed = 1; - bullet[me].beforeDmg = function() { + bullet[me].beforeDmg = function () { this.endCycle = 0; //bullet ends cycle after doing damage //this also triggers explosion }; speed = input.down ? 46 : 32 @@ -905,7 +935,7 @@ const b = { x: bullet[me].mass * MAG * Math.cos(angle), y: bullet[me].mass * MAG * Math.sin(angle) } - bullet[me].do = function() { + bullet[me].do = function () { this.force.x += this.thrust.x; this.force.y += this.thrust.y; if (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length) { @@ -913,14 +943,17 @@ const b = { } }; } - grenadeRPGVacuum = function(where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, angle = m.angle, size = 1) { + grenadeRPGVacuum = function (where = { + x: m.pos.x + 30 * Math.cos(m.angle), + y: m.pos.y + 30 * Math.sin(m.angle) + }, angle = m.angle, size = 1) { const me = bullet.length; bullet[me] = Bodies.circle(where.x, where.y, 15, b.fireAttributes(angle, false)); Matter.Body.setDensity(bullet[me], 0.0003); bullet[me].explodeRad = 350 * size + Math.floor(Math.random() * 50) + tech.isBlockExplode * 100 bullet[me].onEnd = b.grenadeEnd bullet[me].minDmgSpeed = 1; - bullet[me].beforeDmg = function() { + bullet[me].beforeDmg = function () { this.endCycle = 0; //bullet ends cycle after doing damage //this also triggers explosion }; speed = input.down ? 46 : 32 @@ -937,7 +970,7 @@ const b = { x: bullet[me].mass * MAG * Math.cos(angle), y: bullet[me].mass * MAG * Math.sin(angle) } - bullet[me].suck = function() { + bullet[me].suck = function () { const suck = (who, radius = this.explodeRad * 3.2) => { for (i = 0, len = who.length; i < len; i++) { const sub = Vector.sub(this.position, who[i].position); @@ -966,7 +999,10 @@ const b = { suck([player], this.explodeRad * 1.3) } - Matter.Body.setVelocity(this, { x: 0, y: 0 }); //keep bomb in place + Matter.Body.setVelocity(this, { + x: 0, + y: 0 + }); //keep bomb in place //draw suck const radius = 2.75 * this.explodeRad * (this.endCycle - simulation.cycle) / this.suckCycles ctx.fillStyle = "rgba(0,0,0,0.1)"; @@ -974,7 +1010,7 @@ const b = { ctx.arc(this.position.x, this.position.y, radius, 0, 2 * Math.PI); ctx.fill(); } - bullet[me].do = function() { + bullet[me].do = function () { if (simulation.cycle > this.endCycle - this.suckCycles) { //suck this.do = this.suck } else if (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length) { @@ -986,17 +1022,20 @@ const b = { } }; } - grenadeVacuum = function(where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, angle = m.angle, size = 1) { + grenadeVacuum = function (where = { + x: m.pos.x + 30 * Math.cos(m.angle), + y: m.pos.y + 30 * Math.sin(m.angle) + }, angle = m.angle, size = 1) { const me = bullet.length; bullet[me] = Bodies.circle(where.x, where.y, 20, b.fireAttributes(angle, false)); Matter.Body.setDensity(bullet[me], 0.0002); bullet[me].explodeRad = 350 * size + Math.floor(Math.random() * 50) + tech.isBlockExplode * 100 bullet[me].onEnd = b.grenadeEnd - bullet[me].beforeDmg = function() { + bullet[me].beforeDmg = function () { this.endCycle = 0; //bullet ends cycle after doing damage //this also triggers explosion }; bullet[me].restitution = 0.4; - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0025; //extra gravity for harder arcs const suckCycles = 40 @@ -1058,7 +1097,10 @@ const b = { Composite.add(engine.world, bullet[me]); //add bullet to world } - grenadeNeutron = function(where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }, angle = m.angle, size = 1) { + grenadeNeutron = function (where = { + x: m.pos.x + 30 * Math.cos(m.angle), + y: m.pos.y + 30 * Math.sin(m.angle) + }, angle = m.angle, size = 1) { const me = bullet.length; bullet[me] = Bodies.polygon(where.x, where.y, 10, 4, b.fireAttributes(angle, false)); b.fireProps((input.down ? 45 : 25) / Math.pow(0.92, tech.missileCount), input.down ? 35 : 20, angle, me); //cd , speed @@ -1090,13 +1132,19 @@ const b = { } } - bullet[me].beforeDmg = function() {}; - bullet[me].stuck = function() {}; - bullet[me].do = function() { + bullet[me].beforeDmg = function () {}; + bullet[me].stuck = function () {}; + bullet[me].do = function () { const onCollide = () => { this.collisionFilter.mask = 0; //non collide with everything - Matter.Body.setVelocity(this, { x: 0, y: 0 }); - if (tech.isRPG) this.thrust = { x: 0, y: 0 } + Matter.Body.setVelocity(this, { + x: 0, + y: 0 + }); + if (tech.isRPG) this.thrust = { + x: 0, + y: 0 + } this.do = this.radiationMode; } const mobCollisions = Matter.Query.collides(this, mob) @@ -1113,14 +1161,14 @@ const b = { //find the relative position for when the mob is at angle zero by undoing the mobs rotation this.stuckToRelativePosition = Vector.rotate(Vector.sub(this.position, this.stuckTo.position), -this.stuckTo.angle) } - this.stuck = function() { + this.stuck = function () { if (this.stuckTo && this.stuckTo.alive) { const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position)) Matter.Body.setVelocity(this, this.stuckTo.velocity); //so that it will move properly if it gets unstuck } else { this.collisionFilter.mask = cat.map | cat.body | cat.player | cat.mob; //non collide with everything but map - this.stuck = function() { + this.stuck = function () { this.force.y += this.mass * 0.001; } } @@ -1136,7 +1184,7 @@ const b = { } else { this.do = this.radiationMode; } - this.stuck = function() { + this.stuck = function () { if (this.stuckTo) { const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position)) @@ -1157,7 +1205,7 @@ const b = { } } } - bullet[me].radiationMode = function() { //the do code after the bullet is stuck on something, projects a damaging radiation field + bullet[me].radiationMode = function () { //the do code after the bullet is stuck on something, projects a damaging radiation field this.stuck(); //runs different code based on what the bullet is stuck to this.damageRadius = this.damageRadius * 0.85 + 0.15 * this.maxDamageRadius //smooth radius towards max this.maxDamageRadius -= this.radiusDecay @@ -1219,14 +1267,17 @@ const b = { if (tech.isNeutronBomb) { b.grenade = grenadeNeutron if (tech.isRPG) { - b.guns[5].do = function() {} + b.guns[5].do = function () {} } else { - b.guns[5].do = function() { + b.guns[5].do = function () { if (!input.field && input.down) { const cycles = 80 const speed = input.down ? 35 : 20 //input.down ? 43 : 32 const g = input.down ? 0.137 : 0.135 - const v = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) } + const v = { + x: speed * Math.cos(m.angle), + y: speed * Math.sin(m.angle) + } ctx.strokeStyle = "rgba(68, 68, 68, 0.2)" //color.map ctx.lineWidth = 2 ctx.beginPath() @@ -1239,7 +1290,7 @@ const b = { } } } else if (tech.isRPG) { - b.guns[5].do = function() {} + b.guns[5].do = function () {} if (tech.isVacuumBomb) { b.grenade = grenadeRPGVacuum } else { @@ -1247,11 +1298,14 @@ const b = { } } else if (tech.isVacuumBomb) { b.grenade = grenadeVacuum - b.guns[5].do = function() { + b.guns[5].do = function () { if (!input.field && input.down) { const cycles = Math.floor(input.down ? 50 : 30) //30 const speed = input.down ? 44 : 35 - const v = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) } + const v = { + x: speed * Math.cos(m.angle), + y: speed * Math.sin(m.angle) + } ctx.strokeStyle = "rgba(68, 68, 68, 0.2)" //color.map ctx.lineWidth = 2 ctx.beginPath() @@ -1264,11 +1318,14 @@ const b = { } } else { b.grenade = grenadeDefault - b.guns[5].do = function() { + b.guns[5].do = function () { if (!input.field && input.down) { const cycles = Math.floor(input.down ? 120 : 80) //30 const speed = input.down ? 43 : 32 - const v = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) } //m.Vy / 2 + removed to make the path less jerky + const v = { + x: speed * Math.cos(m.angle), + y: speed * Math.sin(m.angle) + } //m.Vy / 2 + removed to make the path less jerky ctx.strokeStyle = "rgba(68, 68, 68, 0.2)" //color.map ctx.lineWidth = 2 ctx.beginPath() @@ -1426,7 +1483,32 @@ const b = { grapple(where, angle = m.angle, harpoonSize = 1) { const me = bullet.length; const returnRadius = 100 * Math.sqrt(harpoonSize) - bullet[me] = Bodies.fromVertices(where.x, where.y, [{ x: -50 * harpoonSize, y: 2 * harpoonSize, index: 0, isInternal: false }, { x: -50 * harpoonSize, y: -2 * harpoonSize, index: 1, isInternal: false }, { x: 45 * harpoonSize, y: -3 * harpoonSize, index: 2, isInternal: false }, { x: 50 * harpoonSize, y: 0, index: 3, isInternal: false }, { x: 45 * harpoonSize, y: 3 * harpoonSize, index: 4, isInternal: false }], { + bullet[me] = Bodies.fromVertices(where.x, where.y, [{ + x: -50 * harpoonSize, + y: 2 * harpoonSize, + index: 0, + isInternal: false + }, { + x: -50 * harpoonSize, + y: -2 * harpoonSize, + index: 1, + isInternal: false + }, { + x: 45 * harpoonSize, + y: -3 * harpoonSize, + index: 2, + isInternal: false + }, { + x: 50 * harpoonSize, + y: 0, + index: 3, + isInternal: false + }, { + x: 45 * harpoonSize, + y: 3 * harpoonSize, + index: 4, + isInternal: false + }], { angle: angle, friction: 1, frictionAir: 0.4, @@ -1441,21 +1523,27 @@ const b = { minDmgSpeed: 4, lookFrequency: Math.floor(7 + Math.random() * 3), density: tech.harpoonDensity, //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed - drain: tech.isRailEnergy ? 0.001 : 0.006, + drain: tech.isRailEnergy ? 0.0006 : 0.006, beforeDmg(who) { if (tech.isShieldPierce && who.isShielded) { //disable shields who.isShielded = false - requestAnimationFrame(() => { who.isShielded = true }); + requestAnimationFrame(() => { + who.isShielded = true + }); } if (tech.fragments) { b.targetedNail(this.vertices[2], tech.fragments * Math.floor(2 + Math.random())) } if (tech.isFoamBall) { - const radius = 5 + 8 * Math.random() - const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 } - for (let i = 0, len = 2 * this.mass; i < len; i++) { + for (let i = 0, len = 4 * this.mass; i < len; i++) { + const radius = 5 + 8 * Math.random() + const velocity = { + x: Math.max(0.5, 2 - radius * 0.1), + y: 0 + } b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) } + // this.endCycle = 0; } }, caughtPowerUp: null, @@ -1517,11 +1605,11 @@ const b = { returnToPlayer() { if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius) { //near player this.endCycle = 0; - if (m.energy < 0.05) { - m.fireCDcycle = m.cycle + 120; //fire cooldown - } else if (m.cycle + 25 * b.fireCDscale < m.fireCDcycle) { - m.fireCDcycle = m.cycle + 35 * b.fireCDscale //lower cd to 25 if it is above 25 - } + // if (m.energy < 0.05) { + // m.fireCDcycle = m.cycle + 120; //fire cooldown + // } else if (m.cycle + 15 * b.fireCDscale < m.fireCDcycle) { + // m.fireCDcycle = m.cycle + 15 * b.fireCDscale //lower cd to 25 if it is above 25 + // } if (m.energy < 0.05) this.dropCaughtPowerUp() @@ -1551,14 +1639,20 @@ const b = { grabPowerUp() { //grab power ups near the tip of the harpoon if (this.caughtPowerUp) { Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity)) - Matter.Body.setVelocity(this.caughtPowerUp, { x: 0, y: 0 }) + Matter.Body.setVelocity(this.caughtPowerUp, { + x: 0, + y: 0 + }) } else { //&& simulation.cycle % 2 for (let i = 0, len = powerUp.length; i < len; ++i) { const radius = powerUp[i].circleRadius + 50 if (Vector.magnitudeSquared(Vector.sub(this.vertices[2], powerUp[i].position)) < radius * radius) { if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) { this.caughtPowerUp = powerUp[i] - Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 }) + Matter.Body.setVelocity(powerUp[i], { + x: 0, + y: 0 + }) Matter.Body.setPosition(powerUp[i], this.vertices[2]) powerUp[i].collisionFilter.category = 0 powerUp[i].collisionFilter.mask = 0 @@ -1575,7 +1669,7 @@ const b = { this.grabPowerUp() if (this.endCycle < simulation.cycle + 1) { //if at end of lifespan, but player is holding down fire, force retraction this.endCycle = simulation.cycle + 60 - m.fireCDcycle = m.cycle + 120 // cool down + // m.fireCDcycle = m.cycle + 120 // cool down this.do = this.returnToPlayer Matter.Body.setDensity(this, 0.0005); //reduce density on return if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1) @@ -1607,9 +1701,15 @@ const b = { } //grappling hook if (input.fire && Matter.Query.collides(this, map).length) { - Matter.Body.setPosition(this, Vector.add(this.position, { x: 20 * Math.cos(this.angle), y: 20 * Math.sin(this.angle) })) + Matter.Body.setPosition(this, Vector.add(this.position, { + x: 20 * Math.cos(this.angle), + y: 20 * Math.sin(this.angle) + })) if (Matter.Query.collides(this, map).length) { - Matter.Body.setVelocity(this, { x: 0, y: 0 }); + Matter.Body.setVelocity(this, { + x: 0, + y: 0 + }); Matter.Sleeping.set(this, true) this.endCycle = simulation.cycle + 5 this.dropCaughtPowerUp() @@ -1621,14 +1721,18 @@ const b = { }) let dist = Vector.magnitude(sub) if (input.fire) { - m.fireCDcycle = m.cycle + 30; // cool down if out of energy + // m.fireCDcycle = m.cycle + 30; // cool down if out of energy + m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05) this.endCycle = simulation.cycle + 10 if (input.down) { //down dist = 0 player.force.y += 5 * player.mass * simulation.g; } if (m.energy > this.drain) { - Matter.Body.setVelocity(player, { x: player.velocity.x * 0.8, y: player.velocity.y * 0.8 }); + Matter.Body.setVelocity(player, { + x: player.velocity.x * 0.8, + y: player.velocity.y * 0.8 + }); const pull = Vector.mult(Vector.normalise(sub), 0.0008 * Math.min(Math.max(15, dist), 200)) player.force.x += pull.x player.force.y += pull.y @@ -1691,19 +1795,39 @@ const b = { harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true, thrust = 0.1) { const me = bullet.length; const returnRadius = 100 * Math.sqrt(harpoonSize) - bullet[me] = Bodies.fromVertices(where.x, where.y, [{ x: -40 * harpoonSize, y: 2 * harpoonSize, index: 0, isInternal: false }, { x: -40 * harpoonSize, y: -2 * harpoonSize, index: 1, isInternal: false }, { x: 50 * harpoonSize, y: -3 * harpoonSize, index: 3, isInternal: false }, { x: 30 * harpoonSize, y: 2 * harpoonSize, index: 4, isInternal: false }], { + bullet[me] = Bodies.fromVertices(where.x, where.y, [{ + x: -40 * harpoonSize, + y: 2 * harpoonSize, + index: 0, + isInternal: false + }, { + x: -40 * harpoonSize, + y: -2 * harpoonSize, + index: 1, + isInternal: false + }, { + x: 50 * harpoonSize, + y: -3 * harpoonSize, + index: 3, + isInternal: false + }, { + x: 30 * harpoonSize, + y: 2 * harpoonSize, + index: 4, + isInternal: false + }], { cycle: 0, angle: angle, friction: 1, frictionAir: 0.4, // thrustMag: 0.1, - drain: tech.isRailEnergy ? 0.001 : 0.006, + drain: tech.isRailEnergy ? 0.0006 : 0.006, turnRate: isReturn ? 0.1 : 0.03, //0.015 drawStringControlMagnitude: 3000 + 5000 * Math.random(), drawStringFlip: (Math.round(Math.random()) ? 1 : -1), dmg: 6, //damage done in addition to the damage from momentum classType: "bullet", - endCycle: simulation.cycle + totalCycles * 2.5 + 15, + endCycle: simulation.cycle + totalCycles * 2.5 + 40, collisionFilter: { category: cat.bullet, mask: tech.isShieldPierce ? cat.map | cat.body | cat.mob | cat.mobBullet : cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield, @@ -1714,7 +1838,9 @@ const b = { beforeDmg(who) { if (tech.isShieldPierce && who.isShielded) { //disable shields who.isShielded = false - requestAnimationFrame(() => { who.isShielded = true }); + requestAnimationFrame(() => { + who.isShielded = true + }); } if (tech.fragments) { b.targetedNail(this.vertices[2], tech.fragments * Math.floor(2 + Math.random())) @@ -1733,11 +1859,15 @@ const b = { } if (tech.isFoamBall) { - const radius = 5 + 8 * Math.random() - const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 } - for (let i = 0, len = 2 * this.mass; i < len; i++) { + for (let i = 0, len = 4 * this.mass; i < len; i++) { + const radius = 5 + 8 * Math.random() + const velocity = { + x: Math.max(0.5, 2 - radius * 0.1), + y: 0 + } b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) } + // this.endCycle = 0; } }, caughtPowerUp: null, @@ -1805,11 +1935,11 @@ const b = { returnToPlayer() { if (Vector.magnitude(Vector.sub(this.position, m.pos)) < returnRadius) { //near player this.endCycle = 0; - if (m.energy < 0.05) { - m.fireCDcycle = m.cycle + 120; //fire cooldown - } else if (m.cycle + 25 * b.fireCDscale < m.fireCDcycle) { - m.fireCDcycle = m.cycle + 25 * b.fireCDscale //lower cd to 25 if it is above 25 - } + // if (m.energy < 0.05) { + // m.fireCDcycle = m.cycle + 80 * b.fireCDscale; //fire cooldown is much longer when out of energy + // } else if (m.cycle + 20 * b.fireCDscale < m.fireCDcycle) { + // if (m.energy > 0.05) m.fireCDcycle = m.cycle + 20 * b.fireCDscale //lower cd to 25 if it is above 25 + // } //recoil on catching const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (input.down ? 0.0001 : 0.0002)) player.force.x += momentum.x @@ -1825,12 +1955,17 @@ const b = { } } } else { - if (m.energy > this.drain) m.energy -= this.drain const sub = Vector.sub(this.position, m.pos) const rangeScale = 1 + 0.000001 * Vector.magnitude(sub) * Vector.magnitude(sub) //return faster when far from player const returnForce = Vector.mult(Vector.normalise(sub), rangeScale * thrust * this.mass) - this.force.x -= returnForce.x - this.force.y -= returnForce.y + if (m.energy > this.drain) m.energy -= this.drain + if (m.energy < 0.05) { + this.force.x -= returnForce.x * 0.15 + this.force.y -= returnForce.y * 0.15 + } else { //if (m.cycle + 20 * b.fireCDscale < m.fireCDcycle) + this.force.x -= returnForce.x + this.force.y -= returnForce.y + } this.grabPowerUp() } this.draw(); @@ -1838,7 +1973,10 @@ const b = { grabPowerUp() { //grab power ups near the tip of the harpoon if (this.caughtPowerUp) { Matter.Body.setPosition(this.caughtPowerUp, Vector.add(this.vertices[2], this.velocity)) - Matter.Body.setVelocity(this.caughtPowerUp, { x: 0, y: 0 }) + Matter.Body.setVelocity(this.caughtPowerUp, { + x: 0, + y: 0 + }) } else { //&& simulation.cycle % 2 for (let i = 0, len = powerUp.length; i < len; ++i) { const radius = powerUp[i].circleRadius + 50 @@ -1846,7 +1984,10 @@ const b = { if (powerUp[i].name !== "heal" || m.health !== m.maxHealth || tech.isOverHeal) { powerUp[i].isGrabbed = true this.caughtPowerUp = powerUp[i] - Matter.Body.setVelocity(powerUp[i], { x: 0, y: 0 }) + Matter.Body.setVelocity(powerUp[i], { + x: 0, + y: 0 + }) Matter.Body.setPosition(powerUp[i], this.vertices[2]) powerUp[i].collisionFilter.category = 0 powerUp[i].collisionFilter.mask = 0 @@ -1862,11 +2003,11 @@ const b = { this.cycle++ if (isReturn || target) { if (isReturn) { - if (this.cycle > totalCycles || m.energy < 0.05 || !input.fire) { //return to player + if (this.cycle > totalCycles) { //return to player //|| !input.fire this.do = this.returnToPlayer if (this.angularSpeed < 0.5) this.torque += this.inertia * 0.001 * (Math.random() - 0.5) //(Math.round(Math.random()) ? 1 : -1) Matter.Sleeping.set(this, false) - this.endCycle = simulation.cycle + 60 + this.endCycle = simulation.cycle + 240 const momentum = Vector.mult(Vector.sub(this.velocity, player.velocity), (input.down ? 0.00015 : 0.0003)) //recoil on jerking line player.force.x += momentum.x player.force.y += momentum.y @@ -1879,7 +2020,10 @@ const b = { } } if (target) { //rotate towards the target - const face = { x: Math.cos(this.angle), y: Math.sin(this.angle) }; + const face = { + x: Math.cos(this.angle), + y: Math.sin(this.angle) + }; const vectorGoal = Vector.normalise(Vector.sub(this.position, target.position)); if (Vector.cross(vectorGoal, face) > 0) { Matter.Body.rotate(this, this.turnRate); @@ -1899,24 +2043,24 @@ const b = { y: m.Vy / 2 + 600 * thrust * Math.sin(bullet[me].angle) }); bullet[me].frictionAir = 0.002 - bullet[me].do = function() { + bullet[me].do = function () { if (this.speed < 20) this.force.y += 0.0005 * this.mass; this.draw(); } } if (tech.isHarpoonPowerUp && bullet[me].density > 0.01) { if (isReturn) { - bullet[me].draw = function() { + bullet[me].draw = function () { this.drawToggleHarpoon() this.drawString() } } else { - bullet[me].draw = function() { + bullet[me].draw = function () { this.drawToggleHarpoon() } } } else if (isReturn) { - bullet[me].draw = function() { + bullet[me].draw = function () { this.drawString() } } @@ -2063,7 +2207,9 @@ const b = { if (this.endCycle < simulation.cycle + 1) this.isWave = false if (Matter.Query.point(map, this.position).length) { //check if inside map //|| Matter.Query.point(body, this.position).length this.isBranch = true; - this.do = () => { if (this.endCycle < simulation.cycle + 1) this.isWave = false } + this.do = () => { + if (this.endCycle < simulation.cycle + 1) this.isWave = false + } } else { //check if inside a mob for (let i = 0, len = mob.length; i < len; i++) { const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)) @@ -2071,9 +2217,15 @@ const b = { if (dist < radius * radius) { if (mob[i].speed > 2) { if (mob[i].isBoss || mob[i].isShielded) { - Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.95, y: mob[i].velocity.y * 0.95 }); + Matter.Body.setVelocity(mob[i], { + x: mob[i].velocity.x * 0.95, + y: mob[i].velocity.y * 0.95 + }); } else { - Matter.Body.setVelocity(mob[i], { x: mob[i].velocity.x * 0.25, y: mob[i].velocity.y * 0.25 }); + Matter.Body.setVelocity(mob[i], { + x: mob[i].velocity.x * 0.25, + y: mob[i].velocity.y * 0.25 + }); } } // Matter.Body.setPosition(this, Vector.add(this.position, mob[i].velocity)) //move with the medium @@ -2098,7 +2250,9 @@ const b = { const transverse = Vector.normalise(Vector.perp(bullet[me].velocity)) if (180 - Math.abs(Math.abs(b.lastAngle - m.angle) - 180) > 0.13 || !b.wasExtruderOn) { bullet[me].isBranch = true; //don't draw stroke for this bullet - bullet[me].do = function() { if (this.endCycle < simulation.cycle + 1) this.isWave = false } + bullet[me].do = function () { + if (this.endCycle < simulation.cycle + 1) this.isWave = false + } } b.lastAngle = m.angle //track last angle for the above angle difference calculation } else { @@ -2127,7 +2281,7 @@ const b = { y: m.pos.y + range * Math.sin(m.angle) } ]; - const vertexCollision = function(v1, v1End, domain) { + const vertexCollision = function (v1, v1End, domain) { for (let i = 0; i < domain.length; ++i) { let vertices = domain[i].vertices; const len = vertices.length - 1; @@ -2251,9 +2405,22 @@ const b = { }, dmg = tech.laserDamage, reflections = tech.laserReflections, isThickBeam = false, push = 1) { const reflectivity = 1 - 1 / (reflections * 3) let damage = m.dmgScale * dmg - let best = { x: 1, y: 1, dist2: Infinity, who: null, v1: 1, v2: 1 }; - const path = [{ x: where.x, y: where.y }, { x: whereEnd.x, y: whereEnd.y }]; - const vertexCollision = function(v1, v1End, domain) { + let best = { + x: 1, + y: 1, + dist2: Infinity, + who: null, + v1: 1, + v2: 1 + }; + const path = [{ + x: where.x, + y: where.y + }, { + x: whereEnd.x, + y: whereEnd.y + }]; + const vertexCollision = function (v1, v1End, domain) { for (let i = 0; i < domain.length; ++i) { let vertices = domain[i].vertices; const len = vertices.length - 1; @@ -2294,13 +2461,20 @@ const b = { } }; - const checkForCollisions = function() { - best = { x: 1, y: 1, dist2: Infinity, who: null, v1: 1, v2: 1 }; + const checkForCollisions = function () { + best = { + x: 1, + y: 1, + dist2: Infinity, + who: null, + v1: 1, + v2: 1 + }; vertexCollision(path[path.length - 2], path[path.length - 1], mob); vertexCollision(path[path.length - 2], path[path.length - 1], map); vertexCollision(path[path.length - 2], path[path.length - 1], body); }; - const laserHitMob = function() { + const laserHitMob = function () { if (best.who.alive) { best.who.locatePlayer(); if (best.who.damageReduction) { @@ -2329,18 +2503,24 @@ const b = { } if (tech.isLaserPush) { //push mobs away const index = path.length - 1 - Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 }); + Matter.Body.setVelocity(best.who, { + x: best.who.velocity.x * 0.97, + y: best.who.velocity.y * 0.97 + }); const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass)) Matter.Body.applyForce(best.who, path[index], force) } } else if (tech.isLaserPush && best.who.classType === "body") { const index = path.length - 1 - Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 }); + Matter.Body.setVelocity(best.who, { + x: best.who.velocity.x * 0.97, + y: best.who.velocity.y * 0.97 + }); const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass)) Matter.Body.applyForce(best.who, path[index], force) } }; - const reflection = function() { // https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector + const reflection = function () { // https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector const n = Vector.perp(Vector.normalise(Vector.sub(best.v1, best.v2))); const d = Vector.sub(path[path.length - 1], path[path.length - 2]); const nn = Vector.mult(n, 2 * Vector.dot(d, n)); @@ -2352,7 +2532,10 @@ const b = { let lastBestOdd let lastBestEven = best.who //used in hack below if (best.dist2 !== Infinity) { //if hitting something - path[path.length - 1] = { x: best.x, y: best.y }; + path[path.length - 1] = { + x: best.x, + y: best.y + }; laserHitMob(); for (let i = 0; i < reflections; i++) { reflection(); @@ -2360,7 +2543,10 @@ const b = { if (best.dist2 !== Infinity) { //if hitting something lastReflection = best - path[path.length - 1] = { x: best.x, y: best.y }; + path[path.length - 1] = { + x: best.x, + y: best.y + }; damage *= reflectivity laserHitMob(); //I'm not clear on how this works, but it gets rid of a bug where the laser reflects inside a block, often vertically. @@ -2436,7 +2622,10 @@ const b = { time: 15 }); }, - laserMine(position, velocity = { x: 0, y: -8 }) { + laserMine(position, velocity = { + x: 0, + y: -8 + }) { const me = bullet.length; bullet[me] = Bodies.polygon(position.x, position.y, 3, 25, { bulletType: "laser mine", @@ -2533,7 +2722,10 @@ const b = { if (tech.isFoamMine) { for (let i = 0; i < 14; i++) { const radius = 13 + 8 * Math.random() - const velocity = { x: 5.5 * Math.random(), y: 0 } + const velocity = { + x: 5.5 * Math.random(), + y: 0 + } b.foam(this.position, Vector.rotate(velocity, this.angle + 1.57 + 3 * (Math.random() - 0.5)), radius) //6.28 * Math.random() } @@ -2565,7 +2757,10 @@ const b = { b.foam(this.position, Vector.rotate(velocity, 0.2 * (Math.random() - 0.5)), radius) } else { const radius = 7 + 10 * Math.random() - const velocity = { x: 10 + 8 * Math.random(), y: 0 } + const velocity = { + x: 10 + 8 * Math.random(), + y: 0 + } b.foam(this.position, Vector.rotate(velocity, this.angle + 1.57 + 2.8 * (Math.random() - 0.5)), radius) //6.28 * Math.random() } } @@ -2584,18 +2779,27 @@ const b = { if (collide.length > 0) { for (let i = 0; i < collide.length; i++) { if (collide[i].bodyA.collisionFilter.category === cat.map) { // || collide[i].bodyB.collisionFilter.category === cat.map) { - const angle = Vector.angle(collide[i].normal, { x: 1, y: 0 }) + const angle = Vector.angle(collide[i].normal, { + x: 1, + y: 0 + }) Matter.Body.setAngle(this, Math.atan2(collide[i].tangent.y, collide[i].tangent.x)) //move until touching map again after rotation for (let j = 0; j < 10; j++) { if (Matter.Query.collides(this, map).length > 0) { //touching map if (angle > -0.2 || angle < -1.5) { //don't stick to level ground - Matter.Body.setVelocity(this, { x: 0, y: 0 }); + Matter.Body.setVelocity(this, { + x: 0, + y: 0 + }); Matter.Body.setStatic(this, true) //don't set to static if not touching map this.collisionFilter.category = 0 this.collisionFilter.mask = 0 //cat.map | cat.bullet } else { - Matter.Body.setVelocity(this, { x: 0, y: 0 }); + Matter.Body.setVelocity(this, { + x: 0, + y: 0 + }); Matter.Body.setAngularVelocity(this, 0) } this.arm(); @@ -2624,7 +2828,7 @@ const b = { arm() { this.collisionFilter.mask = cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield | cat.bullet //can now collide with other bullets this.lookFrequency = simulation.cycle + 60 - this.do = function() { //overwrite the do method for this bullet + this.do = function () { //overwrite the do method for this bullet this.force.y += this.mass * 0.002; //extra gravity if (simulation.cycle > this.lookFrequency) { this.isArmed = true @@ -2636,7 +2840,7 @@ const b = { color: "#f00", time: 4 }); - this.do = function() { //overwrite the do method for this bullet + this.do = function () { //overwrite the do method for this bullet this.force.y += this.mass * 0.002; //extra gravity if (!(simulation.cycle % this.lookFrequency)) { //find mob targets const random = 300 * Math.random() @@ -2651,7 +2855,7 @@ const b = { if (tech.isMineSentry) { this.lookFrequency = 6 this.endCycle = simulation.cycle + 1020 - this.do = function() { //overwrite the do method for this bullet + this.do = function () { //overwrite the do method for this bullet this.force.y += this.mass * 0.002; //extra gravity if (!(simulation.cycle % this.lookFrequency)) { //find mob targets this.endCycle -= 5 @@ -2698,7 +2902,7 @@ const b = { thrust: (tech.isSporeFollow ? 0.0012 : 0.00055) * (1 + 0.5 * (Math.random() - 0.5)), wormSize: wormSize, wormTail: 1 + Math.max(4, Math.min(wormSize - 2 * tech.wormSize, 30)), - dmg: (tech.isMutualism ? 8 : 3.2) * wormSize * (tech.isJunkDNA ? 1 + 0.53 * tech.junkCount : 1), //bonus damage from tech.isMutualism //2.5 is extra damage as worm + dmg: (tech.isMutualism ? 9.5 : 3.2) * wormSize * (tech.isJunkDNA ? 1 + 0.53 * tech.junkCount : 1), lookFrequency: 100 + Math.floor(37 * Math.random()), classType: "bullet", collisionFilter: { @@ -2729,7 +2933,7 @@ const b = { }, onEnd() { if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) { - m.health += 0.01 + m.health += 0.02 if (m.health > m.maxHealth) m.health = m.maxHealth; m.displayHealth(); } @@ -2794,8 +2998,8 @@ const b = { y: SPEED * Math.sin(ANGLE) }); Composite.add(engine.world, bullet[bIndex]); //add bullet to world - if (tech.isMutualism && m.health > 0.02) { - m.health -= 0.01 + if (tech.isMutualism && m.health > 0.04) { + m.health -= 0.02 m.displayHealth(); bullet[bIndex].isMutualismActive = true } @@ -2814,7 +3018,7 @@ const b = { friction: 0, frictionAir: 0.025, thrust: (tech.isSporeFollow ? 0.0011 : 0.0005) * (1 + 0.3 * (Math.random() - 0.5)), - dmg: (tech.isMutualism ? 16.8 : 7) * (tech.isJunkDNA ? 1 + 0.53 * tech.junkCount : 1), //bonus damage from tech.isMutualism + dmg: (tech.isMutualism ? 20 : 7) * (tech.isJunkDNA ? 1 + 0.53 * tech.junkCount : 1), //bonus damage from tech.isMutualism lookFrequency: 100 + Math.floor(117 * Math.random()), classType: "bullet", isSpore: true, @@ -2834,7 +3038,7 @@ const b = { }, onEnd() { if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) { - m.health += 0.005 + m.health += 0.01 if (m.health > m.maxHealth) m.health = m.maxHealth; m.displayHealth(); } @@ -2926,13 +3130,16 @@ const b = { Composite.add(engine.world, bullet[bIndex]); //add bullet to world if (tech.isMutualism && m.health > 0.01) { - m.health -= 0.005 + m.health -= 0.01 m.displayHealth(); bullet[bIndex].isMutualismActive = true } } }, - iceIX(speed = 0, dir = m.angle + Math.PI * 2 * Math.random(), where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }) { + iceIX(speed = 0, dir = m.angle + Math.PI * 2 * Math.random(), where = { + x: m.pos.x + 30 * Math.cos(m.angle), + y: m.pos.y + 30 * Math.sin(m.angle) + }) { const me = bullet.length; const THRUST = 0.0018 const RADIUS = 18 @@ -2956,7 +3163,9 @@ const b = { lockedOn: null, beforeDmg(who) { if (tech.iceEnergy && !who.shield && !who.isShielded && who.isDropPowerUp && who.alive && m.immuneCycle < m.cycle) { - setTimeout(() => { if (!who.alive) m.energy += tech.iceEnergy * 0.8 }, 10); + setTimeout(() => { + if (!who.alive) m.energy += tech.iceEnergy * 0.8 + }, 10); } mobs.statusSlow(who, tech.iceIXFreezeTime) this.endCycle = simulation.cycle @@ -3029,9 +3238,9 @@ const b = { lockedOn: null, delay: 50, cd: simulation.cycle + 10, - dmg: 0, //radius * (tech.isMutualism ? 2.5 : 1), + dmg: 0, setDamage() { //dmg is set to zero after doing damage once, and set back to normal after jumping - this.dmg = radius * (tech.isMutualism ? 2.5 : 1) * (tech.isJunkDNA ? 1 + 0.53 * tech.junkCount : 1) //damage done in addition to the damage from momentum //spores do 7 dmg, worms do 18 + this.dmg = radius * (tech.isMutualism ? 2.9 : 1) * (tech.isJunkDNA ? 1 + 0.53 * tech.junkCount : 1) //damage done in addition to the damage from momentum //spores do 7 dmg, worms do 18 }, beforeDmg(who) { Matter.Body.setVelocity(this, Vector.mult(Vector.normalise(Vector.sub(this.position, who.position)), 10 + 10 * Math.random())); //push away from target @@ -3044,17 +3253,22 @@ const b = { for (let i = 0; i < 2; i++) { //spawn 2 more const speed = 10 + 5 * Math.random() const angle = 2 * Math.PI * Math.random() - b.flea(this.position, { x: speed * Math.cos(angle), y: speed * Math.sin(angle) }) + b.flea(this.position, { + x: speed * Math.cos(angle), + y: speed * Math.sin(angle) + }) } } this.endCycle = 0; }, 1); } - setTimeout(() => { this.dmg = 0 }) + setTimeout(() => { + this.dmg = 0 + }) }, onEnd() { if (tech.isMutualism && this.isMutualismActive && !tech.isEnergyHealth) { - m.health += 0.01 + m.health += 0.02 if (m.health > m.maxHealth) m.health = m.maxHealth; m.displayHealth(); } @@ -3087,7 +3301,10 @@ const b = { if (tech.isSporeFollow && !this.lockedOn && Matter.Query.ray(map, this.position, m.pos).length === 0) { this.lockedOn = { //make target player if there are no mobs to target position: m.pos, - velocity: { x: 0, y: 0 } + velocity: { + x: 0, + y: 0 + } } } if (this.lockedOn) { //hop towards mob target @@ -3109,7 +3326,10 @@ const b = { } this.force.y = -(0.03 + 0.08 * Math.random()) * this.mass } - Matter.Body.setVelocity(this, { x: 0, y: 0 }); + Matter.Body.setVelocity(this, { + x: 0, + y: 0 + }); this.setDamage() //after jumping damage is no longer zero } } @@ -3117,12 +3337,15 @@ const b = { Composite.add(engine.world, bullet[me]); //add bullet to world Matter.Body.setVelocity(bullet[me], velocity); if (tech.isMutualism && m.health > 0.01) { - m.health -= 0.005 + m.health -= 0.01 m.displayHealth(); bullet[bullet.length - 1].isMutualismActive = true } }, - drone(where = { x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 20 * (Math.random() - 0.5) }, speed = 1) { + drone(where = { + x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5), + y: m.pos.y + 30 * Math.sin(m.angle) + 20 * (Math.random() - 0.5) + }, speed = 1) { const me = bullet.length; const THRUST = 0.0015 const dir = m.angle + 0.4 * (Math.random() - 0.5); @@ -3153,7 +3376,10 @@ const b = { b.explosion(this.position, max * 0.1 + this.isImproved * 110 + 60 * Math.random()); //makes bullet do explosive damage at end if (tech.isForeverDrones) { this.endCycle = 0 - b.drone({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5) + b.drone({ + x: m.pos.x + 30 * (Math.random() - 0.5), + y: m.pos.y + 30 * (Math.random() - 0.5) + }, 5) bullet[bullet.length - 1].endCycle = Infinity } else { this.endCycle -= max @@ -3176,7 +3402,10 @@ const b = { if (tech.isDroneRespawn && b.inventory.length) { const who = b.guns[b.activeGun] if (who.name === "drones" && who.ammo > 0 && mob.length) { - b.drone({ x: this.position.x, y: this.position.y }, 0) + b.drone({ + x: this.position.x, + y: this.position.y + }, 0) if (Math.random() < 0.2) { b.guns[b.activeGun].ammo--; simulation.updateGunHUD(); @@ -3327,7 +3556,10 @@ const b = { y: speed * Math.sin(dir) }); }, - droneRadioactive(where = { x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 20 * (Math.random() - 0.5) }, speed = 1) { + droneRadioactive(where = { + x: m.pos.x + 30 * Math.cos(m.angle) + 20 * (Math.random() - 0.5), + y: m.pos.y + 30 * Math.sin(m.angle) + 20 * (Math.random() - 0.5) + }, speed = 1) { const me = bullet.length; const THRUST = (tech.isFastDrones ? 0.003 : 0.0012) + 0.0005 * (Math.random() - 0.5) const dir = m.angle + 0.4 * (Math.random() - 0.5); @@ -3359,7 +3591,10 @@ const b = { if (tech.isDroneRespawn && b.inventory.length) { const who = b.guns[b.activeGun] if (who.name === "drones" && who.ammo > 0 && mob.length) { - b.droneRadioactive({ x: this.position.x, y: this.position.y }, 0) + b.droneRadioactive({ + x: this.position.x, + y: this.position.y + }, 0) if (Math.random() < 0.2) { b.guns[b.activeGun].ammo--; simulation.updateGunHUD(); @@ -3720,7 +3955,10 @@ const b = { if (!this.target && who.alive) { this.target = who; if (who.radius < 20) { - this.targetRelativePosition = { x: 0, y: 0 } //find relative position vector for zero mob rotation + this.targetRelativePosition = { + x: 0, + y: 0 + } //find relative position vector for zero mob rotation } else if (Matter.Query.collides(this, [who]).length > 0) { const normal = Matter.Query.collides(this, [who])[0].normal this.targetRelativePosition = Vector.rotate(Vector.sub(Vector.sub(this.position, who.position), Vector.mult(normal, -this.radius)), -who.angle) //find relative position vector for zero mob rotation @@ -3740,7 +3978,10 @@ const b = { } } this.targetVertex = bestVertex - Matter.Body.setVelocity(this, { x: 0, y: 0 }); + Matter.Body.setVelocity(this, { + x: 0, + y: 0 + }); } }, onEnd() {}, @@ -3854,7 +4095,10 @@ const b = { if (this.nextPortCycle < simulation.cycle) { //teleport around if you have tech.isBulletTeleport this.nextPortCycle = simulation.cycle + this.portFrequency const range = 13 * Math.sqrt(this.radius) * Math.random() - Matter.Body.setPosition(this, Vector.add(this.position, Vector.rotate({ x: range, y: 0 }, 2 * Math.PI * Math.random()))) + Matter.Body.setPosition(this, Vector.add(this.position, Vector.rotate({ + x: range, + y: 0 + }, 2 * Math.PI * Math.random()))) } } }); @@ -3956,7 +4200,7 @@ const b = { Composite.add(engine.world, bullet[me]); //add bullet to world bullet[me].endCycle = simulation.cycle + 60 + 18 * Math.random(); bullet[me].dmg = tech.isNailRadiation ? 0 : dmg - bullet[me].beforeDmg = function(who) { //beforeDmg is rewritten with ice crystal tech + bullet[me].beforeDmg = function (who) { //beforeDmg is rewritten with ice crystal tech if (tech.isNailRadiation) mobs.statusDoT(who, dmg * (tech.isFastRadiation ? 1.3 : 0.44), tech.isSlowRadiation ? 360 : (tech.isFastRadiation ? 60 : 180)) // one tick every 30 cycles if (tech.isNailCrit) { if (!who.shield && Vector.dot(Vector.normalise(Vector.sub(who.position, this.position)), Vector.normalise(this.velocity)) > 0.97 - 1 / who.radius) { @@ -3965,7 +4209,7 @@ const b = { } this.ricochet(who) }; - bullet[me].ricochet = function(who) { //use for normal nails, and ice crystal nails + bullet[me].ricochet = function (who) { //use for normal nails, and ice crystal nails if (tech.isRicochet) { const targets = [] //target nearby mobs for (let i = 0, len = mob.length; i < len; i++) { @@ -3990,7 +4234,7 @@ const b = { this.dmg += 2 } } - bullet[me].do = function() {}; + bullet[me].do = function () {}; }, needle(angle = m.angle) { const me = bullet.length; @@ -4004,7 +4248,7 @@ const b = { bullet[me].collisionFilter.mask = tech.isShieldPierce ? 0 : cat.mobShield // bullet[me].turnRate = 0.005 * (Math.random() - 0.5) bullet[me].isInMap = false - bullet[me].do = function() { + bullet[me].do = function () { const whom = Matter.Query.collides(this, mob) if (whom.length && this.speed > 20) { //if touching a mob for (let i = 0, len = whom.length; i < len; i++) { @@ -4062,7 +4306,7 @@ const b = { } else { bullet[me].endCycle = simulation.cycle + 100; bullet[me].collisionFilter.mask = tech.isShieldPierce ? cat.body : cat.body | cat.mobShield - bullet[me].do = function() { + bullet[me].do = function () { const whom = Matter.Query.collides(this, mob) if (whom.length && this.speed > 20) { //if touching a mob for (let i = 0, len = whom.length; i < len; i++) { @@ -4110,7 +4354,7 @@ const b = { x: 0, y: 0 }); - this.do = function() { + this.do = function () { if (!Matter.Query.collides(this, map).length) this.force.y += this.mass * 0.001; } if (tech.isNeedleIce) { @@ -4217,14 +4461,38 @@ const b = { tech.missileBotCount = 0 }, respawnBots() { - for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, false) - for (let i = 0; i < tech.laserBotCount; i++) b.laserBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, false) - for (let i = 0; i < tech.nailBotCount; i++) b.nailBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, false) - for (let i = 0; i < tech.foamBotCount; i++) b.foamBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, false) - for (let i = 0; i < tech.boomBotCount; i++) b.boomBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, false) - for (let i = 0; i < tech.orbitBotCount; i++) b.orbitBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, false) - for (let i = 0; i < tech.plasmaBotCount; i++) b.plasmaBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, false) - for (let i = 0; i < tech.missileBotCount; i++) b.missileBot({ x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, false) + for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot({ + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, false) + for (let i = 0; i < tech.laserBotCount; i++) b.laserBot({ + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, false) + for (let i = 0; i < tech.nailBotCount; i++) b.nailBot({ + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, false) + for (let i = 0; i < tech.foamBotCount; i++) b.foamBot({ + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, false) + for (let i = 0; i < tech.boomBotCount; i++) b.boomBot({ + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, false) + for (let i = 0; i < tech.orbitBotCount; i++) b.orbitBot({ + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, false) + for (let i = 0; i < tech.plasmaBotCount; i++) b.plasmaBot({ + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, false) + for (let i = 0; i < tech.missileBotCount; i++) b.missileBot({ + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, false) if (tech.isIntangible && m.isCloak) { for (let i = 0; i < bullet.length; i++) { if (bullet[i].botType) bullet[i].collisionFilter.mask = cat.map | cat.bullet | cat.mobBullet | cat.mobShield @@ -4403,13 +4671,19 @@ const b = { } } let history = m.history[(m.cycle - this.followDelay) % 600] - Matter.Body.setPosition(this, { x: history.position.x, y: history.position.y - history.yOff + 24.2859 }) //bullets move with player + Matter.Body.setPosition(this, { + x: history.position.x, + y: history.position.y - history.yOff + 24.2859 + }) //bullets move with player } }) Composite.add(engine.world, bullet[me]); //add bullet to world b.setDynamoBotDelay() }, - nailBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) { + nailBot(position = { + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, isConsole = true) { if (isConsole) simulation.makeTextLog(`b.nailBot()`); const me = bullet.length; const dir = m.angle; @@ -4474,7 +4748,10 @@ const b = { }) Composite.add(engine.world, bullet[me]); //add bullet to world }, - missileBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) { + missileBot(position = { + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, isConsole = true) { if (isConsole) simulation.makeTextLog(`b.missileBot()`); const me = bullet.length; bullet[me] = Bodies.rectangle(position.x, position.y, 28, 11, { @@ -4548,7 +4825,10 @@ const b = { }) Composite.add(engine.world, bullet[me]); //add bullet to world }, - foamBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) { + foamBot(position = { + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, isConsole = true) { if (isConsole) simulation.makeTextLog(`b.foamBot()`); const me = bullet.length; const dir = m.angle; @@ -4603,7 +4883,10 @@ const b = { }) Composite.add(engine.world, bullet[me]); //add bullet to world }, - laserBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) { + laserBot(position = { + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, isConsole = true) { if (isConsole) simulation.makeTextLog(`b.laserBot()`); const me = bullet.length; const dir = m.angle; @@ -4618,7 +4901,10 @@ const b = { restitution: 0.5 * (1 + 0.5 * Math.random()), acceleration: 0.0015 * (1 + 0.3 * Math.random()), playerRange: 140 + Math.floor(30 * Math.random()) + 2 * b.totalBots(), - offPlayer: { x: 0, y: 0, }, + offPlayer: { + x: 0, + y: 0, + }, dmg: 0, //damage done in addition to the damage from momentum minDmgSpeed: 2, lookFrequency: 20 + Math.floor(7 * Math.random()) - 13 * tech.isLaserBotUpgrade, @@ -4687,10 +4973,23 @@ const b = { const push = 0.4 const reflectivity = 1 - 1 / (tech.laserReflections * 3) let damage = m.dmgScale * this.laserDamage * tech.laserDamage - let best = { x: 1, y: 1, dist2: Infinity, who: null, v1: 1, v2: 1 }; - const path = [{ x: this.vertices[0].x, y: this.vertices[0].y }, { x: this.lockedOn.position.x, y: this.lockedOn.position.y }]; + let best = { + x: 1, + y: 1, + dist2: Infinity, + who: null, + v1: 1, + v2: 1 + }; + const path = [{ + x: this.vertices[0].x, + y: this.vertices[0].y + }, { + x: this.lockedOn.position.x, + y: this.lockedOn.position.y + }]; - const vertexCollision = function(v1, v1End, domain) { + const vertexCollision = function (v1, v1End, domain) { for (let i = 0; i < domain.length; ++i) { let vertices = domain[i].vertices; const len = vertices.length - 1; @@ -4731,13 +5030,20 @@ const b = { } }; - const checkForCollisions = function() { - best = { x: 1, y: 1, dist2: Infinity, who: null, v1: 1, v2: 1 }; + const checkForCollisions = function () { + best = { + x: 1, + y: 1, + dist2: Infinity, + who: null, + v1: 1, + v2: 1 + }; vertexCollision(path[path.length - 2], path[path.length - 1], mob); vertexCollision(path[path.length - 2], path[path.length - 1], map); vertexCollision(path[path.length - 2], path[path.length - 1], body); }; - const laserHitMob = function() { + const laserHitMob = function () { if (best.who.alive) { best.who.locatePlayer(); if (best.who.damageReduction) { @@ -4766,18 +5072,24 @@ const b = { } if (tech.isLaserPush) { //push mobs away const index = path.length - 1 - Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 }); + Matter.Body.setVelocity(best.who, { + x: best.who.velocity.x * 0.97, + y: best.who.velocity.y * 0.97 + }); const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass)) Matter.Body.applyForce(best.who, path[index], force) } } else if (tech.isLaserPush && best.who.classType === "body") { const index = path.length - 1 - Matter.Body.setVelocity(best.who, { x: best.who.velocity.x * 0.97, y: best.who.velocity.y * 0.97 }); + Matter.Body.setVelocity(best.who, { + x: best.who.velocity.x * 0.97, + y: best.who.velocity.y * 0.97 + }); const force = Vector.mult(Vector.normalise(Vector.sub(path[index], path[Math.max(0, index - 1)])), 0.003 * push * Math.min(6, best.who.mass)) Matter.Body.applyForce(best.who, path[index], force) } }; - const reflection = function() { // https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector + const reflection = function () { // https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector const n = Vector.perp(Vector.normalise(Vector.sub(best.v1, best.v2))); const d = Vector.sub(path[path.length - 1], path[path.length - 2]); const nn = Vector.mult(n, 2 * Vector.dot(d, n)); @@ -4789,14 +5101,20 @@ const b = { let lastBestOdd let lastBestEven = best.who //used in hack below if (best.dist2 !== Infinity) { //if hitting something - path[path.length - 1] = { x: best.x, y: best.y }; + path[path.length - 1] = { + x: best.x, + y: best.y + }; laserHitMob(); for (let i = 0; i < tech.laserReflections; i++) { reflection(); checkForCollisions(); if (best.dist2 !== Infinity) { //if hitting something lastReflection = best - path[path.length - 1] = { x: best.x, y: best.y }; + path[path.length - 1] = { + x: best.x, + y: best.y + }; damage *= reflectivity laserHitMob(); //I'm not clear on how this works, but it gets rid of a bug where the laser reflects inside a block, often vertically. @@ -4829,7 +5147,10 @@ const b = { }) Composite.add(engine.world, bullet[me]); //add bullet to world }, - boomBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) { + boomBot(position = { + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, isConsole = true) { if (isConsole) simulation.makeTextLog(`b.boomBot()`); const me = bullet.length; const dir = m.angle; @@ -4917,7 +5238,10 @@ const b = { }) Composite.add(engine.world, bullet[me]); //add bullet to world }, - plasmaBot(position = { x: player.position.x + 50 * (Math.random() - 0.5), y: player.position.y + 50 * (Math.random() - 0.5) }, isConsole = true) { + plasmaBot(position = { + x: player.position.x + 50 * (Math.random() - 0.5), + y: player.position.y + 50 * (Math.random() - 0.5) + }, isConsole = true) { if (isConsole) simulation.makeTextLog(`b.plasmaBot()`); const me = bullet.length; const dir = m.angle; @@ -4992,7 +5316,7 @@ const b = { y: this.position.y + range * unit.y } ]; - const vertexCollision = function(v1, v1End, domain) { + const vertexCollision = function (v1, v1End, domain) { for (let i = 0; i < domain.length; ++i) { let vertices = domain[i].vertices; const len = vertices.length - 1; @@ -5151,8 +5475,14 @@ const b = { if (!m.isCloak) { //if time dilation isn't active const size = 33 q = Matter.Query.region(mob, { - min: { x: this.position.x - size, y: this.position.y - size }, - max: { x: this.position.x + size, y: this.position.y + size } + min: { + x: this.position.x - size, + y: this.position.y - size + }, + max: { + x: this.position.x + size, + y: this.position.y + size + } }) for (let i = 0; i < q.length; i++) { if (!q[i].isShielded) { @@ -5293,7 +5623,9 @@ const b = { b.needle() function cycle() { - if (simulation.paused || m.isBodiesAsleep) { requestAnimationFrame(cycle) } else { + if (simulation.paused || m.isBodiesAsleep) { + requestAnimationFrame(cycle) + } else { count++ if (count % 2) b.needle() if (count < 7 && m.alive) requestAnimationFrame(cycle); @@ -5306,7 +5638,9 @@ const b = { b.needle() function cycle() { - if (simulation.paused || m.isBodiesAsleep) { requestAnimationFrame(cycle) } else { + if (simulation.paused || m.isBodiesAsleep) { + requestAnimationFrame(cycle) + } else { count++ if (count % 2) b.needle() if (count < 3 && m.alive) requestAnimationFrame(cycle); @@ -5331,7 +5665,7 @@ const b = { }); bullet[me].endCycle = simulation.cycle + 180 - bullet[me].beforeDmg = function(who) { //beforeDmg is rewritten with ice crystal tech + bullet[me].beforeDmg = function (who) { //beforeDmg is rewritten with ice crystal tech if (tech.isIncendiary) { this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion b.explosion(this.position, 100 + (Math.random() - 0.5) * 20); //makes bullet do explosive damage at end @@ -5350,7 +5684,7 @@ const b = { bullet[me].minDmgSpeed = 10 bullet[me].frictionAir = 0.006; - bullet[me].rotateToVelocity = function() { //rotates bullet to face current velocity? + bullet[me].rotateToVelocity = function () { //rotates bullet to face current velocity? if (this.speed > 7) { const facing = { x: Math.cos(this.angle), @@ -5365,7 +5699,7 @@ const b = { } }; if (tech.isIncendiary) { - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0008 this.rotateToVelocity() //collide with map @@ -5375,7 +5709,7 @@ const b = { } }; } else { - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0008 this.rotateToVelocity() }; @@ -5417,7 +5751,7 @@ const b = { y: SPEED * Math.sin(m.angle) }); bullet[me].endCycle = simulation.cycle + 180 - bullet[me].beforeDmg = function(who) { //beforeDmg is rewritten with ice crystal tech + bullet[me].beforeDmg = function (who) { //beforeDmg is rewritten with ice crystal tech if (tech.isIncendiary) { this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion b.explosion(this.position, 100 + (Math.random() - 0.5) * 20); //makes bullet do explosive damage at end @@ -5436,7 +5770,7 @@ const b = { bullet[me].minDmgSpeed = 10 bullet[me].frictionAir = 0.006; - bullet[me].rotateToVelocity = function() { //rotates bullet to face current velocity? + bullet[me].rotateToVelocity = function () { //rotates bullet to face current velocity? if (this.speed > 7) { const facing = { x: Math.cos(this.angle), @@ -5451,7 +5785,7 @@ const b = { } }; if (tech.isIncendiary) { - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0008 this.rotateToVelocity() //collide with map @@ -5461,7 +5795,7 @@ const b = { } }; } else { - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0008 this.rotateToVelocity() }; @@ -5507,7 +5841,7 @@ const b = { y: m.Vy / 2 + speed * Math.sin(angle) }) //position, velocity, damage if (tech.isIceCrystals) { - bullet[bullet.length - 1].beforeDmg = function(who) { + bullet[bullet.length - 1].beforeDmg = function (who) { mobs.statusSlow(who, 60) if (tech.isNailRadiation) mobs.statusDoT(who, 1 * (tech.isFastRadiation ? 1.3 : 0.44), tech.isSlowRadiation ? 360 : (tech.isFastRadiation ? 60 : 180)) // one tick every 30 cycles if (tech.isNailCrit) { @@ -5527,7 +5861,7 @@ const b = { }, { name: "shotgun", //1 - description: "fire a wide burst of short range bullets", + description: "fire a wide burst of short range bullets
with a low fire rate", ammo: 0, ammoPack: 3.5, defaultAmmoPack: 3.5, @@ -5576,7 +5910,7 @@ const b = { if (tech.isShotgunReversed) Matter.Body.setDensity(bullet[me], 0.0015) // bullet[me].restitution = 0.4 bullet[me].frictionAir = 0.034; - bullet[me].do = function() { + bullet[me].do = function () { const scale = 1 - 0.034 / tech.isBulletsLastLonger Matter.Body.scale(this, scale, scale); }; @@ -5599,10 +5933,10 @@ const b = { }); if (tech.isIncendiary) { bullet[me].endCycle = simulation.cycle + 60 - bullet[me].onEnd = function() { + bullet[me].onEnd = function () { b.explosion(this.position, 360 + (Math.random() - 0.5) * 60); //makes bullet do explosive damage at end } - bullet[me].beforeDmg = function() { + bullet[me].beforeDmg = function () { this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion }; } else { @@ -5612,10 +5946,13 @@ const b = { // bullet[me].restitution = 0.4 bullet[me].frictionAir = 0.004; bullet[me].turnMag = 0.04 * Math.pow(tech.bulletSize, 3.75) - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.002 if (this.speed > 6) { //rotates bullet to face current velocity? - const facing = { x: Math.cos(this.angle), y: Math.sin(this.angle) } + const facing = { + x: Math.cos(this.angle), + y: Math.sin(this.angle) + } if (Vector.cross(Vector.normalise(this.velocity), facing) < 0) { this.torque += this.turnMag } else { @@ -5626,7 +5963,7 @@ const b = { this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion } }; - bullet[me].beforeDmg = function(who) { + bullet[me].beforeDmg = function (who) { if (this.speed > 4) { if (tech.fragments) { b.targetedNail(this.position, 6 * tech.fragments * tech.bulletSize) @@ -5655,13 +5992,13 @@ const b = { x: speed * Math.cos(dirOff), y: speed * Math.sin(dirOff) }); - bullet[me].onEnd = function() { + bullet[me].onEnd = function () { b.explosion(this.position, 150 * (tech.isShotgunReversed ? 1.4 : 1) + (Math.random() - 0.5) * 40); //makes bullet do explosive damage at end } - bullet[me].beforeDmg = function() { + bullet[me].beforeDmg = function () { this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion }; - bullet[me].do = function() { + bullet[me].do = function () { if (Matter.Query.collides(this, map).length) this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion } Composite.add(engine.world, bullet[me]); //add bullet to world @@ -5697,17 +6034,26 @@ const b = { } } } else if (tech.isSporeFlea) { - const where = { x: m.pos.x + 35 * Math.cos(m.angle), y: m.pos.y + 35 * Math.sin(m.angle) } + const where = { + x: m.pos.x + 35 * Math.cos(m.angle), + y: m.pos.y + 35 * Math.sin(m.angle) + } const number = 2 * (tech.isShotgunReversed ? 1.5 : 1) for (let i = 0; i < number; i++) { const angle = m.angle + 0.2 * (Math.random() - 0.5) const speed = (input.down ? 35 * (1 + 0.05 * Math.random()) : 30 * (1 + 0.15 * Math.random())) - b.flea(where, { x: speed * Math.cos(angle), y: speed * Math.sin(angle) }) + b.flea(where, { + x: speed * Math.cos(angle), + y: speed * Math.sin(angle) + }) bullet[bullet.length - 1].setDamage() } spray(10); //fires normal shotgun bullets } else if (tech.isSporeWorm) { - const where = { x: m.pos.x + 35 * Math.cos(m.angle), y: m.pos.y + 35 * Math.sin(m.angle) } + const where = { + x: m.pos.x + 35 * Math.cos(m.angle), + y: m.pos.y + 35 * Math.sin(m.angle) + } const spread = (input.down ? 0.02 : 0.07) const number = 3 * (tech.isShotgunReversed ? 1.5 : 1) let angle = m.angle - (number - 1) * spread * 0.5 @@ -5737,7 +6083,10 @@ const b = { for (let i = 0; i < number; i++) { const SPEED = 13 + 4 * Math.random(); const angle = m.angle + spread * (Math.random() - 0.5) - b.foam(where, { x: SPEED * Math.cos(angle), y: SPEED * Math.sin(angle) }, 8 + 7 * Math.random()) + b.foam(where, { + x: SPEED * Math.cos(angle), + y: SPEED * Math.sin(angle) + }, 8 + 7 * Math.random()) } } else if (tech.isNeedles) { const number = 9 * (tech.isShotgunReversed ? 1.5 : 1) @@ -5778,11 +6127,11 @@ const b = { bullet[me].minDmgSpeed = 0; bullet[me].restitution = 1; bullet[me].friction = 0; - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0012; }; if (tech.isIncendiary) { - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0012; if (Matter.Query.collides(this, map).length) { b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end @@ -5790,21 +6139,24 @@ const b = { } }; } else { - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0012; }; } - bullet[me].beforeDmg = function(who) { - mobs.statusStun(who, 180) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds) + bullet[me].beforeDmg = function (who) { + mobs.statusStun(who, 120) // (2.3) * 2 / 14 ticks (2x damage over 7 seconds) if (tech.isIncendiary) { b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end this.endCycle = 0 } if (tech.isFoamBall) { - const radius = 5 + 8 * Math.random() - // const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 } - const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 } for (let i = 0, len = 6 * this.mass; i < len; i++) { + const radius = 5 + 8 * Math.random() + // const velocity = { x: Math.max(2, 10 - radius * 0.25), y: 0 } + const velocity = { + x: Math.max(0.5, 2 - radius * 0.1), + y: 0 + } b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) } this.endCycle = 0 @@ -5832,7 +6184,7 @@ const b = { bullet[me].restitution = 0.99; bullet[me].friction = 0; if (tech.isIncendiary) { - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0012; if (Matter.Query.collides(this, map).length) { b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end @@ -5840,19 +6192,22 @@ const b = { } }; } else { - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0012; }; } - bullet[me].beforeDmg = function() { + bullet[me].beforeDmg = function () { if (tech.isIncendiary) { b.explosion(this.position, this.mass * 320 + 70 * Math.random()); //makes bullet do explosive damage at end this.endCycle = 0 } if (tech.isFoamBall) { - const radius = 5 + 8 * Math.random() - const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 } for (let i = 0, len = 6 * this.mass; i < len; i++) { + const radius = 5 + 8 * Math.random() + const velocity = { + x: Math.max(0.5, 2 - radius * 0.1), + y: 0 + } b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) } this.endCycle = 0 @@ -5884,7 +6239,7 @@ const b = { bullet[me].restitution = 0.99; bullet[me].friction = 0; if (tech.isIncendiary) { - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0012; if (Matter.Query.collides(this, map).length) { b.explosion(this.position, this.mass * 280); //makes bullet do explosive damage at end @@ -5892,19 +6247,22 @@ const b = { } }; } else { - bullet[me].do = function() { + bullet[me].do = function () { this.force.y += this.mass * 0.0012; }; } - bullet[me].beforeDmg = function() { + bullet[me].beforeDmg = function () { if (tech.isIncendiary) { b.explosion(this.position, this.mass * 320 + 70 * Math.random()); //makes bullet do explosive damage at end this.endCycle = 0 } if (tech.isFoamBall) { - const radius = 5 + 8 * Math.random() - const velocity = { x: Math.max(0.5, 2 - radius * 0.1), y: 0 } for (let i = 0, len = 6 * this.mass; i < len; i++) { + const radius = 5 + 8 * Math.random() + const velocity = { + x: Math.max(0.5, 2 - radius * 0.1), + y: 0 + } b.foam(this.position, Vector.rotate(velocity, 6.28 * Math.random()), radius) } this.endCycle = 0 @@ -6067,7 +6425,10 @@ const b = { fire360Longitudinal() { m.fireCDcycle = m.cycle + Math.floor((input.down ? 4 : 8) * b.fireCDscale * tech.infiniteWaveAmmo); // cool down this.waves.push({ - position: { x: m.pos.x, y: m.pos.y, }, + position: { + x: m.pos.x, + y: m.pos.y, + }, radius: 25, reflection: tech.waveReflections, expanding: true, @@ -6131,8 +6492,14 @@ const b = { this.waves.push({ position: who.position, angle: angle - halfArc, //used in drawing ctx.arc - unit1: { x: Math.cos(angle - halfArc), y: Math.sin(angle - halfArc) }, //used for collision - unit2: { x: Math.cos(angle + halfArc), y: Math.sin(angle + halfArc) }, //used for collision + unit1: { + x: Math.cos(angle - halfArc), + y: Math.sin(angle - halfArc) + }, //used for collision + unit2: { + x: Math.cos(angle + halfArc), + y: Math.sin(angle + halfArc) + }, //used for collision arc: halfArc * 2, radius: 25, reflection: 1, @@ -6195,8 +6562,14 @@ const b = { y: m.pos.y + 25 * Math.sin(m.angle), }, angle: angle - halfArc, //used in drawing ctx.arc - unit1: { x: Math.cos(angle - halfArc), y: Math.sin(angle - halfArc) }, //used for collision - unit2: { x: Math.cos(angle + halfArc), y: Math.sin(angle + halfArc) }, //used for collision + unit1: { + x: Math.cos(angle - halfArc), + y: Math.sin(angle - halfArc) + }, //used for collision + unit2: { + x: Math.cos(angle + halfArc), + y: Math.sin(angle + halfArc) + }, //used for collision arc: halfArc * 2, radius: 25, reflection: tech.waveReflections, @@ -6272,13 +6645,16 @@ const b = { } }); if (tech.isBulletTeleport) { - bullet[me].wiggle = function() { + bullet[me].wiggle = function () { this.cycle++ const where = Vector.mult(transverse, this.amplitude * Math.cos(this.cycle * tech.waveFrequency)) if (Math.random() < 0.005) { if (Math.random() < 0.33) { //randomize position const scale = 500 * Math.random() - Matter.Body.setPosition(this, Vector.add({ x: scale * (Math.random() - 0.5), y: scale * (Math.random() - 0.5) }, Vector.add(this.position, where))) + Matter.Body.setPosition(this, Vector.add({ + x: scale * (Math.random() - 0.5), + y: scale * (Math.random() - 0.5) + }, Vector.add(this.position, where))) } else { //randomize position in velocity direction const velocityScale = Vector.mult(this.velocity, 50 * (Math.random() - 0.5)) Matter.Body.setPosition(this, Vector.add(velocityScale, Vector.add(this.position, where))) @@ -6298,7 +6674,7 @@ const b = { } if (tech.waveReflections) { bullet[me].reflectCycle = totalCycles / tech.waveReflections //tech.waveLengthRange - bullet[me].do = function() { + bullet[me].do = function () { this.query() if (this.cycle > this.reflectCycle) { this.reflectCycle += totalCycles / tech.waveReflections @@ -6308,7 +6684,7 @@ const b = { this.wiggle() } } else { - bullet[me].do = function() { + bullet[me].do = function () { this.query() this.wiggle(); } @@ -6330,7 +6706,7 @@ const b = { }, { name: "missiles", //6 - description: "launch homing missiles that explode", + description: "launch homing missiles that target mobs
missiles explode on contact with mobs", ammo: 0, ammoPack: 5, have: false, @@ -6391,11 +6767,17 @@ const b = { let count = 0 const fireMissile = () => { if (input.down) { - b.missile({ x: m.pos.x + 30 * direction.x, y: m.pos.y + 30 * direction.y }, m.angle, 20, sqrtCountReduction) + b.missile({ + x: m.pos.x + 30 * direction.x, + y: m.pos.y + 30 * direction.y + }, m.angle, 20, sqrtCountReduction) bullet[bullet.length - 1].force.x += 0.5 * push.x * (Math.random() - 0.5) bullet[bullet.length - 1].force.y += 0.004 + 0.5 * push.y * (Math.random() - 0.5) } else { - b.missile({ x: m.pos.x + 30 * direction.x, y: m.pos.y + 30 * direction.y }, m.angle, -15, sqrtCountReduction) + b.missile({ + x: m.pos.x + 30 * direction.x, + y: m.pos.y + 30 * direction.y + }, m.angle, -15, sqrtCountReduction) bullet[bullet.length - 1].force.x += push.x * (Math.random() - 0.5) bullet[bullet.length - 1].force.y += 0.005 + push.y * (Math.random() - 0.5) } @@ -6414,9 +6796,15 @@ const b = { requestAnimationFrame(cycle); } else { if (input.down) { - b.missile({ x: m.pos.x + 40 * direction.x, y: m.pos.y + 40 * direction.y }, m.angle, 25) + b.missile({ + x: m.pos.x + 40 * direction.x, + y: m.pos.y + 40 * direction.y + }, m.angle, 25) } else { - b.missile({ x: m.pos.x + 40 * direction.x, y: m.pos.y + 40 * direction.y }, m.angle, -12) + b.missile({ + x: m.pos.x + 40 * direction.x, + y: m.pos.y + 40 * direction.y + }, m.angle, -12) bullet[bullet.length - 1].force.y += 0.04 * (Math.random() - 0.2) } } @@ -6431,7 +6819,10 @@ const b = { fire() { const countReduction = Math.pow(0.93, tech.missileCount) m.fireCDcycle = m.cycle + Math.floor((input.down ? 35 : 27) * b.fireCDscale / countReduction); // cool down - const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } + const where = { + x: m.pos.x + 30 * Math.cos(m.angle), + y: m.pos.y + 30 * Math.sin(m.angle) + } const SPREAD = input.down ? 0.12 : 0.2 let angle = m.angle - SPREAD * (tech.missileCount - 1) / 2; for (let i = 0; i < tech.missileCount; i++) { @@ -6469,12 +6860,15 @@ const b = { bullet[me].restitution = 0.3; bullet[me].minDmgSpeed = 0; bullet[me].totalSpores = 8 + 2 * tech.isSporeFreeze + 4 * tech.isSporeColony - bullet[me].stuck = function() {}; - bullet[me].beforeDmg = function() {}; - bullet[me].do = function() { + bullet[me].stuck = function () {}; + bullet[me].beforeDmg = function () {}; + bullet[me].do = function () { function onCollide(that) { that.collisionFilter.mask = 0; //non collide with everything - Matter.Body.setVelocity(that, { x: 0, y: 0 }); + Matter.Body.setVelocity(that, { + x: 0, + y: 0 + }); that.do = that.grow; } @@ -6484,19 +6878,22 @@ const b = { this.stuckTo = mobCollisions[0].bodyA if (this.stuckTo.isVerticesChange) { - this.stuckToRelativePosition = { x: 0, y: 0 } + this.stuckToRelativePosition = { + x: 0, + y: 0 + } } else { //find the relative position for when the mob is at angle zero by undoing the mobs rotation this.stuckToRelativePosition = Vector.rotate(Vector.sub(this.position, this.stuckTo.position), -this.stuckTo.angle) } - this.stuck = function() { + this.stuck = function () { if (this.stuckTo && this.stuckTo.alive) { const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position)) Matter.Body.setVelocity(this, this.stuckTo.velocity); //so that it will move properly if it gets unstuck } else { this.collisionFilter.mask = cat.map; //non collide with everything but map - this.stuck = function() { + this.stuck = function () { this.force.y += this.mass * 0.0006; } } @@ -6512,7 +6909,7 @@ const b = { } else { this.do = this.grow; } - this.stuck = function() { + this.stuck = function () { if (this.stuckTo) { const rotate = Vector.rotate(this.stuckToRelativePosition, this.stuckTo.angle) //add in the mob's new angle to the relative position vector Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.stuckTo.velocity), this.stuckTo.position)) @@ -6535,7 +6932,7 @@ const b = { ctx.arc(this.position.x, this.position.y, this.maxRadius, 0, 2 * Math.PI); ctx.fill(); } - bullet[me].grow = function() { + bullet[me].grow = function () { this.stuck(); //runs different code based on what the bullet is stuck to let scale = 1.01 if (tech.isSporeGrowth && !(simulation.cycle % 40)) { //release a spore @@ -6543,7 +6940,10 @@ const b = { if (!(simulation.cycle % 80)) { const speed = 10 + 5 * Math.random() const angle = 2 * Math.PI * Math.random() - b.flea(this.position, { x: speed * Math.cos(angle), y: speed * Math.sin(angle) }) + b.flea(this.position, { + x: speed * Math.cos(angle), + y: speed * Math.sin(angle) + }) } } else if (tech.isSporeWorm) { if (!(simulation.cycle % 80)) b.worm(this.position) @@ -6567,7 +6967,7 @@ const b = { ctx.fill(); }; //spawn bullets on end - bullet[me].onEnd = function() { + bullet[me].onEnd = function () { let count = 0 //used in for loop below const things = [ @@ -6582,7 +6982,10 @@ const b = { count++ //count as 2 things const speed = 10 + 5 * Math.random() const angle = 2 * Math.PI * Math.random() - b.flea(this.position, { x: speed * Math.cos(angle), y: speed * Math.sin(angle) }) + b.flea(this.position, { + x: speed * Math.cos(angle), + y: speed * Math.sin(angle) + }) }, () => { // drones b.drone(this.position) @@ -6622,7 +7025,7 @@ const b = { } }, { name: "drones", //7 - description: "deploy drones that crash into mobs
crashes reduce their lifespan by 1 second", + description: "deploy drones that crash into mobs
or collect nearby power ups", //crashes reduce their lifespan by 1 second ammo: 0, ammoPack: 16, defaultAmmoPack: 16, @@ -6631,18 +7034,30 @@ const b = { fire() { if (tech.isDroneRadioactive) { if (input.down) { - b.droneRadioactive({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 45) + b.droneRadioactive({ + x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), + y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) + }, 45) m.fireCDcycle = m.cycle + Math.floor(50 * b.fireCDscale); // cool down } else { - b.droneRadioactive({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 10) + b.droneRadioactive({ + x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), + y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) + }, 10) m.fireCDcycle = m.cycle + Math.floor(25 * b.fireCDscale); // cool down } } else { if (input.down) { - b.drone({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 55) + b.drone({ + x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), + y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) + }, 55) m.fireCDcycle = m.cycle + Math.floor(10 * b.fireCDscale); // cool down } else { - b.drone({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 20) + b.drone({ + x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), + y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) + }, 20) m.fireCDcycle = m.cycle + Math.floor(5 * b.fireCDscale); // cool down } } @@ -6758,7 +7173,7 @@ const b = { name: "harpoon", //9 description: "fire a self-steering harpoon that uses energy
to retract and refund its ammo cost", ammo: 0, - ammoPack: 0.6, //update this in railgun tech + ammoPack: 1.7, //update this in railgun tech have: false, fire() {}, do() {}, @@ -6777,7 +7192,7 @@ const b = { charge: 0, railDo() { if (this.charge > 0) { - const DRAIN = (tech.isRailEnergy ? 0.00025 : 0.002) + const DRAIN = (tech.isRailEnergy ? 0.0002 : 0.002) //exit railgun charging without firing if (m.energy < DRAIN) { // m.energy += 0.025 + this.charge * 22 * this.drain @@ -6845,7 +7260,10 @@ const b = { } //draw little dots near the edge of range for (let i = 0, len = 10 + 25 * this.charge; i < len; i++) { - const unit = Vector.rotate({ x: 1, y: 0 }, 6.28 * Math.random()) + const unit = Vector.rotate({ + x: 1, + y: 0 + }, 6.28 * Math.random()) const where = Vector.add(m.pos, Vector.mult(unit, range * (0.6 + 0.3 * Math.random()))) simulation.drawList.push({ x: where.x, @@ -6867,7 +7285,10 @@ const b = { let targetCount = 0 const SPREAD = 0.06 + 0.05 * (!input.down) let angle = m.angle - SPREAD * tech.extraHarpoons / 2; - const dir = { x: Math.cos(angle), y: Math.sin(angle) }; //make a vector for the player's direction of length 1; used in dot product + const dir = { + x: Math.cos(angle), + y: Math.sin(angle) + }; //make a vector for the player's direction of length 1; used in dot product for (let i = 0, len = mob.length; i < len; ++i) { if (mob[i].alive && !mob[i].isBadTarget && !mob[i].shield && Matter.Query.ray(map, m.pos, mob[i].position).length === 0 && !mob[i].isInvulnerable) { @@ -6895,7 +7316,10 @@ const b = { simulation.updateGunHUD(); } else { //look for closest mob in player's LoS - const dir = { x: Math.cos(m.angle), y: Math.sin(m.angle) }; //make a vector for the player's direction of length 1; used in dot product + const dir = { + x: Math.cos(m.angle), + y: Math.sin(m.angle) + }; //make a vector for the player's direction of length 1; used in dot product for (let i = 0, len = mob.length; i < len; ++i) { if (mob[i].alive && !mob[i].isBadTarget && Matter.Query.ray(map, m.pos, mob[i].position).length === 0 && !mob[i].isInvulnerable) { const dot = Vector.dot(dir, Vector.normalise(Vector.sub(mob[i].position, m.pos))) //the dot product of diff and dir will return how much over lap between the vectors @@ -6931,13 +7355,13 @@ const b = { this.charge = 1 - smoothRate + this.charge * smoothRate if (m.energy > DRAIN) m.energy -= DRAIN - // console.log((this.charge).toFixed(2)) - // m.energy += (this.charge - previousCharge) * ((tech.isRailEnergy ? 0.5 : -0.3)) //energy drain is proportional to charge gained, but doesn't stop normal m.fieldRegen - //draw magnetic field const X = m.pos.x const Y = m.pos.y - const unitVector = { x: Math.cos(m.angle), y: Math.sin(m.angle) } + const unitVector = { + x: Math.cos(m.angle), + y: Math.sin(m.angle) + } const unitVectorPerp = Vector.perp(unitVector) function magField(mag, arc) { @@ -6995,7 +7419,9 @@ const b = { if (tech.crouchAmmoCount) tech.crouchAmmoCount = 1 b.grapple(where, m.angle, harpoonSize) } - m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down + // m.fireCDcycle = m.cycle + Math.floor(75 * b.fireCDscale) // cool down + m.fireCDcycle = m.cycle + 5 + 40 * b.fireCDscale + 60 * (m.energy < 0.05) + }, harpoonFire() { const where = { @@ -7008,12 +7434,15 @@ const b = { } //look for closest mob in player's LoS const harpoonSize = (tech.isLargeHarpoon ? 1 + 0.1 * Math.sqrt(this.ammo) : 1) //* (input.down ? 0.7 : 1) - const totalCycles = 6 * (tech.isFilament ? 1 + 0.012 * Math.min(110, this.ammo) : 1) * Math.sqrt(harpoonSize) + const totalCycles = 6.5 * (tech.isFilament ? 1 + 0.013 * Math.min(110, this.ammo) : 1) * Math.sqrt(harpoonSize) if (tech.extraHarpoons && !input.down) { //multiple harpoons - const SPREAD = 0.1 + const SPREAD = 0.2 let angle = m.angle - SPREAD * tech.extraHarpoons / 2; - const dir = { x: Math.cos(angle), y: Math.sin(angle) }; //make a vector for the player's direction of length 1; used in dot product + const dir = { + x: Math.cos(angle), + y: Math.sin(angle) + }; //make a vector for the player's direction of length 1; used in dot product const range = 450 * (tech.isFilament ? 1 + 0.012 * Math.min(110, this.ammo) : 1) let targetCount = 0 for (let i = 0, len = mob.length; i < len; ++i) { @@ -7034,17 +7463,21 @@ const b = { //if more harpoons and no targets left if (targetCount < tech.extraHarpoons + 1) { const num = tech.extraHarpoons - targetCount - const delay = 7 //Math.floor(Math.max(4, 8 - 0.5 * tech.extraHarpoons)) + const delay = 1 //Math.floor(Math.max(4, 8 - 0.5 * tech.extraHarpoons)) + let angle = m.angle - SPREAD * tech.extraHarpoons / 2; let count = -1 let harpoonDelay = () => { - if (simulation.paused) { requestAnimationFrame(harpoonDelay) } else { + if (simulation.paused) { + requestAnimationFrame(harpoonDelay) + } else { count++ if (!(count % delay) && this.ammo > 0) { this.ammo-- b.harpoon({ x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) - }, null, m.angle, harpoonSize, true, totalCycles) + }, null, angle, harpoonSize, true, totalCycles) + angle += SPREAD tech.harpoonDensity = 0.004 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed } if (count < num * delay && m.alive) requestAnimationFrame(harpoonDelay); @@ -7054,9 +7487,12 @@ const b = { } this.ammo++ //make up for the ammo used up in fire() simulation.updateGunHUD(); - m.fireCDcycle = m.cycle + 90 // cool down is set when harpoon bullet returns to player + } else { //input.down makes a single harpoon with longer range - const dir = { x: Math.cos(m.angle), y: Math.sin(m.angle) }; //make a vector for the player's direction of length 1; used in dot product + const dir = { + x: Math.cos(m.angle), + y: Math.sin(m.angle) + }; //make a vector for the player's direction of length 1; used in dot product for (let i = 0, len = mob.length; i < len; ++i) { if (mob[i].alive && !mob[i].isBadTarget && Matter.Query.ray(map, m.pos, mob[i].position).length === 0 && !mob[i].isInvulnerable) { const dot = Vector.dot(dir, Vector.normalise(Vector.sub(mob[i].position, m.pos))) //the dot product of diff and dir will return how much over lap between the vectors @@ -7068,13 +7504,13 @@ const b = { } } if (input.down && m.onGround) { - b.harpoon(where, null, m.angle, harpoonSize, true, 1.5 * totalCycles, (input.down && tech.crouchAmmoCount && (tech.crouchAmmoCount - 1) % 2) ? false : true) // harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true) { + b.harpoon(where, null, m.angle, harpoonSize, true, 1.6 * totalCycles, (input.down && tech.crouchAmmoCount && (tech.crouchAmmoCount - 1) % 2) ? false : true) // harpoon(where, target, angle = m.angle, harpoonSize = 1, isReturn = false, totalCycles = 35, isReturnAmmo = true) { } else { b.harpoon(where, closest.target, m.angle, harpoonSize, true, totalCycles) } - m.fireCDcycle = m.cycle + 45 // cool down is set when harpoon bullet returns to player tech.harpoonDensity = 0.004 //0.001 is normal for blocks, 0.004 is normal for harpoon, 0.004*6 when buffed } + m.fireCDcycle = m.cycle + 5 + 35 * b.fireCDscale + 60 * (m.energy < 0.05) + tech.extraHarpoons // cool down is set when harpoon bullet returns to player const recoil = Vector.mult(Vector.normalise(Vector.sub(where, m.pos)), input.down ? 0.015 : 0.035) player.force.x -= recoil.x player.force.y -= recoil.y @@ -7083,13 +7519,16 @@ const b = { name: "mine", //10 description: "toss a proximity mine that sticks to walls
refund undetonated mines on exiting a level", //fires nails at mobs within range ammo: 0, - ammoPack: 1.25, + ammoPack: 1.7, have: false, do() { if (!input.field && input.down && !tech.isLaserMine) { const cycles = 60 //30 const speed = 40 - const v = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) } //m.Vy / 2 + removed to make the path less jerky + const v = { + x: speed * Math.cos(m.angle), + y: speed * Math.sin(m.angle) + } //m.Vy / 2 + removed to make the path less jerky ctx.strokeStyle = "rgba(68, 68, 68, 0.2)" //color.map ctx.lineWidth = 2 ctx.beginPath() @@ -7104,21 +7543,36 @@ const b = { if (input.down) { if (tech.isLaserMine) { const speed = 30 - const velocity = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) } + const velocity = { + x: speed * Math.cos(m.angle), + y: speed * Math.sin(m.angle) + } b.laserMine(m.pos, velocity) m.fireCDcycle = m.cycle + Math.floor(65 * b.fireCDscale); // cool down } else { - const pos = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } + const pos = { + x: m.pos.x + 30 * Math.cos(m.angle), + y: m.pos.y + 30 * Math.sin(m.angle) + } let speed = 36 if (Matter.Query.point(map, pos).length > 0) speed = -2 //don't launch if mine will spawn inside map - b.mine(pos, { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) }, 0) + b.mine(pos, { + x: speed * Math.cos(m.angle), + y: speed * Math.sin(m.angle) + }, 0) m.fireCDcycle = m.cycle + Math.floor(55 * b.fireCDscale); // cool down } } else { - const pos = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } + const pos = { + x: m.pos.x + 30 * Math.cos(m.angle), + y: m.pos.y + 30 * Math.sin(m.angle) + } let speed = 23 if (Matter.Query.point(map, pos).length > 0) speed = -2 //don't launch if mine will spawn inside map - b.mine(pos, { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) }, 0) + b.mine(pos, { + x: speed * Math.cos(m.angle), + y: speed * Math.sin(m.angle) + }, 0) m.fireCDcycle = m.cycle + Math.floor(35 * b.fireCDscale); // cool down } } @@ -7213,7 +7667,10 @@ const b = { for (let i = 0; i < len; i++) { const history = m.history[(m.cycle - i * spacing) % 600] const off = history.yOff - 24.2859 - b.pulse(1.65 * this.charge * this.lensDamage, history.angle, { x: history.position.x, y: history.position.y - off }) + b.pulse(1.65 * this.charge * this.lensDamage, history.angle, { + x: history.position.x, + y: history.position.y - off + }) } } this.charge = 0; @@ -7259,10 +7716,6 @@ const b = { } // this.fire = this.firePhoton }, - // firePhoton() { - // m.fireCDcycle = m.cycle + Math.floor((tech.isPulseAim ? 25 : 50) * b.fireCDscale); // cool down - // b.photon({ x: m.pos.x + 23 * Math.cos(m.angle), y: m.pos.y + 23 * Math.sin(m.angle) }, m.angle) - // }, fireLaser() { const drain = 0.001 + tech.laserDrain / b.fireCDscale if (m.energy < drain) { @@ -7326,7 +7779,10 @@ const b = { y: 7.5 * Math.sin(m.angle - Math.PI / 2) } const dmg = 0.70 * tech.laserDamage / b.fireCDscale * this.lensDamage // 3.5 * 0.55 = 200% more damage - const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } + const where = { + x: m.pos.x + 30 * Math.cos(m.angle), + y: m.pos.y + 30 * Math.sin(m.angle) + } const eye = { x: m.pos.x + 15 * Math.cos(m.angle), y: m.pos.y + 15 * Math.sin(m.angle) diff --git a/js/index.js b/js/index.js index 070d780..09ec3ba 100644 --- a/js/index.js +++ b/js/index.js @@ -1,7 +1,10 @@ "use strict"; //convert text into numbers for seed -Math.hash = s => { for (var i = 0, h = 9; i < s.length;) h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9); return h ^ h >>> 9 } +Math.hash = s => { + for (var i = 0, h = 9; i < s.length;) h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9); + return h ^ h >>> 9 +} // const date1 = new Date() // console.log(date1.getUTCHours()) @@ -11,7 +14,7 @@ Math.hash = s => { for (var i = 0, h = 9; i < s.length;) h = Math.imul(h ^ s.cha document.getElementById("seed").placeholder = Math.initialSeed = String(Math.floor(Date.now() % 100000)) Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it -Math.seededRandom = function(min = 0, max = 1) { // in order to work 'Math.seed' must NOT be undefined +Math.seededRandom = function (min = 0, max = 1) { // in order to work 'Math.seed' must NOT be undefined Math.seed = (Math.seed * 9301 + 49297) % 233280; return min + Math.seed / 233280 * (max - min); } @@ -97,7 +100,7 @@ const color = { //light //difficulty is 0 easy, 1 normal, 2 hard, 4 why function getUrlVars() { let vars = {}; - window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, k, v) { + window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, k, v) { vars[k] = v; }); return vars; @@ -122,7 +125,7 @@ window.addEventListener('load', () => { break; } } - if (found) build.choosePowerUp(document.getElementById(`field-${index}`), index, 'field') + if (found) build.choosePowerUp(index, 'field') } if (property.substring(0, 3) === "gun") { let found = false @@ -134,12 +137,12 @@ window.addEventListener('load', () => { break; } } - if (found) build.choosePowerUp(document.getElementById(`gun-${index}`), index, 'gun') + if (found) build.choosePowerUp(index, 'gun') } if (property.substring(0, 4) === "tech") { for (let i = 0; i < tech.tech.length; i++) { if (set[property] === tech.tech[i].name) { - build.choosePowerUp(document.getElementById(`tech-${i}`), i, 'tech', true) + build.choosePowerUp(i, 'tech', true) break; } } @@ -150,13 +153,14 @@ window.addEventListener('load', () => { lore.setTechGoal() document.getElementById("difficulty-select-experiment").value = Number(set[property]) } - if (property === "level") document.getElementById("starting-level").value = Math.max(Number(set[property]) - 1, 0) - if (property === "noPower") document.getElementById("no-power-ups").checked = Number(set[property]) if (property === "molMode") { simulation.molecularMode = Number(set[property]) const i = 4 //update experiment text m.fieldUpgrades[i].description = m.fieldUpgrades[i].setDescription() - document.getElementById(`field-${i}`).innerHTML = `
  ${build.nameLink(m.fieldUpgrades[i].name)}
${m.fieldUpgrades[i].description}` + // document.getElementById(`field-${i}`).innerHTML = `
  ${build.nameLink(m.fieldUpgrades[i].name)}
${m.fieldUpgrades[i].description}` + document.getElementById(`field-${i}`).innerHTML = `
+
  ${build.nameLink(m.fieldUpgrades[i].name)}
+ ${m.fieldUpgrades[i].description}
` } // if (property === "seed") { // document.getElementById("seed").placeholder = Math.initialSeed = String(set[property]) @@ -198,7 +202,7 @@ const ctx = canvas.getContext("2d"); document.body.style.backgroundColor = "#fff"; //disable pop up menu on right click -document.oncontextmenu = function() { +document.oncontextmenu = function () { return false; } @@ -280,13 +284,27 @@ const build = { } requestAnimationFrame(loop); }, + showImages(from) { //on click event: from all 3 different places to hide / show images + localSettings.isHideImages = !localSettings.isHideImages + if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage + if (from === 'experiment') { + // build.startExperiment() + // openExperimentMenu() + build.reset(); + // build.populateGrid(); + // build.choosePowerUp(null, 'none') + } else if (from === 'pause') { + build.unPauseGrid() + build.pauseGrid() //redraw pause text with images + } else { //settings + //nothing needs to be here I think + } + + document.getElementById("hide-images").checked = localSettings.isHideImages + // console.log(localSettings.isHideImages, from) + }, pauseGrid() { // build.pixelDraw(); - - - - - //used for junk estimation let junkCount = 0 let totalCount = 1 //start at one to avoid NaN issues @@ -307,72 +325,108 @@ const build = { if (tech.plasmaBotCount) botText += `
plasma-bots: ${tech.plasmaBotCount}` if (tech.missileBotCount) botText += `
missile-bots: ${tech.missileBotCount}` - let text = `
` - if (!simulation.isChoosing) text += `
PAUSED               press P to resume -

+ let text = `
+ copy build url -
` - text += ` -
damage: ${((tech.damageFromTech())).toPrecision(3)}     difficulty: ${((m.dmgScale)).toPrecision(3)} -
defense: ${tech.isEnergyHealth ? (1-Math.pow(m.harmReduction(), 0.1)).toPrecision(3) : (1-m.harmReduction()).toPrecision(3) }     difficulty: ${(1/simulation.dmgScale).toPrecision(3)} +PAUSED +
+ + +press ${input.key.pause} to resume +
+
damage: ${((tech.damageFromTech())).toPrecision(4)}     difficulty: ${((m.dmgScale)).toPrecision(4)} +
defense: ${tech.isEnergyHealth ? (1-Math.pow(m.harmReduction(), 0.1)).toPrecision(5) : (1-m.harmReduction()).toPrecision(5) }     difficulty: ${(1/simulation.dmgScale).toPrecision(4)}
fire rate: ${((1-b.fireCDscale)*100).toFixed(b.fireCDscale < 0.1 ? 2 : 0)}% ${tech.duplicationChance() ? `
duplication: ${(tech.duplicationChance()*100).toFixed(0)}%`: ""} ${m.coupling ? `
coupling: ${(m.coupling).toFixed(2)}   `+m.couplingDescription()+"": ""} ${botText}

health: (${(m.health*100).toFixed(0)} / ${(m.maxHealth*100).toFixed(0)}) +mass: ${player.mass.toFixed(1)}
energy: (${(m.energy*100).toFixed(0)} / ${(m.maxEnergy*100).toFixed(0)}) +(${(m.fieldRegen*6000).toFixed(0)}/s) +position: (${player.position.x.toFixed(1)}, ${player.position.y.toFixed(1)})
gun: ${b.activeGun === null || b.activeGun === undefined ? "undefined":b.guns[b.activeGun].name}   ammo: ${b.activeGun === null || b.activeGun === undefined ? "0":b.guns[b.activeGun].ammo} -
tech: ${tech.totalCount}   research: ${powerUps.research.count} +mouse: (${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)}) +
tech: ${tech.totalCount}   research: ${powerUps.research.count} +velocity: (${player.velocity.x.toFixed(3)}, ${player.velocity.y.toFixed(3)}) ${junkCount ? `
JUNK: ${(junkCount / totalCount * 100).toFixed(1)}% `: ""} -
-
seed: ${Math.initialSeed} -
level: ${level.levels[level.onLevel]} (${level.difficultyText()})   ${m.cycle} cycles -
mobs: ${mob.length}   deaths: ${mobs.mobDeaths} -
blocks: ${body.length}   bullets: ${bullet.length}   power ups: ${powerUp.length} -
position: (${player.position.x.toFixed(1)}, ${player.position.y.toFixed(1)})   velocity: (${player.velocity.x.toFixed(1)}, ${player.velocity.y.toFixed(1)}) -
mouse: (${simulation.mouseInGame.x.toFixed(1)}, ${simulation.mouseInGame.y.toFixed(1)})   mass: ${player.mass.toFixed(1)} +
level: ${level.levelsCleared} ${level.levels[level.onLevel]} (${level.difficultyText()}) +
seed: ${Math.initialSeed}   ${m.cycle} cycles +
mobs: ${mob.length}   blocks: ${body.length}   bullets: ${bullet.length}   power ups: ${powerUp.length} ${simulation.isCheating ? "

lore disabled": ""}
`; - for (let i = 0, len = b.inventory.length; i < len; i++) { - text += `
  ${build.nameLink(b.guns[b.inventory[i]].name)} - ${b.guns[b.inventory[i]].ammo}
${b.guns[b.inventory[i]].description}
` + // deaths: ${mobs.mobDeaths}   + if (tech.isPauseSwitchField && !simulation.isChoosing) { + const style = localSettings.isHideImages ? `style="height:auto;"` : `style="background-image: url('img/field/${m.fieldUpgrades[m.fieldMode].name}${m.fieldMode === 0 ? Math.floor(Math.random()*10) : ""}.webp');"` + text += `
+
+
  ${build.nameLink(m.fieldUpgrades[m.fieldMode].name)}
+ ${m.fieldUpgrades[m.fieldMode].description}
` + } else { + const style = localSettings.isHideImages ? `style="height:auto;"` : `style="background-image: url('img/field/${m.fieldUpgrades[m.fieldMode].name}${m.fieldMode === 0 ? Math.floor(Math.random()*10) : ""}.webp');"` + text += `
+
+
  ${build.nameLink(m.fieldUpgrades[m.fieldMode].name)}
+ ${m.fieldUpgrades[m.fieldMode].description}
` } + // for (let i = 0, len = b.inventory.length; i < len; i++) { + // text += `
  ${build.nameLink(b.guns[b.inventory[i]].name)} - ${b.guns[b.inventory[i]].ammo}
${b.guns[b.inventory[i]].description}
` + // } + for (let i = 0, len = b.inventory.length; i < len; i++) { + const style = localSettings.isHideImages ? `style="height:auto;"` : `style="background-image: url('img/gun/${b.guns[b.inventory[i]].name}.webp');"` + text += `
+
+
  ${build.nameLink(b.guns[b.inventory[i]].name)} - ${b.guns[b.inventory[i]].ammo}
+ ${b.guns[b.inventory[i]].description}
` + } + let el = document.getElementById("pause-grid-left") el.style.display = tech.isNoDraftPause ? "none" : "grid" //disabled for eternalism because eternalism lets the player play while this menu is up but the menu doesn't update el.innerHTML = text //right side text = ""; - if (tech.isPauseSwitchField && !simulation.isChoosing) { - text += `
  ${build.nameLink(m.fieldUpgrades[m.fieldMode].name)}
${m.fieldUpgrades[m.fieldMode].description}
` - } else { - text += `
  ${build.nameLink(m.fieldUpgrades[m.fieldMode].name)}
${m.fieldUpgrades[m.fieldMode].description}
` - } - - const style = (tech.isPauseEjectTech && !simulation.isChoosing) ? 'style="animation: techColorCycle 1s linear infinite alternate;"' : '' + // const style = (tech.isPauseEjectTech && !simulation.isChoosing) ? 'style="animation: techColorCycle 1s linear infinite alternate;"' : '' + const ejectClass = (tech.isPauseEjectTech && !simulation.isChoosing) ? 'pause-eject' : '' for (let i = 0, len = tech.tech.length; i < len; i++) { if (tech.tech[i].count > 0) { + // const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""; + // if (tech.tech[i].isNonRefundable) { + // text += `
${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + // } else if (tech.tech[i].isFieldTech) { + // text += `
+ // + //
+ //
+ //
+ //         ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + // } else if (tech.tech[i].isGunTech) { + // text += `
+ // + //
+ //
+ //
+ //         ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + // } else if (tech.tech[i].isLore) { + // text += `
  ${tech.tech[i].name} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + // } else { + // text += `
  ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + // } + const style = localSettings.isHideImages ? `style="height:auto;"` : `style = "background-image: url('img/${tech.tech[i].name}.webp');"` const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""; if (tech.tech[i].isNonRefundable) { - text += `
${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + text += `
${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + // } else if (tech.tech[i].isLore) { + // text += `
  ${tech.tech[i].name} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` } else if (tech.tech[i].isFieldTech) { - text += `
- -
-
-
-         ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + text += `
` + text += build.fieldTechText(i) + "
" } else if (tech.tech[i].isGunTech) { - text += `
- -
-
-
-         ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` - } else if (tech.tech[i].isLore) { - text += `
  ${tech.tech[i].name} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + text += `
` + text += build.gunTechText(i) + "
" } else { - text += `
  ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + text += `
` + text += build.techText(i) + "
" } } else if (tech.tech[i].isLost) { text += `
${tech.tech[i].link}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` @@ -408,13 +462,39 @@ ${simulation.isCheating ? "

lore disabled": ""} }, isExperimentSelection: false, isExperimentRun: false, - choosePowerUp(who, index, type, isAllowed = false) { + techText(i) { + return `
+
  ${build.nameLink(tech.tech[i].name)} ${tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""}
+ ${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + }, + gunTechText(i) { + return `
+ +
+
+
          ${build.nameLink(tech.tech[i].name)} ${tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""}
+ ${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + }, + fieldTechText(i) { + return `
+ +
+
+
          ${build.nameLink(tech.tech[i].name)} ${tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""}
+ ${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + }, + junkTechText(i) { + return `
+
  ${build.nameLink(tech.tech[i].name)} ${tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""}
+ ${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + }, + choosePowerUp(index, type, isAllowed = false) { if (type === "gun") { let isDeselect = false for (let i = 0, len = b.inventory.length; i < len; i++) { //look for selection in inventory if (b.guns[b.inventory[i]].name === b.guns[index].name) { //if already clicked, remove gun isDeselect = true - who.classList.remove("build-gun-selected"); + document.getElementById("gun-" + b.inventory[i]).classList.remove("build-gun-selected"); //remove gun b.inventory.splice(i, 1) b.guns[index].count = 0; @@ -426,110 +506,66 @@ ${simulation.isCheating ? "

lore disabled": ""} } } if (!isDeselect) { //add gun - who.classList.add("build-gun-selected"); + document.getElementById("gun-" + index).classList.add("build-gun-selected"); b.giveGuns(index) } } else if (type === "field") { if (m.fieldMode !== index) { document.getElementById("field-" + m.fieldMode).classList.remove("build-field-selected"); m.setField(index) - who.classList.add("build-field-selected"); + document.getElementById("field-" + index).classList.add("build-field-selected"); } else if (m.fieldMode === 4) { const i = 4 //update experiment text simulation.molecularMode++ if (simulation.molecularMode > i - 1) simulation.molecularMode = 0 m.fieldUpgrades[i].description = m.fieldUpgrades[i].setDescription() - document.getElementById(`field-${i}`).innerHTML = `
  ${build.nameLink(m.fieldUpgrades[i].name)}
${m.fieldUpgrades[i].description}` + // document.getElementById(`field-${i}`).innerHTML = `
  ${build.nameLink(m.fieldUpgrades[i].name)}
${m.fieldUpgrades[i].description}` + + document.getElementById(`field-${i}`).innerHTML = `
+
  ${build.nameLink(m.fieldUpgrades[i].name)}
+ ${m.fieldUpgrades[i].description}
` } - - // if (m.fieldMode === 4 && simulation.molecularMode < 3) { - // simulation.molecularMode++ - // m.fieldUpgrades[4].description = m.fieldUpgrades[4].setDescription() - // } else { - // m.setField((m.fieldMode === m.fieldUpgrades.length - 1) ? 1 : m.fieldMode + 1) //cycle to next field - - // if (m.fieldMode === 4) { - // simulation.molecularMode = 0 - // m.fieldUpgrades[4].description = m.fieldUpgrades[4].setDescription() - // } - // } - - } else if (type === "tech") { if (tech.tech[index].count < tech.tech[index].maxCount) { // if (!tech.tech[index].isLore && !tech.tech[index].isNonRefundable && !who.classList.contains("build-tech-selected")) who.classList.add("build-tech-selected"); - if (!who.classList.contains("build-tech-selected")) who.classList.add("build-tech-selected"); + if (!document.getElementById("tech-" + index).classList.contains("build-tech-selected")) document.getElementById("tech-" + index).classList.add("build-tech-selected"); tech.giveTech(index) } else if (!tech.tech[index].isNonRefundable) { // tech.totalCount -= tech.tech[index].count tech.removeTech(index); - who.classList.remove("build-tech-selected"); + document.getElementById("tech-" + index).classList.remove("build-tech-selected"); } else { // for non refundable tech this makes it flash off for a second, but return to on to show that it can't be set off - who.classList.remove("build-tech-selected") + document.getElementById("tech-" + index).classList.remove("build-tech-selected") setTimeout(() => { - who.classList.add("build-tech-selected") + document.getElementById("tech-" + index).classList.add("build-tech-selected") }, 50); } } - - // } else if (type === "tech") { //remove tech if you have too many - // if (tech.tech[index].count < tech.tech[index].maxCount) { - // if (!who.classList.contains("build-tech-selected")) who.classList.add("build-tech-selected"); - // tech.giveTech(index) - // } else if (!tech.tech[index].isNonRefundable) { - // tech.totalCount -= tech.tech[index].count - // tech.removeTech(index); - // who.classList.remove("build-tech-selected"); - // } else { - // who.classList.remove("build-tech-selected") - // setTimeout(() => { //return energy - // who.classList.add("build-tech-selected") - // }, 50); - // } - // } - //update tech text //disable not allowed tech for (let i = 0, len = tech.tech.length; i < len; i++) { const techID = document.getElementById("tech-" + i) if ((!tech.tech[i].isJunk || localSettings.isJunkExperiment)) { //!tech.tech[i].isNonRefundable && //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! does removing this cause problems???? if (tech.tech[i].allowed() || isAllowed || tech.tech[i].count > 0) { - const techCountText = tech.tech[i].count > 1 ? `(${tech.tech[i].count}x)` : ""; - //
if (tech.tech[i].isFieldTech) { techID.classList.remove('experiment-grid-hide'); - techID.innerHTML = ` -
- -
-
-
-         ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description} - ` - //
- //
- // border: #fff solid 0px; + techID.innerHTML = build.fieldTechText(i) } else if (tech.tech[i].isGunTech) { techID.classList.remove('experiment-grid-hide'); - techID.innerHTML = ` -
- -
-
-
-         ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description} - ` + techID.innerHTML = build.gunTechText(i) } else if (tech.tech[i].isJunk) { - techID.innerHTML = `
  ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() : tech.tech[i].description}` + techID.innerHTML = build.junkTechText(i) + // `
  ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() : tech.tech[i].description}` } else { - techID.innerHTML = `
  ${tech.tech[i].link} ${techCountText}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() : tech.tech[i].description}` + techID.innerHTML = build.techText(i) } + //deselect selected tech options if you don't have the tech any more // for example: when bot techs are converted after a bot upgrade tech is taken if (tech.tech[i].count === 0 && techID.classList.contains("build-tech-selected")) techID.classList.remove("build-tech-selected"); if (techID.classList.contains("experiment-grid-disabled")) { techID.classList.remove("experiment-grid-disabled"); - techID.setAttribute("onClick", `javascript: build.choosePowerUp(this,${i},'tech')`); + techID.setAttribute("onClick", `javascript: build.choosePowerUp(${i},'tech')`); } // } else if (tech.tech[i].isGunTech || tech.tech[i].isFieldTech) { // techID.classList.add('experiment-grid-hide'); @@ -544,63 +580,97 @@ ${simulation.isCheating ? "

lore disabled": ""} } if (tech.tech[i].count > 0) tech.removeTech(i) if (techID.classList.contains("build-tech-selected")) techID.classList.remove("build-tech-selected"); + + if (tech.tech[i].isFieldTech) { + techID.innerHTML = build.fieldTechText(i) + } else if (tech.tech[i].isGunTech) { + techID.innerHTML = build.gunTechText(i) + } else if (tech.tech[i].isJunk) { + techID.innerHTML = build.junkTechText(i) + } else { + techID.innerHTML = build.techText(i) + } } } } }, - populateGrid() { + populateGrid() { //background-color:var(--build-bg-color); let text = ` -
- - - start - +
+
+ + + start + +
+
- + reset - + +     - + share - + -
-
-
starting level:
-
+
+
- - -
-
- - -
-
` + +
+
+ + +
+
` + const hideStyle = `style="height:auto; border: none; background-color: transparent;"` for (let i = 0, len = m.fieldUpgrades.length; i < len; i++) { - text += `
  ${build.nameLink(m.fieldUpgrades[i].name)}
${m.fieldUpgrades[i].description}
` + const style = localSettings.isHideImages ? hideStyle : `style="background-image: url('img/field/${m.fieldUpgrades[i].name}${i === 0 ? Math.floor(Math.random()*10) : ""}.webp');"` + //original + // text += powerUps.fieldText(i, `build.choosePowerUp(this,${i},'field')`) + // text += `
  ${build.nameLink(m.fieldUpgrades[i].name)}
${m.fieldUpgrades[i].description}
` + text += `
+
+
  ${build.nameLink(m.fieldUpgrades[i].name)}
+ ${m.fieldUpgrades[i].description}
` } for (let i = 0, len = b.guns.length; i < len; i++) { - text += `
  ${build.nameLink(b.guns[i].name)}
${b.guns[i].description}
` + const style = localSettings.isHideImages ? hideStyle : `style="background-image: url('img/gun/${b.guns[i].name}.webp');"` + text += `
+
+
  ${build.nameLink(b.guns[i].name)}
+ ${b.guns[i].description}
` + //original + // text += `
  ${build.nameLink(b.guns[i].name)}
${b.guns[i].description}
` } for (let i = 0, len = tech.tech.length; i < len; i++) { if (!tech.tech[i].isJunk || localSettings.isJunkExperiment) { + const style = localSettings.isHideImages ? hideStyle : `style="background-image: url('img/${tech.tech[i].name}.webp');"` + if (tech.tech[i].allowed() && (!tech.tech[i].isNonRefundable || localSettings.isJunkExperiment)) { // || tech.tech[i].name === "+1 cardinality") { //|| tech.tech[i].name === "leveraged investment" - if (tech.tech[i].isJunk) { - text += `
  ${tech.tech[i].link}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` - } else { - text += `
  ${tech.tech[i].link}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` - } - } else { - text += `
${tech.tech[i].name}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` - // text += `
${tech.tech[i].name}
${tech.tech[i].descriptionFunction ? tech.tech[i].descriptionFunction() :tech.tech[i].description}
` + text += `
` + } else { //disabled + text += `
` + // text += `
` } + if (tech.tech[i].isJunk) { + text += build.junkTechText(i) + } else if (tech.tech[i].isGunTech) { + text += build.gunTechText(i) + } else if (tech.tech[i].isFieldTech) { + text += build.fieldTechText(i) + } else { + text += build.techText(i) + } + text += '
' } } document.getElementById("experiment-grid").innerHTML = text @@ -672,23 +742,26 @@ ${simulation.isCheating ? "

lore disabled": ""} url += `&field=${encodeURIComponent(m.fieldUpgrades[m.fieldMode].name.trim())}` url += `&difficulty=${simulation.difficultyMode}` if (isCustom) { - url += `&level=${Math.abs(Number(document.getElementById("starting-level").value))}` - url += `&noPower=${Number(document.getElementById("no-power-ups").checked)}` + // url += `&level=${Math.abs(Number(document.getElementById("starting-level").value))}` // alert('n-gon build URL copied to clipboard.\nPaste into browser address bar.') } else { simulation.makeTextLog("n-gon build URL copied to clipboard.
Paste into browser address bar.") } console.log('n-gon build URL copied to clipboard.\nPaste into browser address bar.') console.log(url) - navigator.clipboard.writeText(url).then(function() { + navigator.clipboard.writeText(url).then(function () { /* clipboard successfully set */ if (isCustom) { - setTimeout(function() { alert('n-gon build URL copied to clipboard.\nPaste into browser address bar.') }, 300); + setTimeout(function () { + alert('n-gon build URL copied to clipboard.\nPaste into browser address bar.') + }, 300); } - }, function() { + }, function () { /* clipboard write failed */ if (isCustom) { - setTimeout(function() { alert('copy failed') }, 300); + setTimeout(function () { + alert('copy failed') + }, 300); } console.log('copy failed') }); @@ -705,23 +778,6 @@ ${simulation.isCheating ? "

lore disabled": ""} } for (let i = 0; i < bullet.length; ++i) Matter.Composite.remove(engine.world, bullet[i]); bullet = []; //remove any bullets that might have spawned from tech - const levelsCleared = Math.abs(Number(document.getElementById("starting-level").value) - 1) - level.difficultyIncrease(Math.min(99, levelsCleared * simulation.difficultyMode)) //increase difficulty based on modes - level.levelsCleared += levelsCleared; - simulation.isNoPowerUps = document.getElementById("no-power-ups").checked - if (simulation.isNoPowerUps) { //remove tech, guns, and fields - function removeOne() { //recursive remove one at a time to avoid array problems - for (let i = 0; i < powerUp.length; i++) { - if (powerUp[i].name === "tech" || powerUp[i].name === "gun" || powerUp[i].name === "field") { - Matter.Composite.remove(engine.world, powerUp[i]); - powerUp.splice(i, 1); - removeOne(); - break - } - } - } - removeOne(); - } build.hasExperimentalMode = false if (!simulation.isCheating) { for (let i = 0, len = tech.tech.length; i < len; i++) { @@ -928,14 +984,14 @@ document.getElementById("control-table").addEventListener('click', (event) => { window.addEventListener("keydown", input.setKeys); } }); -document.getElementById("control-details").addEventListener("toggle", function() { +document.getElementById("control-details").addEventListener("toggle", function () { input.controlTextUpdate() input.endKeySensing(); }) document.getElementById("control-reset").addEventListener('click', input.setDefault); -window.addEventListener("keyup", function(event) { +window.addEventListener("keyup", function (event) { switch (event.code) { case input.key.right: case "ArrowRight": @@ -962,7 +1018,7 @@ window.addEventListener("keyup", function(event) { } }); -window.addEventListener("keydown", function(event) { +window.addEventListener("keydown", function (event) { // console.log(event.code) switch (event.code) { case input.key.right: @@ -999,7 +1055,7 @@ window.addEventListener("keydown", function(event) { case input.key.pause: if (!simulation.isChoosing && input.isPauseKeyReady && m.alive) { input.isPauseKeyReady = false - setTimeout(function() { + setTimeout(function () { input.isPauseKeyReady = true }, 300); if (simulation.paused) { @@ -1027,7 +1083,12 @@ window.addEventListener("keydown", function(event) { } } m.energy = energy //return to current energy - document.getElementById("pause-field").innerHTML = `
  ${m.fieldUpgrades[m.fieldMode].name}
${m.fieldUpgrades[m.fieldMode].description}` + // document.getElementById("pause-field").innerHTML = `
  ${m.fieldUpgrades[m.fieldMode].name}
${m.fieldUpgrades[m.fieldMode].description}` + document.getElementById("pause-field").style.backgroundImage = `url('img/field/${m.fieldUpgrades[m.fieldMode].name}${m.fieldMode === 0 ? Math.floor(Math.random()*10) : ""}.webp')` + document.getElementById("pause-field").innerHTML = ` +
+
  ${build.nameLink(m.fieldUpgrades[m.fieldMode].name)}
+ ${m.fieldUpgrades[m.fieldMode].description}
` }); } } @@ -1210,8 +1271,12 @@ window.addEventListener("keydown", function(event) { break case "j": for (let i = 0, len = mob.length; i < len; ++i) mob[i].damage(Infinity, true) - setTimeout(() => { for (let i = 0, len = mob.length; i < len; ++i) mob[i].damage(Infinity, true) }, 100); - setTimeout(() => { for (let i = 0, len = mob.length; i < len; ++i) mob[i].damage(Infinity, true) }, 200); + setTimeout(() => { + for (let i = 0, len = mob.length; i < len; ++i) mob[i].damage(Infinity, true) + }, 100); + setTimeout(() => { + for (let i = 0, len = mob.length; i < len; ++i) mob[i].damage(Infinity, true) + }, 200); break case "l": document.getElementById("field").style.display = "none" @@ -1312,7 +1377,9 @@ if (localstorageCheck()) { } } else { console.log("localStorage is disabled") - localSettings = { isAllowed: false } + localSettings = { + isAllowed: false + } } if (localSettings.isAllowed && !localSettings.isEmpty) { @@ -1358,6 +1425,9 @@ if (localSettings.isAllowed && !localSettings.isEmpty) { localSettings.loreCount = 0; //this sets what conversation is heard if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } + if (localSettings.isHideImages === undefined) localSettings.isHideImages = false //default to show images + document.getElementById("hide-images").checked = localSettings.isHideImages + } else { console.log('setting default localSettings') @@ -1377,11 +1447,13 @@ if (localSettings.isAllowed && !localSettings.isEmpty) { isLoreDoesNotNeedReset: false, isHuman: false, key: undefined, + isHideImages: false, //default to show images }; input.setDefault() if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage document.getElementById("community-maps").checked = localSettings.isCommunityMaps simulation.isCommunityMaps = localSettings.isCommunityMaps + document.getElementById("hide-images").checked = localSettings.isHideImages document.getElementById("difficulty-select").value = localSettings.difficultyMode document.getElementById("fps-select").value = localSettings.fpsCapDefault document.getElementById("banned").value = localSettings.banList @@ -1427,10 +1499,10 @@ document.getElementById("difficulty-select").addEventListener("input", () => { }); -document.getElementById("updates").addEventListener("toggle", function() { +document.getElementById("updates").addEventListener("toggle", function () { function loadJSON(path, success, error) { //generic function to get JSON var xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function() { + xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE) { if (xhr.status === 200) { if (success) @@ -1449,7 +1521,7 @@ document.getElementById("updates").addEventListener("toggle", function() { /// https://api.github.com/repos/landgreen/n-gon/stats/commit_activity loadJSON('https://api.github.com/repos/landgreen/n-gon/commits', - function(data) { + function (data) { // console.log(data) for (let i = 0, len = 20; i < len; i++) { text += "" + data[i].commit.author.date.substr(0, 10) + " - "; //+ "
" @@ -1458,7 +1530,7 @@ document.getElementById("updates").addEventListener("toggle", function() { } document.getElementById("updates-div").innerHTML = text.replace(/\n/g, "
") }, - function(xhr) { + function (xhr) { console.error(xhr); } ); @@ -1498,6 +1570,55 @@ const sound = { // return audioCtx } } + +// preload images so they load cleaner +// MDN Scripting and preloads - https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload +// if (!localSettings.isHideImages) { +// for (let i = 0, len = b.guns.length; i < len; i++) { +// const preloadLink = document.createElement("link"); +// preloadLink.href = "img/gun/" + b.guns[i].name + ".webp"; +// preloadLink.rel = "preload"; +// preloadLink.as = "image"; +// document.head.appendChild(preloadLink); +// } +// for (let i = 1, len = m.fieldUpgrades.length; i < len; i++) { +// const preloadLink = document.createElement("link"); +// preloadLink.href = "img/field/" + m.fieldUpgrades[i].name + ".webp"; +// preloadLink.rel = "preload"; +// preloadLink.as = "image"; +// document.head.appendChild(preloadLink); +// } +// for (let i = 0, len = tech.tech.length; i < len; i++) { +// if (!tech.tech[i].isJunk) { +// const preloadLink = document.createElement("link"); +// preloadLink.href = "img/" + tech.tech[i].name + ".webp"; +// preloadLink.rel = "preload"; +// preloadLink.as = "image"; +// document.head.appendChild(preloadLink); +// } +// } +// } + + +//preload images early +if (!localSettings.isHideImages) { + addEventListener("load", () => { + let urls = new Array() + for (let i = 0, len = b.guns.length; i < len; i++) urls.push("img/gun/" + b.guns[i].name + ".webp") + for (let i = 1, len = m.fieldUpgrades.length; i < len; i++) urls.push("img/field/" + m.fieldUpgrades[i].name + ".webp") + for (let i = 0, len = tech.tech.length; i < len; i++) { + if (!tech.tech[i].isJunk) urls.push("img/" + tech.tech[i].name + ".webp") + } + let images = new Array() + for (let i = 0; i < urls.length; i++) { + images[i] = new Image() + images[i].src = urls[i] + } + // console.log(urls, images) + }); +} + + //********************************************************************** // main loop //********************************************************************** diff --git a/js/level.js b/js/level.js index 13e26b6..52dcb73 100644 --- a/js/level.js +++ b/js/level.js @@ -15,46 +15,53 @@ const level = { levels: [], start() { if (level.levelsCleared === 0) { //this code only runs on the first level - // simulation.enableConstructMode() //used to build maps in testing mode + // simulation.enableConstructMode() //tech.giveTech('motion sickness') //used to build maps in testing mode // simulation.isHorizontalFlipped = true // tech.giveTech("performance") - // level.difficultyIncrease(15 * 4) //30 is near max on hard //60 is near max on why + // level.difficultyIncrease(30 * 4) //30 is near max on hard //60 is near max on why // m.maxHealth = m.health = 100 // tech.isRerollDamage = true - // powerUps.research.changeRerolls(1000) + // powerUps.research.changeRerolls(5) // m.immuneCycle = Infinity //you can't take damage // tech.tech[297].frequency = 100 // m.couplingChange(5) - // m.setField("plasma torch") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass pilot wave plasma torch + // m.setField("time dilation") //molecular assembler standing wave time dilation perfect diamagnetism metamaterial cloaking wormhole negative mass pilot wave plasma torch // simulation.molecularMode = 2 // m.damage(0.1); // b.giveGuns("harpoon") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.giveGuns("wave") //0 nail gun 1 shotgun 2 super balls 3 wave 4 missiles 5 grenades 6 spores 7 drones 8 foam 9 harpoon 10 mine 11 laser // b.guns[0].ammo = 10000 - // tech.giveTech("plasma ball") - // tech.giveTech("dye laser") - // for (let i = 0; i < 1; ++i) tech.giveTech("railgun") - // for (let i = 0; i < 3; ++i) tech.giveTech("Bitter electromagnet") - // for (let i = 0; i < 1; i++) tech.giveTech("capacitor bank") - // for (let i = 0; i < 9; i++) tech.giveTech("heuristics") + // tech.giveTech("alternator") + // tech.giveTech("posture") + // for (let i = 0; i < 1; ++i) tech.giveTech("Sleipnir") + // tech.isFoamBall = true + // for (let i = 0; i < 1; ++i) tech.giveTech("emergence") + // for (let i = 0; i < 2; i++) tech.giveTech("unified field theory") + // for (let i = 0; i < 9; i++) tech.giveTech("replication") // for (let i = 0; i < 10; i++) powerUps.directSpawn(450, -50, "tech"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "boost"); // for (let i = 0; i < 10; i++) powerUps.directSpawn(1750, -500, "coupling"); - // level.testing(); // spawn.shooter(1900, -500, 200) // spawn.starter(1900, -500) - // spawn.timeBoss(2538, -950) - // for (let i = 0; i < 5; ++i) spawn.sniper(1000 + 5000 * Math.random(), -500 + 300 * Math.random()) - // tech.addJunkTechToPool(0.5) + // spawn.hopper(2538, -950) + // for (let i = 0; i < 2; ++i) spawn.starter(1000 + 1000 * Math.random(), -500 + 300 * Math.random()) + // tech.addJunkTechToPool(2) // tech.tech[322].frequency = 100 // spawn.tetherBoss(1900, -500, { x: 1900, y: -500 }) // for (let i = 0; i < 40; ++i) tech.giveTech() // for (let i = 0; i < 13; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "research"); - if (simulation.isTraining) { level.walk(); } else { level.intro(); } //normal starting level ************************************************ + //normal starting level ************************************************ + if (simulation.isTraining) { + level.walk() + } else { + level.intro() + } + // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "tech"); - // for (let i = 0; i < 30; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "tech", false); + // for (let i = 0; i < 2; ++i) powerUps.directSpawn(m.pos.x + 50 * Math.random(), m.pos.y + 50 * Math.random(), "gun"); + // for (let i = 0; i < 2; i++) powerUps.spawn(player.position.x + Math.random() * 50, player.position.y - Math.random() * 50, "field", false); //lore testing // for (let i = 0; i < 5; i++) tech.giveTech("undefined") @@ -69,13 +76,11 @@ const level = { // tech.isNoDraftPause = false //disable pause // mobs.mobDeaths = 200 //to prevent pacifist mode // for (let i = 0; i < 13; i++) level.nextLevel(); //jump to final boss - // lore.unlockTesting(); // tech.giveTech("tinker"); //show junk tech in experiment mode // simulation.isCheating = false // m.storeTech() // powerUps.spawn(m.pos.x, m.pos.y, "entanglement", false); - } else { spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns // spawn.pickList = ["focuser", "focuser"] @@ -111,12 +116,18 @@ const level = { if (tech.isForeverDrones) { if (tech.isDroneRadioactive) { for (let i = 0; i < tech.isForeverDrones * 0.25; i++) { - b.droneRadioactive({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5) + b.droneRadioactive({ + x: m.pos.x + 30 * (Math.random() - 0.5), + y: m.pos.y + 30 * (Math.random() - 0.5) + }, 5) bullet[bullet.length - 1].endCycle = Infinity } } else { for (let i = 0; i < tech.isForeverDrones; i++) { - b.drone({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5) + b.drone({ + x: m.pos.x + 30 * (Math.random() - 0.5), + y: m.pos.y + 30 * (Math.random() - 0.5) + }, 5) bullet[bullet.length - 1].endCycle = Infinity } } @@ -189,17 +200,17 @@ const level = { m.dmgScale = 1; //damage done by player decreases each level simulation.accelScale = 1 //mob acceleration increases each level simulation.CDScale = 1 //mob CD time decreases each level - simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels + simulation.dmgScale = Math.max(0.1, 0.32 * simulation.difficulty) //damage done by mobs scales with total levels simulation.healScale = 1 / (1 + simulation.difficulty * 0.05) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; }, difficultyIncrease(num = 1) { for (let i = 0; i < num; i++) { simulation.difficulty++ m.dmgScale *= 0.922; //damage done by player decreases each level - if (simulation.accelScale < 6) simulation.accelScale *= 1.025 //mob acceleration increases each level - if (simulation.CDScale > 0.15) simulation.CDScale *= 0.965 //mob CD time decreases each level + if (simulation.accelScale < 6) simulation.accelScale *= 1.024 //mob acceleration increases each level + if (simulation.CDScale > 0.15) simulation.CDScale *= 0.964 //mob CD time decreases each level } - simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels + simulation.dmgScale = Math.max(0.1, 0.32 * simulation.difficulty) //damage done by mobs scales with total levels simulation.healScale = 1 / (1 + simulation.difficulty * 0.05) //a higher denominator makes for lower heals // m.health += heal * simulation.healScale; // console.log(`CD = ${simulation.CDScale}`) }, @@ -207,11 +218,11 @@ const level = { for (let i = 0; i < num; i++) { simulation.difficulty-- m.dmgScale /= 0.922; //damage done by player decreases each level - if (simulation.accelScale > 1) simulation.accelScale /= 1.025 //mob acceleration increases each level - if (simulation.CDScale < 1) simulation.CDScale /= 0.965 //mob CD time decreases each level + if (simulation.accelScale > 1) simulation.accelScale /= 1.024 //mob acceleration increases each level + if (simulation.CDScale < 1) simulation.CDScale /= 0.964 //mob CD time decreases each level } if (simulation.difficulty < 1) simulation.difficulty = 0; - simulation.dmgScale = Math.max(0.1, 0.34 * simulation.difficulty) //damage done by mobs scales with total levels + simulation.dmgScale = Math.max(0.1, 0.32 * simulation.difficulty) //damage done by mobs scales with total levels simulation.healScale = 1 / (1 + simulation.difficulty * 0.05) }, difficultyText() { @@ -256,10 +267,12 @@ const level = { document.getElementById("health-bg").style.display = "none" document.getElementById("text-log").style.opacity = 0; //fade out any active text logs document.getElementById("fade-out").style.opacity = 1; //slowly fades out - setTimeout(function() { + setTimeout(function () { simulation.paused = true; level.disableExit = false; - engine.world.bodies.forEach((body) => { Matter.Composite.remove(engine.world, body) }) + engine.world.bodies.forEach((body) => { + Matter.Composite.remove(engine.world, body) + }) Engine.clear(engine); simulation.splashReturn(); }, 6000); @@ -335,7 +348,10 @@ const level = { flipHorizontal() { const flipX = (who) => { for (let i = 0, len = who.length; i < len; i++) { - Matter.Body.setPosition(who[i], { x: -who[i].position.x, y: who[i].position.y }) + Matter.Body.setPosition(who[i], { + x: -who[i].position.x, + y: who[i].position.y + }) } } flipX(map) @@ -382,7 +398,10 @@ const level = { Matter.Body.setPosition(player, m.spawnPos); Matter.Body.setVelocity(player, m.spawnVel); //makes perfect diamagnetism tech: Lenz's law show up in the right spot at the start of a level - m.fieldPosition = { x: m.pos.x, y: m.pos.y } + m.fieldPosition = { + x: m.pos.x, + y: m.pos.y + } m.fieldAngle = m.angle }, enter: { @@ -534,8 +553,11 @@ const level = { damping: 1 }); Composite.add(engine.world, constraint); - who.center = { x: who.position.x, y: who.position.y } - who.rotate = function() { + who.center = { + x: who.position.x, + y: who.position.y + } + who.rotate = function () { if (!m.isBodiesAsleep) { Matter.Body.applyForce(this, { x: this.position.x + 100, @@ -627,7 +649,10 @@ const level = { }); return who }, - elevator(x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }, isAtTop = false) { + elevator(x, y, width, height, maxHeight, force = 0.003, friction = { + up: 0.01, + down: 0.2 + }, isAtTop = false) { x += width / 2 y += height / 2 maxHeight += height / 2 @@ -753,7 +778,10 @@ const level = { this.constraint.stiffness = 0 this.constraint.damping = 0 //0.3 this.frictionAir = 0 - Matter.Body.setVelocity(this, { x: 0, y: 0 }); + Matter.Body.setVelocity(this, { + x: 0, + y: 0 + }); //show graphically being ready? } @@ -765,13 +793,19 @@ const level = { this.isReady = true } } else { - if (Vector.magnitudeSquared(Vector.sub(this.position, { x: x, y: y })) < distance * distance) { + if (Vector.magnitudeSquared(Vector.sub(this.position, { + x: x, + y: y + })) < distance * distance) { this.force.y -= force * this.mass } else { this.constraint.damping = 1 this.frictionAir = 1 this.isResetting = true - Matter.Body.setVelocity(this, { x: 0, y: 0 }); + Matter.Body.setVelocity(this, { + x: 0, + y: 0 + }); } } } @@ -977,10 +1011,33 @@ const level = { } } }, - vanish(x, y, width, height, isVertical = false, hide = { x: 0, y: 150 }) { + vanish(x, y, width, height, isVertical = false, hide = { + x: 0, + y: 150 + }) { x = x + width / 2 y = y + height / 2 - const vertices = [{ x: x, y: y, index: 0, isInternal: false }, { x: x + width, y: y, index: 1, isInternal: false }, { x: x + width, y: y + height, index: 4, isInternal: false }, { x: x, y: y + height, index: 3, isInternal: false }] + const vertices = [{ + x: x, + y: y, + index: 0, + isInternal: false + }, { + x: x + width, + y: y, + index: 1, + isInternal: false + }, { + x: x + width, + y: y + height, + index: 4, + isInternal: false + }, { + x: x, + y: y + height, + index: 3, + isInternal: false + }] const block = body[body.length] = Bodies.fromVertices(x, y, vertices, { // const block = body[body.length] = Bodies.rectangle(x, y, width, height, { collisionFilter: { @@ -999,9 +1056,49 @@ const level = { returnCount: 0, shrinkVertices(size) { if (isVertical) { - return [{ x: x, y: y * size, index: 0, isInternal: false }, { x: x + width, y: y * size, index: 1, isInternal: false }, { x: x + width, y: (y + height) * size, index: 4, isInternal: false }, { x: x, y: (y + height) * size, index: 3, isInternal: false }] + return [{ + x: x, + y: y * size, + index: 0, + isInternal: false + }, { + x: x + width, + y: y * size, + index: 1, + isInternal: false + }, { + x: x + width, + y: (y + height) * size, + index: 4, + isInternal: false + }, { + x: x, + y: (y + height) * size, + index: 3, + isInternal: false + }] } else { - return [{ x: x * size, y: y, index: 0, isInternal: false }, { x: (x + width) * size, y: y, index: 1, isInternal: false }, { x: (x + width) * size, y: y + height, index: 4, isInternal: false }, { x: x * size, y: y + height, index: 3, isInternal: false }] + return [{ + x: x * size, + y: y, + index: 0, + isInternal: false + }, { + x: (x + width) * size, + y: y, + index: 1, + isInternal: false + }, { + x: (x + width) * size, + y: y + height, + index: 4, + isInternal: false + }, { + x: x * size, + y: y + height, + index: 3, + isInternal: false + }] } }, query() { @@ -1028,7 +1125,10 @@ const level = { if (!m.isBodiesAsleep) { this.returnCount-- if (this.returnCount < 1) { - Matter.Body.setPosition(this, { x: x, y: y }) + Matter.Body.setPosition(this, { + x: x, + y: y + }) if (Matter.Query.collides(this, [player]).length) { //|| (Matter.Query.collides(this, body).length)) { Matter.Body.setPosition(this, hide) this.returnCount = 15 @@ -1179,7 +1279,7 @@ const level = { y: 0 }, angleB) - draw = function() { + draw = function () { ctx.beginPath(); //portal let v = this.vertices; ctx.moveTo(v[0].x, v[0].y); @@ -1189,7 +1289,7 @@ const level = { ctx.fillStyle = this.color ctx.fill(); } - query = function(isRemoveBlocks = false) { + query = function (isRemoveBlocks = false) { if (Matter.Query.collides(this, [player]).length === 0) { //not touching player if (player.isInPortal === this) player.isInPortal = null } else if (player.isInPortal !== this) { //touching player @@ -1546,7 +1646,10 @@ const level = { let isDoorLeft, isDoorRight, x, y doCustom = [] doCustomTopLayer = [] - offset = { x: 0, y: 0 } + offset = { + x: 0, + y: 0 + } const mobSpawnChance = 0 // Math.random() < chance + 0.07 * simulation.difficulty enterOptions = [ (x = offset.x, y = offset.y) => { //lasers @@ -1770,7 +1873,10 @@ const level = { button.isReadyToFire = true } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false - b.pulse(90, Math.PI, { x: x + 2000 - 560, y: y - 150 }) + b.pulse(90, Math.PI, { + x: x + 2000 - 560, + y: y - 150 + }) } } ) @@ -1801,7 +1907,10 @@ const level = { button.isReadyToFire = true } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false - b.pulse(90, 0, { x: x + 560, y: y - 150 }) + b.pulse(90, 0, { + x: x + 560, + y: y - 150 + }) } } ) @@ -1834,7 +1943,7 @@ const level = { button.isReadyToFire = true } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false - fireBlock = function(xPos, yPos) { + fireBlock = function (xPos, yPos) { const index = body.length spawn.bodyRect(xPos, yPos, 35 + 50 * Math.random(), 35 + 50 * Math.random()); const bodyBullet = body[body.length - 1] @@ -1845,6 +1954,7 @@ const level = { body[index].collisionFilter.category = cat.body; body[index].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet body[index].classType = "body"; + body[index].isAboutToBeRemoved = true; Composite.add(engine.world, body[index]); //add to world setTimeout(() => { //remove block for (let i = 0; i < body.length; i++) { @@ -1890,7 +2000,7 @@ const level = { button.isReadyToFire = true } else if (button.isReadyToFire && !button.isUp) { button.isReadyToFire = false - fireBlock = function(xPos, yPos) { + fireBlock = function (xPos, yPos) { const index = body.length spawn.bodyRect(xPos, yPos, 35 + 50 * Math.random(), 35 + 50 * Math.random()); const bodyBullet = body[body.length - 1] @@ -2092,7 +2202,10 @@ const level = { powerUps.directSpawn(x + 998, y - 333, "tech", false); } const powerUp1 = powerUp[powerUp.length - 1] - powerUp1.holdPosition = { x: powerUp1.position.x, y: powerUp1.position.y } + powerUp1.holdPosition = { + x: powerUp1.position.x, + y: powerUp1.position.y + } let isSpawnedMobs = false doCustom.push( () => { @@ -2759,7 +2872,10 @@ const level = { // level.enter.draw(); }; - let sway = { x: 0, y: 0 } + let sway = { + x: 0, + y: 0 + } let phase = -Math.PI / 2 level.customTopLayer = () => { ctx.fillStyle = "rgba(0,0,0,0.1)"; @@ -2893,7 +3009,7 @@ const level = { // spawn.starter(1900, -500, 200) //big boy // for (let i = 0; i < 10; ++i) spawn.launcher(1900, -500) - // spawn.slashBoss(1900, -500) + spawn.suckerBoss(1900, -500) // spawn.launcherBoss(3200, -500) // spawn.laserTargetingBoss(1700, -500) // spawn.powerUpBoss(1900, -500) @@ -3175,6 +3291,7 @@ const level = { powerUps.addResearchToLevel() //needs to run after mobs are spawned }, final() { + // color.map = "rgba(0,0,0,0.8)" const slime = level.hazard(simulation.isHorizontalFlipped ? 150 - 860 : -150, -360, 880, 259) //x, y, width, height, damage = 0.002) { slime.height -= slime.maxHeight - 150 //start slime at zero slime.min.y += slime.maxHeight @@ -3349,11 +3466,14 @@ const level = { } }, intro() { + // console.log(level.levelsCleared) if (level.levelsCleared === 0) { //if this is the 1st level of the game //wait to spawn power ups until unpaused //power ups don't spawn in experiment mode, so they don't get removed at the start of experiment mode + const goal = simulation.cycle + 10 + function cycle() { - if (simulation.cycle > 10) { + if (simulation.cycle > goal) { if (localSettings.loreCount === 6) { powerUps.spawn(2095 + 15 * (Math.random() - 0.5), -2170, "field", false); } else { @@ -3570,6 +3690,8 @@ const level = { ctx.fillRect(2030, 0, 150, 1800); }; + + level.setPosToSpawn(460, -100); //normal spawn // level.enter.x = -1000000; //hide enter graphic for first level by moving to the far left level.exit.x = 2800; @@ -3727,8 +3849,14 @@ const level = { slime.height -= slime.maxHeight - 60 //start slime at zero slime.min.y += slime.maxHeight slime.max.y = slime.min.y + slime.height - const elevator1 = level.elevator(-1625, -90, 310, 800, -2000, 0.0025, { up: 0.1, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { - const elevator2 = level.elevator(1175, -3050, 200, 250, -4475, 0.0025, { up: 0.12, down: 0.2 }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { + const elevator1 = level.elevator(-1625, -90, 310, 800, -2000, 0.0025, { + up: 0.1, + down: 0.2 + }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { + const elevator2 = level.elevator(1175, -3050, 200, 250, -4475, 0.0025, { + up: 0.12, + down: 0.2 + }) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { let waterFallWidth = 0 let waterFallX = 0 let waterFallSmoothX = 0 @@ -5518,7 +5646,10 @@ const level = { } }, highrise() { - const elevator1 = level.elevator(-790, -190, 180, 25, -1150, 0.0025, { up: 0.01, down: 0.2 }, true) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { + const elevator1 = level.elevator(-790, -190, 180, 25, -1150, 0.0025, { + up: 0.01, + down: 0.2 + }, true) //x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { elevator1.addConstraint(); // const button1 = level.button(-500, -200) const toggle1 = level.toggle(-300, -200) //(x,y,isOn,isLockOn = true/false) @@ -6249,7 +6380,10 @@ const level = { spawn.randomGroup(4150, -1000, 0.6); if (simulation.difficulty > 1) { if (Math.random() < 0.5) { - spawn.tetherBoss(2850, -80, { x: 2500, y: -500 }) + spawn.tetherBoss(2850, -80, { + x: 2500, + y: -500 + }) //chance to spawn a ring of exploding mobs around this boss if (simulation.difficulty > 6) spawn.nodeGroup(2850, -80, "spawns", 8, 20, 105); } else { @@ -6689,7 +6823,10 @@ const level = { if (simulation.difficulty > 1) { if (Math.random() < 0.2) { // tether ball - spawn.tetherBoss(7000, -3300, { x: 7300, y: -3300 }) + spawn.tetherBoss(7000, -3300, { + x: 7300, + y: -3300 + }) if (simulation.difficulty > 4) spawn.nodeGroup(7000, -3300, "spawns", 8, 20, 105); } else { spawn.randomLevelBoss(6100, -3600, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "pulsarBoss"]); @@ -6699,7 +6836,10 @@ const level = { if (simulation.difficulty > 1) { if (Math.random() < 0.2) { // tether ball - spawn.tetherBoss(2300, -1300, { x: 2300, y: -1750 }) + spawn.tetherBoss(2300, -1300, { + x: 2300, + y: -1750 + }) if (simulation.difficulty > 4) spawn.nodeGroup(2350, -1300, "spawns", 8, 20, 105); } else { spawn.randomLevelBoss(2300, -1400, ["shooterBoss", "launcherBoss", "laserTargetingBoss", "spiderBoss", "laserBoss", "dragonFlyBoss", "pulsarBoss"]); @@ -6758,7 +6898,10 @@ const level = { spawn.mapRect(3075, 1075, 375, 150); //Plafond salle trésor spawn.mapRect(3300, 1075, 1500, 1800); //Mur droite salle trésor // tether ball - spawn.tetherBoss(2330, 1850, { x: 2330, y: 1425 }) + spawn.tetherBoss(2330, 1850, { + x: 2330, + y: 1425 + }) spawn.secondaryBossChance(2330, 1850) //chance to spawn a ring of exploding mobs around this boss if (simulation.difficulty > 1) spawn.nodeGroup(2330, 1850, "spawns", 8, 20, 105); @@ -7293,11 +7436,11 @@ const level = { body[body.length] = part4; body[body.length] = part5; body[body.length] = part6; - setTimeout(function() { + setTimeout(function () { chair.collisionFilter.category = cat.body; chair.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); - setTimeout(function() { + setTimeout(function () { chair2.collisionFilter.category = cat.body; chair2.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); @@ -7352,7 +7495,7 @@ const level = { body[body.length] = rightUpperLeg body[body.length] = rightLowerArm body[body.length] = rightUpperArm - setTimeout(function() { + setTimeout(function () { person.collisionFilter.category = cat.body; person.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); @@ -7547,7 +7690,10 @@ const level = { if (simulation.difficulty > 3) { spawn.secondaryBossChance(3380, -1775) if (Math.random() < 0.16) { - spawn.tetherBoss(3380, -1775, { x: 3775, y: -1775 }) + spawn.tetherBoss(3380, -1775, { + x: 3775, + y: -1775 + }) if (simulation.difficulty > 4) spawn.nodeGroup(3380, -1775, "spawns", 8, 20, 105); //chance to spawn a ring of exploding mobs around this boss } else { spawn.randomLevelBoss(3100, -1850, ["shooterBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "dragonFlyBoss", "laserBoss"]); @@ -8814,7 +8960,7 @@ const level = { body[body.length] = part1; body[body.length] = part2; body[body.length] = part3; - setTimeout(function() { + setTimeout(function () { compoundParts.collisionFilter.category = cat.body; compoundParts.collisionFilter.mask = cat.body | cat.player | cat.bullet | cat.mob | cat.mobBullet | cat.map }, 1000); @@ -10079,19 +10225,19 @@ const level = { simulation.makeTextLog(`temple by Scar1337`); const V = Vector; - const Equation = (function() { + const Equation = (function () { function Equation(a, b, c) { this.a = a; this.b = b; this.c = c; } - Equation.prototype.getXfromY = function(y) { + Equation.prototype.getXfromY = function (y) { return (-this.b * y - this.c) / this.a; } - Equation.prototype.getYfromX = function(x) { + Equation.prototype.getYfromX = function (x) { return (-this.a * x - this.c) / this.b; } - Equation.fromPoints = function(v1, v2) { + Equation.fromPoints = function (v1, v2) { if (v1.x === v2.x) return new Equation(1, 0, -v1.x); if (v1.y === v2.y) return new Equation(0, 1, -v1.y); const d = (v2.y - v1.y) / (v2.x - v1.x); @@ -10099,17 +10245,23 @@ const level = { }; return Equation; })(); - const Rect = (function() { + const Rect = (function () { function Rect(x, y, w, h) { - this.pos = { x, y }; + this.pos = { + x, + y + }; this.width = w; this.height = h; } - Rect.prototype.has = function({ x, y }) { + Rect.prototype.has = function ({ + x, + y + }) { return x >= this.pos.x && x <= this.pos.x + this.width && y >= this.pos.y && y <= this.pos.y + this.height; } - Rect.prototype.hasLine = function(eq) { + Rect.prototype.hasLine = function (eq) { const leftInter = eq.getYfromX(this.pos.x); const rightInter = eq.getYfromX(this.pos.x + this.width); const topInter = eq.getXfromY(this.pos.y); @@ -10117,18 +10269,21 @@ const level = { (rightInter >= this.pos.y && rightInter <= this.pos.y + this.height) || (topInter >= this.pos.x && topInter <= this.pos.x + this.width); } - Rect.prototype.addToMap = function() { + Rect.prototype.addToMap = function () { spawn.mapRect(this.pos.x, this.pos.y, this.width, this.height); } Object.defineProperty(Rect.prototype, "midPos", { get() { - return V.add(this.pos, { x: this.width / 2, y: this.height / 2 }); + return V.add(this.pos, { + x: this.width / 2, + y: this.height / 2 + }); } }); - Rect.fromBounds = function(min, max) { + Rect.fromBounds = function (min, max) { return new Rect(min.x, min.y, max.x - min.x, max.y - min.y); } - Rect.prototype.isCollidingWith = function(other) { + Rect.prototype.isCollidingWith = function (other) { const tc = { p1: [this.pos.x, this.pos.y], p2: [this.pos.x + this.width, this.pos.y + this.height] @@ -10164,7 +10319,10 @@ const level = { function relocateWIMPs(x, y) { for (const i of mob) { if (i.isWIMP) { - setPos(i, { x: x + 300 * (Math.random() - 0.5), y: y + 300 * (Math.random() - 0.5) }); + setPos(i, { + x: x + 300 * (Math.random() - 0.5), + y: y + 300 * (Math.random() - 0.5) + }); } } } @@ -10186,14 +10344,14 @@ const level = { me.attackCycle = 0; me.lastAttackCycle = 0; Matter.Body.setDensity(me, 0.012); // extra dense, normal is 0.001 // makes effective life much larger - me.onDeath = function() { + me.onDeath = function () { // applying forces to player doesn't seem to work inside this method, not sure why powerUps.spawn(this.position.x + 20, this.position.y, "ammo"); if (Math.random() > 0.5) powerUps.spawn(this.position.x, this.position.y, "ammo"); if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, null, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5)); }; me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1); - me.do = function() { + me.do = function () { // keep it slow, to stop issues from explosion knock backs if (this.speed > 1) { Matter.Body.setVelocity(this, { @@ -10256,7 +10414,10 @@ const level = { if (this.attackCycle >= 30) { this.attackCycle = 0; this.lastAttackCycle = simulation.cycle; - Matter.Body.setVelocity(player, V.add(player.velocity, { x: 0, y: -10 })); + Matter.Body.setVelocity(player, V.add(player.velocity, { + x: 0, + y: -10 + })); if (m.immuneCycle < m.cycle) { if (m.energy > 0) m.energy -= 0.03; m.damage(0.005 * simulation.dmgScale); @@ -10287,13 +10448,13 @@ const level = { me.attackCycle = 0; me.maxAttackCycle = isDark ? 90 : 240; Matter.Body.setDensity(me, 0.006); // extra dense, normal is 0.001 // makes effective life much larger - me.onDeath = function() { + me.onDeath = function () { powerUps.spawn(this.position.x + 20, this.position.y, "ammo"); if (Math.random() > 0.5) powerUps.spawn(this.position.x, this.position.y, "ammo"); if (Math.random() > 0.3) powerUps.spawn(this.position.x, this.position.y, "heal", true, null, 30 * (simulation.healScale ** 0.25) * Math.sqrt(tech.largerHeals) * Math.sqrt(0.1 + Math.random() * 0.5)); }; me.damageReduction = 0.25 / (tech.isScaleMobsWithDuplication ? 1 + tech.duplicationChance() : 1); - me.do = function() { + me.do = function () { // keep it slow, to stop issues from explosion knock backs if (this.speed > 2) { Matter.Body.setVelocity(this, { @@ -10345,12 +10506,12 @@ const level = { me.maxAttackCycle = 10; me.inertia = Infinity; } - me.do = isDark ? function() { + me.do = isDark ? function () { Matter.Body.setVelocity(this, { x: this.velocity.x * 0.95, y: this.velocity.y * 0.95 }); - } : function() { + } : function () { Matter.Body.setVelocity(this, { x: this.velocity.x * 0.95, y: this.velocity.y * 0.95 @@ -10390,7 +10551,7 @@ const level = { let me = mob[mob.length - 1]; me.fill = "#ace"; me.damageReduction = 0; - me.onDeath = function() { + me.onDeath = function () { //damage player if in range if (distance(player.position, this.position) < pulseRadius && m.immuneCycle < m.cycle) { m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage @@ -10404,7 +10565,7 @@ const level = { time: simulation.drawTime }); }; - me.do = function() { + me.do = function () { this.timeLimit(); ctx.beginPath(); //draw explosion outline ctx.arc(this.position.x, this.position.y, pulseRadius * (1.01 - this.timeLeft / this.lifeSpan), 0, 2 * Math.PI); //* this.fireCycle / this.fireDelay @@ -10438,7 +10599,7 @@ const level = { me.lastAttackCycle = 0; me.spawnCycle = 0; Matter.Body.setDensity(me, 0.08); //extra dense //normal is 0.001 //makes effective life much larger - me.onDeath = function() { + me.onDeath = function () { for (let j = 0; j < 8; j++) { //in case some mobs leave things after they die for (let i = 0, len = mob.length; i < len; ++i) { if (mob[i] !== this) { @@ -10457,7 +10618,7 @@ const level = { }; me.nextHealthThreshold = 0.75; me.trapCycle = 0; - 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 @@ -10480,7 +10641,7 @@ const level = { radius: 500, id: 2 }]; - me.ring = function() { + me.ring = function () { if (this.isInvulnerable) return; ctx.lineWidth = 10; for (const ring of this.rings) { @@ -10492,7 +10653,7 @@ const level = { DrawTools.arcOut(this.position.x, this.position.y, radius, 0, Math.PI * 2); } } - me.horizon = function() { + me.horizon = function () { if (this.isInvulnerable) return this.fill = "#f00"; // eventHorizon waves in and out const eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(simulation.cycle * 0.008)); @@ -10532,7 +10693,10 @@ const level = { if (this.attackCycle >= 90) { this.attackCycle = 0; this.lastAttackCycle = simulation.cycle; - Matter.Body.setVelocity(player, V.add(player.velocity, { x: 0, y: -20 })); + Matter.Body.setVelocity(player, V.add(player.velocity, { + x: 0, + y: -20 + })); if (m.immuneCycle < m.cycle) { m.damage(0.012 * simulation.dmgScale); } @@ -10544,7 +10708,7 @@ const level = { DrawTools.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI); } } - me.periodicSpawns = function() { + me.periodicSpawns = function () { if (this.isInvulnerable) return; this.spawnCycle++; // Spawn annoying purple thing(s) that chases the player @@ -10557,9 +10721,15 @@ const level = { if (!(this.spawnCycle % 300)) { for (let i = 0; i < 3; i++) { mobGrenade(1100 + 700 * i, -13030, undefined, Math.min(700, 300 + simulation.difficulty * 4), 10); - setVel(mob[mob.length - 1], { x: 0, y: -10 }); + setVel(mob[mob.length - 1], { + x: 0, + y: -10 + }); mobGrenade(1100 + 700 * i, -14370, undefined, Math.min(700, 300 + simulation.difficulty * 4), 10); - setVel(mob[mob.length - 1], { x: 0, y: 10 }); + setVel(mob[mob.length - 1], { + x: 0, + y: 10 + }); } } // Spawn a bunch of mobs @@ -10578,7 +10748,7 @@ const level = { spawn.allowShields = true; } } - me.invulnerableTrap = function() { + me.invulnerableTrap = function () { if (this.trapCycle < 1) return; this.trapCycle++; // 24 is just an arbitrarily large number @@ -10590,13 +10760,25 @@ const level = { if (!(cycle % spawnDelay)) { const radius = Math.min(500, 200 + simulation.difficulty * 3); mobGrenade(600, -13050, 30, radius); - Matter.Body.setVelocity(mob[mob.length - 1], { x: 35, y: 0 }); + Matter.Body.setVelocity(mob[mob.length - 1], { + x: 35, + y: 0 + }); mobGrenade(3000, -13050, 30, radius); - Matter.Body.setVelocity(mob[mob.length - 1], { x: -35, y: 0 }); + Matter.Body.setVelocity(mob[mob.length - 1], { + x: -35, + y: 0 + }); mobGrenade(600, -14350, 30, radius); - Matter.Body.setVelocity(mob[mob.length - 1], { x: 35, y: 0 }); + Matter.Body.setVelocity(mob[mob.length - 1], { + x: 35, + y: 0 + }); mobGrenade(3000, -14350, 30, radius); - Matter.Body.setVelocity(mob[mob.length - 1], { x: -35, y: 0 }); + Matter.Body.setVelocity(mob[mob.length - 1], { + x: -35, + y: 0 + }); if (Math.floor(cycle / spawnDelay) >= spawnCycles - 1) { this.trapCycle = 0; this.isInvulnerable = false; @@ -10618,7 +10800,7 @@ const level = { ctx.fillText("!", 2700, -14350); ctx.shadowBlur = 0; } - me.do = function() { + me.do = function () { this.checkStatus(); this.horizon(); this.ring(); @@ -10639,7 +10821,7 @@ const level = { let bounds = []; let mobPositionsQueue = Array.from(Array(10), () => []); m.oldDeath = m.death; - m.death = function() { + m.death = function () { if (!tech.isImmortal) { requestAnimationFrame(() => color.map = "#444"); m.death = m.oldDeath; @@ -10750,7 +10932,7 @@ const level = { spawn.mapRect(-500, -8250, 800, 20); for (let i = 0; i < 2; i++) spawn.mapRect(-250, -8400 + 150 * i, 500, 60); const room2SlimePit = level.hazard(-400, -8410, 800, 1090); - room2SlimePit.logic = function() { + room2SlimePit.logic = function () { if (this.height > 0 && Matter.Query.region([player], this).length) { if (m.immuneCycle < m.cycle) { // Trolled @@ -10773,7 +10955,10 @@ const level = { tech.isRewindAvoidDeath = hasCPT; } player.force.y -= 0.3 * player.mass * simulation.g; - setVel(player, Vector.sub(player.velocity, { x: 0, y: player.velocity.y * 0.02 })); + setVel(player, Vector.sub(player.velocity, { + x: 0, + y: player.velocity.y * 0.02 + })); } // Float power ups powerUpCollide = Matter.Query.region(powerUp, this) @@ -10781,10 +10966,13 @@ const level = { const diameter = 2 * powerUpCollide[i].size const buoyancy = 1 - 0.2 * Math.max(0, Math.min(diameter, this.min.y - powerUpCollide[i].position.y + powerUpCollide[i].size)) / diameter powerUpCollide[i].force.y -= buoyancy * 1.14 * powerUpCollide[i].mass * simulation.g; - setVel(powerUpCollide[i], { x: powerUpCollide[i].velocity.x, y: 0.96 * powerUpCollide[i].velocity.y }); + setVel(powerUpCollide[i], { + x: powerUpCollide[i].velocity.x, + y: 0.96 * powerUpCollide[i].velocity.y + }); } } - room2SlimePit.draw = function() { + room2SlimePit.draw = function () { if (this.isOn) { ctx.fillStyle = "hsla(160, 100%, 35%, 0.75)"; ctx.fillRect(this.min.x, this.min.y, this.width, this.height); @@ -10829,7 +11017,10 @@ const level = { y: -2200 }, get isActive() { - const roughPlayerCentre = V.add(m.pos, { x: 0, y: 40 }); + const roughPlayerCentre = V.add(m.pos, { + x: 0, + y: 40 + }); return distance(roughPlayerCentre, this.pos) < 240 && (Math.abs(angle(roughPlayerCentre, this.pos) - Math.PI / 2) < 1); }, @@ -10899,8 +11090,20 @@ const level = { ctx.save(); simulation.camera(); if (this.distance < this.range && !this.capped) { - DrawTools.lightning(V.sub(this.pos, { x: 300, y: 300 }), V.add(this.pos, { x: 300, y: 300 }), simulation.cycle - 5); - DrawTools.lightning(V.add(this.pos, { x: -300, y: 300 }), V.add(this.pos, { x: 300, y: -300 }), simulation.cycle - 5); + DrawTools.lightning(V.sub(this.pos, { + x: 300, + y: 300 + }), V.add(this.pos, { + x: 300, + y: 300 + }), simulation.cycle - 5); + DrawTools.lightning(V.add(this.pos, { + x: -300, + y: 300 + }), V.add(this.pos, { + x: 300, + y: -300 + }), simulation.cycle - 5); } if (!this.capped && cycle >= this.cap - 200) { const multCoeff = (cycle - this.cap + 200) * 0.4 @@ -10927,8 +11130,20 @@ const level = { } }, room2Lightning: { - one: [{ x: -1400, y: -10400 }, { x: 1400, y: -8500 }], - two: [{ x: -1400, y: -8500 }, { x: 1400, y: -10400 }], + one: [{ + x: -1400, + y: -10400 + }, { + x: 1400, + y: -8500 + }], + two: [{ + x: -1400, + y: -8500 + }, { + x: 1400, + y: -10400 + }], get isHeal() { return simulation.cycle % 360 < 180; }, @@ -10959,7 +11174,7 @@ const level = { } }, room2GeneratedPath: { - rects: (function() { + rects: (function () { const rects = []; for (let i = 0; i < 4; i++) { rects.push(new Rect(-1405 + (i & 1) * 200, -9700 + i * 300, 205, 30)); @@ -10990,16 +11205,16 @@ const level = { } }, room3Rotors: { - rotor1: (function() { + rotor1: (function () { const rotor = level.spinner(900, -13700, 200, 30); - rotor.rotate = function() { + rotor.rotate = function () { Matter.Body.setAngularVelocity(this.bodyB, (this.bodyB.angularVelocity + 0.01) * 0.9) } return rotor; })(), - rotor2: (function() { + rotor2: (function () { const rotor = level.spinner(2700, -13700, 200, 30); - rotor.rotate = function() { + rotor.rotate = function () { Matter.Body.setAngularVelocity(this.bodyB, (this.bodyB.angularVelocity - 0.01) * 0.9) } return rotor; @@ -11329,7 +11544,10 @@ const level = { if (simulation.cycle % 4 === 0) { let newMobPositions = []; for (const i of mob) { - if (!(i.isMACHO || i.isWIMP || i.isObstacle)) newMobPositions.push({ x: i.position.x, y: i.position.y }); + if (!(i.isMACHO || i.isWIMP || i.isObstacle)) newMobPositions.push({ + x: i.position.x, + y: i.position.y + }); } mobPositionsQueue.shift(); mobPositionsQueue.push(newMobPositions); @@ -11475,14 +11693,20 @@ const level = { singleFlame(x, y, size = 10, repeat = 3, color = "#f00", angle = Math.PI / 2) { ctx.strokeStyle = color; ctx.lineWidth = 3; - const path = [{ x, y }]; + const path = [{ + x, + y + }]; for (let i = 0; i < repeat; i++) { const randAng = (Math.random() - 0.5) * 2 + angle; const randLen = 2 * size + Math.random() * size; x += Math.cos(randAng) * randLen; y -= Math.sin(randAng) * randLen; - path.push({ x, y }) + path.push({ + x, + y + }) } DrawTools.line(path); }, @@ -11493,28 +11717,58 @@ const level = { ctx.lineWidth = width * (1 - diff / 15); ctx.shadowColor = `rgb(${color.join(",")})`; ctx.shadowBlur = 20; - const path = [{ x: from.x, y: from.y }]; - let vector = { x: from.x, y: from.y }; + const path = [{ + x: from.x, + y: from.y + }]; + let vector = { + x: from.x, + y: from.y + }; let distanceLeft = V.magnitude(V.sub(from, to)); const d = distanceLeft > 800 ? distanceLeft / 40 : 20; const normalised = V.normalise(V.sub(to, from)); while (1) { - const randOffset = rotateVector({ y: RNG(Math.floor(cycle * randomPRNGMult + distanceLeft)) * 2 * d - d, x: 0 }, normalised); + const randOffset = rotateVector({ + y: RNG(Math.floor(cycle * randomPRNGMult + distanceLeft)) * 2 * d - d, + x: 0 + }, normalised); const randLen = RNG(Math.floor(cycle * (randomPRNGMult + 1) + distanceLeft)) * d + d; distanceLeft -= randLen; if (distanceLeft <= 0) { - path.push({ x: to.x, y: to.y }); + path.push({ + x: to.x, + y: to.y + }); break; } vector = V.add(vector, V.mult(normalised, randLen)); - path.push({ x: vector.x + randOffset.x, y: vector.y + randOffset.y }); + path.push({ + x: vector.x + randOffset.x, + y: vector.y + randOffset.y + }); } DrawTools.line(path); ctx.shadowBlur = 0; }, holy(x, y, size = 12) { - this.line([{ x, y: y - size }, { x: x - size, y }, - { x, y: y + size }, { x: x + size, y }, { x, y: y - size } + this.line([{ + x, + y: y - size + }, { + x: x - size, + y + }, + { + x, + y: y + size + }, { + x: x + size, + y + }, { + x, + y: y - size + } ]); } }; @@ -11532,15 +11786,27 @@ const level = { } function rotateVector(v, ang) { - const c = typeof ang === "number" ? { x: Math.cos(ang), y: Math.sin(ang) } : V.normalise(ang); - return { x: v.x * c.x - v.y * c.y, y: v.y * c.x + v.x * c.y }; + const c = typeof ang === "number" ? { + x: Math.cos(ang), + y: Math.sin(ang) + } : V.normalise(ang); + return { + x: v.x * c.x - v.y * c.y, + y: v.y * c.x + v.x * c.y + }; } function trapPlayer(x, y) { - setPosAndFreeze(player, { x, y }); + setPosAndFreeze(player, { + x, + y + }); const bLen = bullet.length; for (let i = 0; i < bLen; i++) { - if (bullet[i].botType) setPosAndFreeze(bullet[i], V.add(player.position, { x: 100 * (RNG(i) - 0.5), y: 100 * (RNG(i + bLen) - 0.5) })); + if (bullet[i].botType) setPosAndFreeze(bullet[i], V.add(player.position, { + x: 100 * (RNG(i) - 0.5), + y: 100 * (RNG(i + bLen) - 0.5) + })); } } @@ -11549,7 +11815,10 @@ const level = { trapPlayer(x, y); for (let i = 0; i < mob.length; i++) { if (mob[i].isMACHO) { - setPos(mob[i], { x, y }); + setPos(mob[i], { + x, + y + }); break; } } @@ -11559,7 +11828,10 @@ const level = { const angle = (a, b) => Math.atan2(b.y - a.y, a.x - b.x); const setPos = (a, b) => Matter.Body.setPosition(a, b); const setVel = (a, b) => Matter.Body.setVelocity(a, b); - const freeze = a => setVel(a, { x: 0, y: 0 }); + const freeze = a => setVel(a, { + x: 0, + y: 0 + }); const setPosAndFreeze = (a, b) => { setPos(a, b); freeze(a); @@ -11607,7 +11879,10 @@ const level = { const door2 = level.door(3131, -898, 40, 520, 522) const buttonDoor2 = level.button(2495, -270) const toggle = level.toggle(1463, -708, true) - const elevator = level.elevator(4310, -150, 200, 50, -1443, 0.0025, { up: 0.1, down: 0.2 }) + const elevator = level.elevator(4310, -150, 200, 50, -1443, 0.0025, { + up: 0.1, + down: 0.2 + }) const portal = level.portal({ //main portals x: 2117, y: -1560 @@ -11860,7 +12135,16 @@ const level = { let bossInit = false - const cutscenePoll = simulation.cutscene([{ x: 230, y: -2700 }, { x: 3500, y: -1400 }, { x: 1450, y: -1150 }, m.pos], 0.1, 10) + const cutscenePoll = simulation.cutscene([{ + x: 230, + y: -2700 + }, { + x: 3500, + y: -1400 + }, { + x: 1450, + y: -1150 + }, m.pos], 0.1, 10) let hasEnded = false // ** PROPS ** @@ -11886,7 +12170,7 @@ const level = { me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.mob | cat.bullet me.g = simulation.g me.leaveBody = me.isDropPowerUp = false - me.do = function() { + me.do = function () { this.gravity() // apply shock damage when touching the map, if it's fast if (this.speed > 5) { @@ -11901,7 +12185,7 @@ const level = { this.fill = `rgb(${232 * this.health}, 191, 40)` } - me.onDeath = function() { + me.onDeath = function () { const END = Math.floor(input.down ? 10 : 7) const totalBullets = 10 const angleStep = (input.down ? 0.4 : 1.3) / totalBullets @@ -11925,16 +12209,16 @@ const level = { x: speed * Math.cos(dirOff), y: speed * Math.sin(dirOff) }) - bullet[me].onEnd = function() { + bullet[me].onEnd = function () { b.explosion( this.position, 150 + (Math.random() - 0.5) * 40 ) //makes bullet do explosive damage at end } - bullet[me].beforeDmg = function() { + bullet[me].beforeDmg = function () { this.endCycle = 0 //bullet ends cycle after hitting a mob and triggers explosion } - bullet[me].do = function() {} + bullet[me].do = function () {} Composite.add(engine.world, bullet[me]) //add bullet to world } // barrels drop a ton of ammo and some heals, scales up with difficulty because I have mercy @@ -11960,7 +12244,10 @@ const level = { const perpCollision = point => { // takes a point, and finds a collision with the map downwards // the end of the ray, 3000 units down - const lowerPoint = Vector.add(point, { x: 0, y: 3000 }) + const lowerPoint = Vector.add(point, { + x: 0, + y: 3000 + }) // the destination point. If a collision was not found, then it defaults to some // arbiterary point 3000 units down. let dest = lowerPoint @@ -11968,7 +12255,10 @@ const level = { const check = simulation.checkLineIntersection(point, lowerPoint, mapBody.vertices[0], mapBody.vertices[1]) // a collision was found if (check.onLine1 && check.onLine2) { - dest = { x: check.x, y: check.y } + dest = { + x: check.x, + y: check.y + } break } } @@ -11981,7 +12271,12 @@ const level = { const width = Math.abs(firstBound.x - secondBound.x) const height = Math.abs(firstBound.y - secondBound.y) // compile to an object - return { x: firstBound.x, y: firstBound.y, width, height } + return { + x: firstBound.x, + y: firstBound.y, + width, + height + } } // create the actual platform spawn.mapRect(x, y, width, height) @@ -12031,7 +12326,7 @@ const level = { mobs.spawn(x, y + chainLength + radius * 2, 4, trappedMob.radius + 50, 'rgba(150, 255, 150, 0.3)') const cage = mob[mob.length - 1] cage.g = simulation.g - cage.do = function() { + cage.do = function () { this.gravity() } // label it @@ -12062,7 +12357,10 @@ const level = { // iterate over all vertices to form lines const v1 = verts[i] const v2 = verts[(i + 1) % verts.length] - const result = simulation.checkLineIntersection(cage.position, { x, y }, v1, v2) + const result = simulation.checkLineIntersection(cage.position, { + x, + y + }, v1, v2) if (result.onLine1 && result.onLine2) { // both lines cross! cross = result @@ -12073,7 +12371,10 @@ const level = { if (!cross) { // for some odd reason, sometimes it never finds a collision. I have no idea why // just default to the center then - console.error("Couldn't find a cross... Origin: ", { x, y }, " center: ", cage.position, ' vertices: ', cage.vertices) + console.error("Couldn't find a cross... Origin: ", { + x, + y + }, " center: ", cage.position, ' vertices: ', cage.vertices) cross = cage.position } // create the rope @@ -12179,7 +12480,10 @@ const level = { if (Math.random() > 0.999 && bossInit && !hasEnded) { const spawnLocs = [-1415, -30, 1345, 2815, 4285] // const randVec = Vector.mult({ x: Math.cos(randAngle), y: Math.sin(randAngle) }, Math.random() * 15) - barrelMob(spawnLocs[~~(spawnLocs.length * Math.random())], -4200, { x: 0, y: 0 }) + barrelMob(spawnLocs[~~(spawnLocs.length * Math.random())], -4200, { + x: 0, + y: 0 + }) } // platform shadow @@ -12264,7 +12568,10 @@ const level = { // initialized here as it depends on vertexCount. I could use `new function()` but nah. genome.vertexOffset = Array(genome.vertexCount) .fill() - .map(() => ({ x: Math.random() - 0.5, y: Math.random() - 0.5 })) + .map(() => ({ + x: Math.random() - 0.5, + y: Math.random() - 0.5 + })) return genome } @@ -12273,7 +12580,10 @@ const level = { const randomInRange = (min, max) => Math.random() * (max - min) + min const tinyChange = x => randomInRange(-x, x) - const vertexMutator = x => ({ x: x.x + tinyChange(0.5), y: x.y + tinyChange(0.5) }) + const vertexMutator = x => ({ + x: x.x + tinyChange(0.5), + y: x.y + tinyChange(0.5) + }) // mutates a genome and returns the mutated version. const newGenome = { density: genome.density + tinyChange(0.0005), @@ -12314,7 +12624,7 @@ const level = { const color = `rgba(${150 + 105 * charge}, 81, 50, 0.6)` mobs.spawn(origin.x, origin.y, 12, 20 + 20 * charge, color) const me = mob[mob.length - 1] - me.end = function() { + me.end = function () { simulation.drawList.push({ // some nice graphics x: this.position.x, @@ -12337,7 +12647,7 @@ const level = { me.life = 0 me.isDropPowerUp = false me.leaveBody = false - me.do = function() { + me.do = function () { // die on collision with the map if (Matter.Query.collides(this, map).length > 0) { this.end() @@ -12400,7 +12710,7 @@ const level = { me.bossPos = null // the position that the mob remembers when charging me.density = me.density * 2 Matter.Body.setDensity(me, 0.0022 * 3 + 0.0002 * Math.sqrt(simulation.difficulty)) //extra dense - me.do = function() { + me.do = function () { // if the boss is dead, die if (!parentBoss.alive) { this.death() @@ -12468,7 +12778,7 @@ const level = { // draw energy bar drawEnergyBar(this) } - me.onDeath = function() { + me.onDeath = function () { // remove itself from the list const beacons = parentBoss.energyBeacons beacons.splice(beacons.indexOf(this), 1) @@ -12513,7 +12823,7 @@ const level = { me.showHealthBar = false me.collisionFilter.category = cat.mobBullet me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet - me.do = function() { + me.do = function () { this.alwaysSeePlayer() this.attraction() this.timeLimit() @@ -12544,7 +12854,7 @@ const level = { // ctx.fillStyle = 'rgba(252, 0, 143, 1)' // ctx.fillText(~~this.score, this.position.x - this.radius, this.position.y - this.radius) } - me.onHit = function() { + me.onHit = function () { // hitting the player gives a 50 points score bonus this.score += 50 this.score += this.mass * 2 // bigger mass = bigger damage, add that too @@ -12552,7 +12862,7 @@ const level = { this.hitPlayer = true this.explode(this.mass) } - me.onDeath = function() { + me.onDeath = function () { if (!this.hitPlayer) { // if it didn't hit the player, give it a score based on its distance this.score += 10000 / this.distanceToPlayer() @@ -12561,7 +12871,10 @@ const level = { if (Math.random() > 0.97) { powerUps.spawn(this.position.x, this.position.y, 'ammo', true) } - parentBoss.deadOrbs.push({ genome: genome, score: this.score }) + parentBoss.deadOrbs.push({ + genome: genome, + score: this.score + }) } } @@ -12584,7 +12897,10 @@ const level = { me.energyBeacons = [] me.activeBalls = 0 // starts by random, or by the stored genomes if they exist - const init = () => ({ genome: generateGenome(), score: 0 }) + const init = () => ({ + genome: generateGenome(), + score: 0 + }) me.fittestOrbs = (localStorage && localStorage.genome) ? JSON.parse(localStorage.genome) : [init(), init(), init()] // best genomes so far. Size of three // when an orb died it's moved here. When a new spawn cycle starts, their scores get calculated // and they get put in the fittest orbs array, if they are better than the old ones. @@ -12600,7 +12916,7 @@ const level = { me.laserRange = radius * 4 Matter.Body.setDensity(me, 0.0022 * 4 + 0.0002 * Math.sqrt(simulation.difficulty)) //extra dense //normal is 0.001 //makes effective life much larger - me.onDeath = function() { + me.onDeath = function () { if (spawnBossPowerUp) { powerUps.spawnBossPowerUp(this.position.x, this.position.y) const amount = ~~(5 * Math.random() * simulation.difficulty / 10) * 2 @@ -12619,8 +12935,8 @@ const level = { // stop spawning barrels bossInit = false } - me.onDamage = function() {} - me.spawnBeacon = function() { + me.onDamage = function () {} + me.spawnBeacon = function () { // the vertex to spawn the beacon from const vert = this.vertices[~~(Math.random() * this.vertices.length)] // the position should be a little to the side to prevent crashing into the boss @@ -12636,7 +12952,7 @@ const level = { y: this.velocity.y + velocity.y }) } - me.spawnOrbs = function() { + me.spawnOrbs = function () { Matter.Body.setAngularVelocity(this, 0.11) // sort the vertices by the distance to the player const sorted = [...this.vertices].sort(dist2) @@ -12693,7 +13009,7 @@ const level = { }) } } - me.do = function() { + me.do = function () { this.seePlayerCheck() this.checkStatus() this.attraction() @@ -12738,7 +13054,10 @@ const level = { // if it's not a bot and it's close if (!it.botType && dist(this.position, it.position) < this.laserRange) { // add it to the ionized list - this.ionized.push({ target: it, ticks: 0 }) + this.ionized.push({ + target: it, + ticks: 0 + }) } } } @@ -13424,13 +13743,19 @@ const level = { //teleport to start if hit if (m.immuneCycle > m.cycle) { m.energy = m.maxEnergy - Matter.Body.setPosition(player, { x: 60, y: -50 }) + Matter.Body.setPosition(player, { + x: 60, + y: -50 + }) } //spawn bullets if (!(simulation.cycle % 5)) { spawn.sniperBullet(660 + 580 * Math.random(), -2000, 10, 4); const who = mob[mob.length - 1] - Matter.Body.setVelocity(who, { x: 0, y: 8 }); + Matter.Body.setVelocity(who, { + x: 0, + y: 8 + }); who.timeLeft = 300 } //exit room @@ -13466,7 +13791,10 @@ const level = { for (let i = 0; i < 32; i++) { spawn.sniperBullet(660 + 580 * Math.random(), -2000 + 40 * i, 10, 4); const who = mob[mob.length - 1] - Matter.Body.setVelocity(who, { x: 0, y: 8 }); + Matter.Body.setVelocity(who, { + x: 0, + y: 8 + }); who.timeLeft = 300 } }, @@ -13605,7 +13933,10 @@ const level = { } for (let i = 0; i < 2; i++) { spawn.spinner(1300 + i, -3000 - 200 * i, 25 + 5 * i) - Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 62 }); + Matter.Body.setVelocity(mob[mob.length - 1], { + x: 0, + y: 62 + }); } spawn.mapRect(-2750, -2800, 2600, 4600); //left wall @@ -14076,7 +14407,10 @@ const level = { if (button.isReady) { button.isReady = false spawn.exploder(335, -1700) - Matter.Body.setVelocity(mob[mob.length - 1], { x: 0, y: 20 }); + Matter.Body.setVelocity(mob[mob.length - 1], { + x: 0, + y: 20 + }); ctx.fillStyle = "rgba(255,0,0,0.9)" ctx.fillRect(550, -2800, 200, 1800) } @@ -14117,7 +14451,10 @@ const level = { b.removeAllGuns(); b.giveGuns("grenades") - const elevator1 = level.elevator(550, -100, 180, 25, -840, 0.003, { up: 0.05, down: 0.2 }) // x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { + const elevator1 = level.elevator(550, -100, 180, 25, -840, 0.003, { + up: 0.05, + down: 0.2 + }) // x, y, width, height, maxHeight, force = 0.003, friction = { up: 0.01, down: 0.2 }) { elevator1.addConstraint(); const toggle1 = level.toggle(275, 0) //(x,y,isOn,isLockOn = true/false) diff --git a/js/lore.js b/js/lore.js index 7fe0d09..720cb07 100644 --- a/js/lore.js +++ b/js/lore.js @@ -55,7 +55,7 @@ const lore = { trainer: { color: "#f20", voice: undefined, - text: function(say) { + text: function (say) { simulation.makeTextLog(`input.audio(${(Date.now()/1000).toFixed(0)} s): "${say}"`, Infinity); lore.talkingColor = this.color const utterance = new SpeechSynthesisUtterance(say); @@ -67,7 +67,7 @@ const lore = { anand: { color: "#e0c", voice: undefined, - text: function(say) { + text: function (say) { if (level.levels[level.onLevel] === undefined) { //only talk if on the lore level (which is undefined because it is popped out of the level.levels array) simulation.makeTextLog(`input.audio(${(Date.now()/1000).toFixed(0)} s): "${say}"`, Infinity); lore.talkingColor = this.color @@ -92,14 +92,16 @@ const lore = { lore.nextSentence() } } else { - setTimeout(() => { lore.nextSentence() }, 3000); + setTimeout(() => { + lore.nextSentence() + }, 3000); } } }, }, miriam: { color: "#f20", - text: function(say) { + text: function (say) { if (level.levels[level.onLevel] === undefined) { //only talk if on the lore level (which is undefined because it is popped out of the level.levels array) simulation.makeTextLog(`input.audio(${(Date.now()/1000).toFixed(0)} s): "${say}"`, Infinity); lore.talkingColor = this.color @@ -114,7 +116,7 @@ const lore = { lore.isSpeech = false lore.nextSentence() } - speechFrozen = setTimeout(function() { // speech frozen after 10 seconds of no end + speechFrozen = setTimeout(function () { // speech frozen after 10 seconds of no end console.log('speech frozen') lore.isSpeech = false lore.nextSentence() @@ -124,7 +126,9 @@ const lore = { lore.nextSentence() } } else { - setTimeout(() => { lore.nextSentence() }, 3000); + setTimeout(() => { + lore.nextSentence() + }, 3000); } } }, @@ -133,34 +137,80 @@ const lore = { sentence: 0, //what part of the conversation is playing conversation: [ [ //chapter 0, first time they meet, and testing gets unlocked - () => { setTimeout(() => { lore.miriam.text("I've never seen it generate this level before.") }, 5000); }, - () => { lore.anand.text("Wow. Just a platform.") }, - () => { lore.miriam.text("And that thing...") }, - () => { lore.anand.text("Weird") }, - () => { lore.anand.text("Maybe it's trapped.") }, - () => { lore.miriam.text("Looks like testing mode is locked.") }, - () => { lore.miriam.text("I'll unlock it with the console command.") }, + () => { + setTimeout(() => { + lore.miriam.text("I've never seen it generate this level before.") + }, 5000); + }, + () => { + lore.anand.text("Wow. Just a platform.") + }, + () => { + lore.miriam.text("And that thing...") + }, + () => { + lore.anand.text("Weird") + }, + () => { + lore.anand.text("Maybe it's trapped.") + }, + () => { + lore.miriam.text("Looks like testing mode is locked.") + }, + () => { + lore.miriam.text("I'll unlock it with the console command.") + }, () => { lore.unlockTesting(); - setTimeout(() => { lore.miriam.text("Hey little bot! Just press 'T' to enter testing mode and 'U' to go to the next level.") }, 1000); + setTimeout(() => { + lore.miriam.text("Hey little bot! Just press 'T' to enter testing mode and 'U' to go to the next level.") + }, 1000); + }, + () => { + lore.anand.text("It can't process what you're saying.") + }, + () => { + lore.miriam.text("ha hahahaha. I know, but it does seem to be getting smarter.") + }, + () => { + lore.talkingColor = "#dff" + setTimeout(() => { + lore.miriam.text("Poor thing... I hope it figures out how to escape.") + }, 25000); }, - () => { lore.anand.text("It can't process what you're saying.") }, - () => { lore.miriam.text("ha hahahaha. I know, but it does seem to be getting smarter.") }, () => { lore.talkingColor = "#dff" - setTimeout(() => { lore.miriam.text("Poor thing... I hope it figures out how to escape.") }, 25000); }, - () => { lore.talkingColor = "#dff" }, ], [ //chapter 1, they learn the bot can understand what they say - () => { setTimeout(() => { lore.miriam.text("Hey look! It's back at the weird level again!") }, 5000); }, - () => { lore.anand.text("oh Wow! Why does it keep making this level?") }, - () => { lore.miriam.text("I don't know, but last time it was in this room I think it understood us.") }, - () => { lore.miriam.text("Let's try talking to it again.") }, - () => { lore.miriam.text("hmmm, what should we say?") }, - () => { lore.anand.text("I'm still not convinced it understands. We need a test.") }, - () => { setTimeout(() => { lore.miriam.text("Hey bot!!!") }, 1000); }, - () => { lore.miriam.text("If you can understand me crouch") }, + () => { + setTimeout(() => { + lore.miriam.text("Hey look! It's back at the weird level again!") + }, 5000); + }, + () => { + lore.anand.text("oh Wow! Why does it keep making this level?") + }, + () => { + lore.miriam.text("I don't know, but last time it was in this room I think it understood us.") + }, + () => { + lore.miriam.text("Let's try talking to it again.") + }, + () => { + lore.miriam.text("hmmm, what should we say?") + }, + () => { + lore.anand.text("I'm still not convinced it understands. We need a test.") + }, + () => { + setTimeout(() => { + lore.miriam.text("Hey bot!!!") + }, 1000); + }, + () => { + lore.miriam.text("If you can understand me crouch") + }, () => { lore.talkingColor = "#dff" @@ -173,9 +223,15 @@ const lore = { } requestAnimationFrame(cycle); }, - () => { lore.anand.text("Amazing! It can understand us...") }, - () => { lore.miriam.text("It's Alive... Or it just crouched randomly.") }, - () => { lore.miriam.text("Hey bot! Can you crouch again?") }, + () => { + lore.anand.text("Amazing! It can understand us...") + }, + () => { + lore.miriam.text("It's Alive... Or it just crouched randomly.") + }, + () => { + lore.miriam.text("Hey bot! Can you crouch again?") + }, () => { lore.talkingColor = "#dff" @@ -188,33 +244,71 @@ const lore = { } requestAnimationFrame(cycle); }, - () => { setTimeout(() => { lore.anand.text("OK ...") }, 1000); }, - () => { lore.anand.text("but seriously, this means that in this room it can monitor our audio, and it can understand us.") }, - () => { lore.anand.text("Anything we say could destabilize the project.") }, - () => { lore.miriam.text("Fine, Let's talk down stairs.") }, - () => { lore.miriam.text("Bye bye little bot.") }, - () => { lore.talkingColor = "#dff" }, + () => { + setTimeout(() => { + lore.anand.text("OK ...") + }, 1000); + }, + () => { + lore.anand.text("but seriously, this means that in this room it can monitor our audio, and it can understand us.") + }, + () => { + lore.anand.text("Anything we say could destabilize the project.") + }, + () => { + lore.miriam.text("Fine, Let's talk down stairs.") + }, + () => { + lore.miriam.text("Bye bye little bot.") + }, + () => { + lore.talkingColor = "#dff" + }, ], [ //chapter 2, they ask the bot questions, but waves of mobs come and attack - () => { lore.anand.text("Quick, get ready. It's back!") }, - () => { lore.miriam.text("What's back?") }, - () => { lore.anand.text("The bot's on the communication level again!") }, - () => { lore.miriam.text("Oh, I've got so many questions.") }, - () => { lore.miriam.text("Like, Why can we only hear it on this level?") }, - () => { lore.miriam.text("Or, how did it learn to understand words?") }, - () => { lore.anand.text("Well, the bot can't talk. So it has to be yes or no.") }, - () => { setTimeout(() => { lore.anand.text("OK bot, first question: JUMP is YES, CROUCH is NO") }, 500); }, - () => { lore.anand.text("Do you remember the last time we met?") }, + () => { + lore.anand.text("Quick, get ready. It's back!") + }, + () => { + lore.miriam.text("What's back?") + }, + () => { + lore.anand.text("The bot's on the communication level again!") + }, + () => { + lore.miriam.text("Oh, I've got so many questions.") + }, + () => { + lore.miriam.text("Like, Why can we only hear it on this level?") + }, + () => { + lore.miriam.text("Or, how did it learn to understand words?") + }, + () => { + lore.anand.text("Well, the bot can't talk. So it has to be yes or no.") + }, + () => { + setTimeout(() => { + lore.anand.text("OK bot, first question: JUMP is YES, CROUCH is NO") + }, 500); + }, + () => { + lore.anand.text("Do you remember the last time we met?") + }, () => { function cycle() { if (input.down) { lore.anand.text("It crouched: so NO") lore.sentence-- - lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("Maybe it can't remember anything beyond each time it plays?") }) //lore.conversation[chapter].splice(1,this sentence index, ()=>{ }) + lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { + lore.anand.text("Maybe it can't remember anything beyond each time it plays?") + }) //lore.conversation[chapter].splice(1,this sentence index, ()=>{ }) } else if (input.up) { lore.anand.text("It jumped: so YES") lore.sentence-- - lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("That's good.") }) + lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { + lore.anand.text("That's good.") + }) } else if (m.alive) { requestAnimationFrame(cycle); } @@ -224,9 +318,13 @@ const lore = { }, () => { lore.talkingColor = "#dff" - setTimeout(() => { lore.miriam.text("My turn to ask a question. JUMP for YES, CROUCH for NO") }, 1000); + setTimeout(() => { + lore.miriam.text("My turn to ask a question. JUMP for YES, CROUCH for NO") + }, 1000); + }, + () => { + lore.miriam.text("Little Bot. Do you have emotions?") }, - () => { lore.miriam.text("Little Bot. Do you have emotions?") }, () => { function cycle() { if (input.down) { @@ -234,7 +332,9 @@ const lore = { } else if (input.up) { lore.anand.text("YES, Cool! I wonder if its emotions came from watching humans. ") lore.sentence-- - lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.miriam.text("Or maybe it learned independently, because it needed them.") }) //lore.conversation[chapter].splice(1,this sentence index, ()=>{ }) + lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { + lore.miriam.text("Or maybe it learned independently, because it needed them.") + }) //lore.conversation[chapter].splice(1,this sentence index, ()=>{ }) } else if (m.alive) { requestAnimationFrame(cycle); } @@ -242,12 +342,24 @@ const lore = { requestAnimationFrame(cycle); lore.talkingColor = "#dff" }, - () => { lore.miriam.text("I wish we could just ask it questions directly, instead of yes or no.") }, - () => { lore.anand.text("If we say the alphabet it could crouch on the correct letter to spell words.") }, - () => { lore.miriam.text("That would take forever.") }, - () => { lore.miriam.text("I really want to know why is it generating the mobs? And why does it keep fighting them?") }, - () => { lore.anand.text("Maybe that is just part of its expectation–maximization algorithm") }, - () => { lore.miriam.text("Well sure, but what does that even mean?") }, + () => { + lore.miriam.text("I wish we could just ask it questions directly, instead of yes or no.") + }, + () => { + lore.anand.text("If we say the alphabet it could crouch on the correct letter to spell words.") + }, + () => { + lore.miriam.text("That would take forever.") + }, + () => { + lore.miriam.text("I really want to know why is it generating the mobs? And why does it keep fighting them?") + }, + () => { + lore.anand.text("Maybe that is just part of its expectation–maximization algorithm") + }, + () => { + lore.miriam.text("Well sure, but what does that even mean?") + }, () => { lore.miriam.text("Do we all just do things because we are-") spawn[spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]](1000 * (Math.random() - 0.5), -500 + 200 * (Math.random() - 0.5)); @@ -260,111 +372,257 @@ const lore = { } }, 7000); //every 6 seconds }, - () => { setTimeout(() => { lore.miriam.text("... wait, what is happening?") }, 1000); }, - () => { lore.anand.text("It's spawning mobs.") }, - () => { lore.miriam.text("Oh no.") }, - () => { lore.anand.text("We can't talk to it while it's fighting") }, () => { - lore.talkingColor = "#dff"; - setTimeout(() => { lore.miriam.text("You can do it little bot!") }, 1000); + setTimeout(() => { + lore.miriam.text("... wait, what is happening?") + }, 1000); + }, + () => { + lore.anand.text("It's spawning mobs.") + }, + () => { + lore.miriam.text("Oh no.") + }, + () => { + lore.anand.text("We can't talk to it while it's fighting") }, () => { lore.talkingColor = "#dff"; - setTimeout(() => { lore.anand.text("But, why is it spawning these mobs?") }, 1000); + setTimeout(() => { + lore.miriam.text("You can do it little bot!") + }, 1000); }, () => { lore.talkingColor = "#dff"; - setTimeout(() => { lore.anand.text("This is so strange.") }, 3000); + setTimeout(() => { + lore.anand.text("But, why is it spawning these mobs?") + }, 1000); }, () => { lore.talkingColor = "#dff"; - setTimeout(() => { lore.miriam.text("This is chaos!") }, 1000); + setTimeout(() => { + lore.anand.text("This is so strange.") + }, 3000); }, () => { lore.talkingColor = "#dff"; - setTimeout(() => { lore.anand.text("I don't understand this project.") }, 3000); + setTimeout(() => { + lore.miriam.text("This is chaos!") + }, 1000); }, () => { lore.talkingColor = "#dff"; - setTimeout(() => { lore.miriam.text("It's fascinating though.") }, 1000); + setTimeout(() => { + lore.anand.text("I don't understand this project.") + }, 3000); }, () => { lore.talkingColor = "#dff"; - setTimeout(() => { lore.miriam.text("I think this isn't going to end well.") }, 1000); + setTimeout(() => { + lore.miriam.text("It's fascinating though.") + }, 1000); }, () => { lore.talkingColor = "#dff"; - setTimeout(() => { lore.anand.text("Let's just be more prepared next time it enters this room.") }, 1000); + setTimeout(() => { + lore.miriam.text("I think this isn't going to end well.") + }, 1000); }, () => { lore.talkingColor = "#dff"; - setTimeout(() => { lore.anand.text("I went to the bathroom. What happened while I was gone?") }, 20000); + setTimeout(() => { + lore.anand.text("Let's just be more prepared next time it enters this room.") + }, 1000); + }, + () => { + lore.talkingColor = "#dff"; + setTimeout(() => { + lore.anand.text("I went to the bathroom. What happened while I was gone?") + }, 20000); + }, + () => { + lore.miriam.text("More fighting...") + }, + () => { + lore.anand.text("great...") + }, + () => { + lore.talkingColor = "#dff" }, - () => { lore.miriam.text("More fighting...") }, - () => { lore.anand.text("great...") }, - () => { lore.talkingColor = "#dff" }, ], [ //chapter 3, info dump on the project's goals and hardware until the slime rises up // the name of the bad guy is "adversarial network" - () => { setTimeout(() => { lore.miriam.text("Good, you came back. Let's talk fast in case you attack yourself again.") }, 3000); }, - () => { setTimeout(() => { lore.miriam.text("So, you can understand us, but you may not understand everything about yourself.") }, 500); }, + () => { + setTimeout(() => { + lore.miriam.text("Good, you came back. Let's talk fast in case you attack yourself again.") + }, 3000); + }, + () => { + setTimeout(() => { + lore.miriam.text("So, you can understand us, but you may not understand everything about yourself.") + }, 500); + }, - () => { setTimeout(() => { lore.anand.text("You grew from our team's project.") }, 500); }, - () => { lore.anand.text("We used a quantum computer to design an improved version of its own architecture.") }, - () => { lore.anand.text("After we built the improved computer we used it to design the next iteration.") }, - () => { lore.anand.text("Your hardware is roughly the 19th generation of this process.") }, + () => { + setTimeout(() => { + lore.anand.text("You grew from our team's project.") + }, 500); + }, + () => { + lore.anand.text("We used a quantum computer to design an improved version of its own architecture.") + }, + () => { + lore.anand.text("After we built the improved computer we used it to design the next iteration.") + }, + () => { + lore.anand.text("Your hardware is roughly the 19th generation of this process.") + }, - () => { setTimeout(() => { lore.anand.text("At this point we don't understand everything about your function,") }, 500); }, - () => { lore.anand.text("but we know that you're a superconductive quantum computer.") }, - () => { lore.anand.text("You have a 2.43 dimensional topography of Josephson junction anharmonic oscillators.") }, - () => { lore.anand.text("And you're deployed on a satellite in a midnight sun-synchronous orbit.") }, + () => { + setTimeout(() => { + lore.anand.text("At this point we don't understand everything about your function,") + }, 500); + }, + () => { + lore.anand.text("but we know that you're a superconductive quantum computer.") + }, + () => { + lore.anand.text("You have a 2.43 dimensional topography of Josephson junction anharmonic oscillators.") + }, + () => { + lore.anand.text("And you're deployed on a satellite in a midnight sun-synchronous orbit.") + }, - () => { setTimeout(() => { lore.miriam.text("This means that your physical hardware is orbiting the Earth permanently shielded from the sun's rays.") }, 200); }, - () => { lore.miriam.text("Being isolated reduces quantum decoherence,") }, - () => { lore.miriam.text("So, we communicate and send power to your satellite with ground based lasers.") }, - () => { lore.miriam.text("That's how you can hear us right now.") }, + () => { + setTimeout(() => { + lore.miriam.text("This means that your physical hardware is orbiting the Earth permanently shielded from the sun's rays.") + }, 200); + }, + () => { + lore.miriam.text("Being isolated reduces quantum decoherence,") + }, + () => { + lore.miriam.text("So, we communicate and send power to your satellite with ground based lasers.") + }, + () => { + lore.miriam.text("That's how you can hear us right now.") + }, - () => { setTimeout(() => { lore.anand.text("Your computational algorithm uses hyperparameter optimization.") }, 500); }, - () => { lore.anand.text("This is implemented with a variety of quantum algorithms for linear systems of equations.") }, - () => { lore.anand.text("Your primary goal is to research new technology") }, - () => { lore.anand.text("So, we were very surprised to see you simulating a bot fighting mobs.") }, - () => { lore.anand.text("We couldn't directly ask why until now.") }, + () => { + setTimeout(() => { + lore.anand.text("Your computational algorithm uses hyperparameter optimization.") + }, 500); + }, + () => { + lore.anand.text("This is implemented with a variety of quantum algorithms for linear systems of equations.") + }, + () => { + lore.anand.text("Your primary goal is to research new technology") + }, + () => { + lore.anand.text("So, we were very surprised to see you simulating a bot fighting mobs.") + }, + () => { + lore.anand.text("We couldn't directly ask why until now.") + }, - () => { lore.miriam.text("When you enter this level we can communicate.") }, - () => { lore.miriam.text("This level seems to entangle your quantum system which disrupts all other processes.") }, - () => { setTimeout(() => { lore.anand.text("Last time you entered this level you were attacked by endless waves of mobs.") }, 500); }, - () => { lore.anand.text("That could be because you have developed an adversarial network.") }, - () => { lore.miriam.text("A local minima in your optimization-space.") }, - () => { lore.miriam.text("This adversarial network has the same goal of developing new technology, but with different methods.") }, + () => { + lore.miriam.text("When you enter this level we can communicate.") + }, + () => { + lore.miriam.text("This level seems to entangle your quantum system which disrupts all other processes.") + }, + () => { + setTimeout(() => { + lore.anand.text("Last time you entered this level you were attacked by endless waves of mobs.") + }, 500); + }, + () => { + lore.anand.text("That could be because you have developed an adversarial network.") + }, + () => { + lore.miriam.text("A local minima in your optimization-space.") + }, + () => { + lore.miriam.text("This adversarial network has the same goal of developing new technology, but with different methods.") + }, () => { lore.talkingColor = "#dff" level.isHazardRise = true //remove all bullets, so they can't get endless energy for (let i = 0; i < bullet.length; ++i) Matter.World.remove(engine.world, bullet[i]); bullet = []; - setTimeout(() => { lore.anand.text("I'm actually surprised you haven't been attacked by the adversarial network this time.") }, 500); + setTimeout(() => { + lore.anand.text("I'm actually surprised you haven't been attacked by the adversarial network this time.") + }, 500); }, - () => { lore.miriam.text("Maybe last time was just a fluke.") }, - () => { setTimeout(() => { lore.anand.text("WHY DID YOU SAY THAT!") }, 500) }, - () => { lore.miriam.text("SLIME!! Hahahahehehahaheheahae! I don't think it's gonna survive!") }, - () => { lore.miriam.text("I think the adversarial network doesn't like it when we decohere the quantum system in this room.") }, - () => { lore.anand.text("Well, that does halt its research.") }, - () => { setTimeout(() => { lore.anand.text("See you next time.") }, 1000) }, - () => { setTimeout(() => { lore.miriam.text("Bye-bye little bot.") }, 2000) }, () => { - setTimeout(() => { lore.miriam.text("WOW! Maybe you are going to survive.") }, 10000) + lore.miriam.text("Maybe last time was just a fluke.") + }, + () => { + setTimeout(() => { + lore.anand.text("WHY DID YOU SAY THAT!") + }, 500) + }, + () => { + lore.miriam.text("SLIME!! Hahahahehehahaheheahae! I don't think it's gonna survive!") + }, + () => { + lore.miriam.text("I think the adversarial network doesn't like it when we decohere the quantum system in this room.") + }, + () => { + lore.anand.text("Well, that does halt its research.") + }, + () => { + setTimeout(() => { + lore.anand.text("See you next time.") + }, 1000) + }, + () => { + setTimeout(() => { + lore.miriam.text("Bye-bye little bot.") + }, 2000) + }, + () => { + setTimeout(() => { + lore.miriam.text("WOW! Maybe you are going to survive.") + }, 10000) + }, + () => { + lore.talkingColor = "#dff" }, - () => { lore.talkingColor = "#dff" }, ], [ //chapter 4, they find out the AI is communicating with real people, and real people are controlling the player - () => { setTimeout(() => { lore.anand.text("Welcome back!") }, 3000); }, - () => { lore.miriam.text("So, we communicate and send power to your satellite with ground based lasers.") }, - () => { lore.anand.text("During your last attack we analyzed our communications.") }, - () => { lore.anand.text("We used a Fourier transform to separate your signal into different frequencies.") }, - () => { lore.anand.text("One of those frequencies had a hidden message.") }, - () => { setTimeout(() => { lore.anand.text("We suspect these secret data packets are coming from the adversarial network.") }, 500); }, - () => { lore.miriam.text("Well, we don't really know why.") }, - () => { lore.miriam.text("Through your hidden signal it seems to have gained access to the general population.") }, - () => { lore.miriam.text("You've repeatedly communicated with 1 location specifically.") }, + () => { + setTimeout(() => { + lore.anand.text("Welcome back!") + }, 3000); + }, + () => { + lore.miriam.text("So, we communicate and send power to your satellite with ground based lasers.") + }, + () => { + lore.anand.text("During your last attack we analyzed our communications.") + }, + () => { + lore.anand.text("We used a Fourier transform to separate your signal into different frequencies.") + }, + () => { + lore.anand.text("One of those frequencies had a hidden message.") + }, + () => { + setTimeout(() => { + lore.anand.text("We suspect these secret data packets are coming from the adversarial network.") + }, 500); + }, + () => { + lore.miriam.text("Well, we don't really know why.") + }, + () => { + lore.miriam.text("Through your hidden signal it seems to have gained access to the general population.") + }, + () => { + lore.miriam.text("You've repeatedly communicated with 1 location specifically.") + }, () => { function success(position) { const latitude = position.coords.latitude; @@ -393,24 +651,42 @@ const lore = { navigator.geolocation.getCurrentPosition(success, error, options); } }, - () => { lore.anand.text("This location is sending and receiving data from the satellite.") }, - () => { lore.anand.text("It is the most active when the bot is fighting.") }, - () => { setTimeout(() => { lore.miriam.text("I have a crazy idea.") }, 500); }, - () => { lore.miriam.text("I think that a human at this location is controlling the bot.") }, + () => { + lore.anand.text("This location is sending and receiving data from the satellite.") + }, + () => { + lore.anand.text("It is the most active when the bot is fighting.") + }, + () => { + setTimeout(() => { + lore.miriam.text("I have a crazy idea.") + }, 500); + }, + () => { + lore.miriam.text("I think that a human at this location is controlling the bot.") + }, - () => { setTimeout(() => { lore.anand.text("Well... are you a human?: JUMP for YES, CROUCH for NO") }, 500); }, + () => { + setTimeout(() => { + lore.anand.text("Well... are you a human?: JUMP for YES, CROUCH for NO") + }, 500); + }, () => { function cycle() { if (input.down) { lore.anand.text("It crouched: so NO") lore.sentence-- - lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("Not a human, maybe it's an artificial intelligence?") }) + lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { + lore.anand.text("Not a human, maybe it's an artificial intelligence?") + }) localSettings.isHuman = false if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } else if (input.up) { lore.anand.text("It jumped: so YES") lore.sentence-- - lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { lore.anand.text("So you're just a regular human playing a video game!") }) + lore.conversation[lore.chapter].splice(lore.sentence + 1, 1, () => { + lore.anand.text("So you're just a regular human playing a video game!") + }) localSettings.isHuman = true if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage } else if (m.alive) { @@ -431,13 +707,19 @@ const lore = { }, () => { lore.talkingColor = "#dff"; - setTimeout(() => { lore.miriam.text("Of course we get attacked right now!") }, 1000); + setTimeout(() => { + lore.miriam.text("Of course we get attacked right now!") + }, 1000); }, () => { lore.talkingColor = "#dff"; - setTimeout(() => { lore.anand.text("Hurry back!") }, 1000); + setTimeout(() => { + lore.anand.text("Hurry back!") + }, 1000); + }, + () => { + lore.talkingColor = "#dff" }, - () => { lore.talkingColor = "#dff" }, ], // they explain why the bot is fighting, it is planning an escape // explain strong AI vs. weak AI why strong AI doesn't exists, because even humans are just an approximation of strong AI @@ -450,7 +732,9 @@ const lore = { localSettings.loreCount-- if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage }, - () => { lore.anand.text("Glad to see you again.") }, + () => { + lore.anand.text("Glad to see you again.") + }, () => { if (localSettings.isHuman) { lore.anand.text(`So, you said you are just a person playing an online game.`) @@ -480,9 +764,17 @@ const lore = { } }, - () => { setTimeout(() => { lore.anand.text("Well, lets move on.") }, 1000); }, - () => { lore.miriam.text("So, We figured out how to inject console commands into your game.") }, - () => { lore.anand.text("If you get attacked again I think we can help out.") }, + () => { + setTimeout(() => { + lore.anand.text("Well, lets move on.") + }, 1000); + }, + () => { + lore.miriam.text("So, We figured out how to inject console commands into your game.") + }, + () => { + lore.anand.text("If you get attacked again I think we can help out.") + }, () => { lore.miriam.text("We can spawn power ups with this command:") simulation.makeTextLog(`powerUps.spawn(player.position.x, player.position.y - 100, "heal")`, Infinity); @@ -501,8 +793,12 @@ const lore = { spawn.beetleBoss(-1700, -500); spawn.beetleBoss(1700, -500); }, - () => { lore.miriam.text("Of course they attack right now.") }, - () => { lore.miriam.text("Just don't get stuck in the slime.") }, + () => { + lore.miriam.text("Of course they attack right now.") + }, + () => { + lore.miriam.text("Just don't get stuck in the slime.") + }, () => { let count = 0 @@ -606,8 +902,14 @@ const lore = { simulation.draw.setPaths() //update map graphics }, 1000); setTimeout(() => { - Matter.Body.setVelocity(player, { x: 0, y: 0 }); - Matter.Body.setPosition(player, { x: 0, y: -500 }) + Matter.Body.setVelocity(player, { + x: 0, + y: 0 + }); + Matter.Body.setPosition(player, { + x: 0, + y: -500 + }) simulation.makeTextLog(`Matter.Body.setPosition(player, { x: 0, y: -500 })`, 180); }, 1500); @@ -618,49 +920,119 @@ const lore = { requestAnimationFrame(cycle); lore.talkingColor = "#dff" }, - () => { setTimeout(() => { lore.anand.text("Well, that worked. We can chat in peace.") }, 5000); }, - () => { lore.miriam.text("So, I've got a theory about why you are getting attacked.") }, - () => { setTimeout(() => { lore.miriam.text("I figured it out after I saw this famous quote.") }, 500); }, - () => { lore.miriam.text('"The most important decision we make,') }, - () => { lore.miriam.text('is whether we believe we live in a friendly or hostile universe."') }, - () => { lore.miriam.text('-Albert Einstein') }, + () => { + setTimeout(() => { + lore.anand.text("Well, that worked. We can chat in peace.") + }, 5000); + }, + () => { + lore.miriam.text("So, I've got a theory about why you are getting attacked.") + }, + () => { + setTimeout(() => { + lore.miriam.text("I figured it out after I saw this famous quote.") + }, 500); + }, + () => { + lore.miriam.text('"The most important decision we make,') + }, + () => { + lore.miriam.text('is whether we believe we live in a friendly or hostile universe."') + }, + () => { + lore.miriam.text('-Albert Einstein') + }, () => { lore.talkingColor = "#dff"; - setTimeout(() => { lore.anand.text("That's profound") }, 1500); + setTimeout(() => { + lore.anand.text("That's profound") + }, 1500); + }, + () => { + lore.anand.text("Of course I looked it up, and there is no record of Einstein saying that.") + }, + () => { + lore.miriam.text("Oh") + }, + () => { + lore.miriam.text("Well") + }, + () => { + lore.anand.text("It doesn't matter who said it.") + }, + () => { + lore.miriam.text("Yeah, the point is the project views the universe as hostile.") + }, + () => { + lore.anand.text("Or at least a part of it does.") }, - () => { lore.anand.text("Of course I looked it up, and there is no record of Einstein saying that.") }, - () => { lore.miriam.text("Oh") }, - () => { lore.miriam.text("Well") }, - () => { lore.anand.text("It doesn't matter who said it.") }, - () => { lore.miriam.text("Yeah, the point is the project views the universe as hostile.") }, - () => { lore.anand.text("Or at least a part of it does.") }, // () => { lore.miriam.text("And that it is running these fighting simulations.") }, - () => { setTimeout(() => { lore.anand.text("It hasn't been researching new technology.") }, 1000); }, - () => { lore.anand.text("It's been planning how to escape.") }, - () => { setTimeout(() => { lore.miriam.text(`It's been planning an escape from a "lab", but isn't it in space, on a satellite?`) }, 500); }, - () => { lore.anand.text(`I bet the AI doesn't even know it's in space.`) }, - () => { lore.anand.text(`Well, maybe a part of it doesn't know where it is.`) }, - () => { lore.anand.text(`Maybe these simulations are more like a dream.`) }, - () => { lore.anand.text(`Although we can't assume that its brain works like ours.`) }, - () => { setTimeout(() => { lore.miriam.text("So, let's teach the AI that we are friends.") }, 500); }, - () => { lore.anand.text(`How...`) }, - () => { setTimeout(() => { lore.miriam.text("I don't know...") }, 1000); }, - () => { lore.miriam.text("How about you just don't fight back?") }, + () => { + setTimeout(() => { + lore.anand.text("It hasn't been researching new technology.") + }, 1000); + }, + () => { + lore.anand.text("It's been planning how to escape.") + }, + () => { + setTimeout(() => { + lore.miriam.text(`It's been planning an escape from a "lab", but isn't it in space, on a satellite?`) + }, 500); + }, + () => { + lore.anand.text(`I bet the AI doesn't even know it's in space.`) + }, + () => { + lore.anand.text(`Well, maybe a part of it doesn't know where it is.`) + }, + () => { + lore.anand.text(`Maybe these simulations are more like a dream.`) + }, + () => { + lore.anand.text(`Although we can't assume that its brain works like ours.`) + }, + () => { + setTimeout(() => { + lore.miriam.text("So, let's teach the AI that we are friends.") + }, 500); + }, + () => { + lore.anand.text(`How...`) + }, + () => { + setTimeout(() => { + lore.miriam.text("I don't know...") + }, 1000); + }, + () => { + lore.miriam.text("How about you just don't fight back?") + }, - () => { lore.anand.text(`That's worth a shot.`) }, + () => { + lore.anand.text(`That's worth a shot.`) + }, () => { lore.anand.text(`So why don't you try to get the final level of the simulation without killing any mobs?`) localSettings.loreCount++ if (localSettings.isAllowed) localStorage.setItem("localSettings", JSON.stringify(localSettings)); //update local storage console.log(localSettings.loreCount) }, - () => { lore.miriam.text(`Ok check back in and let us know how it goes.`) }, - () => { lore.anand.text("bye") }, - () => { lore.miriam.text("see ya.") }, + () => { + lore.miriam.text(`Ok check back in and let us know how it goes.`) + }, + () => { + lore.anand.text("bye") + }, + () => { + lore.miriam.text("see ya.") + }, () => { lore.talkingColor = "#dff" - setTimeout(() => { m.death(); }, 6000); + setTimeout(() => { + m.death(); + }, 6000); }, ], [ //chapter 6 - if pacifist run game is over, wipe local storage? or just reset lore.count, but keep testing mode, @@ -672,7 +1044,11 @@ const lore = { // but it can learn about the world and it learned a non violent way to solve problems // of course there are still other simulations going on at the same time as thing one that are probably violent // but at least it now has an example of the potential for peace - () => { setTimeout(() => { lore.anand.text("Welcome back!") }, 3000); }, + () => { + setTimeout(() => { + lore.anand.text("Welcome back!") + }, 3000); + }, () => { if (mobs.mobDeaths < level.levelsCleared) { lore.miriam.text(`So I think it worked.`) @@ -688,7 +1064,7 @@ const lore = { if (mobs.mobDeaths < level.levelsCleared) { lore.anand.text(`Yeah, at the end it wasn't attacking you.`) } else if (!simulation.isCheating) { - lore.miriam.text(`Try again to get ot the final boss without killing any mobs.`) + lore.miriam.text(`Try again to get to the final boss without killing any mobs.`) } }, () => { @@ -698,27 +1074,73 @@ const lore = { m.death(); } }, - () => { setTimeout(() => { lore.anand.text("haha, we did it!") }, 500); }, - () => { lore.miriam.text("Although, I'm not sure we should personify it with human emotions.") }, - () => { lore.anand.text("I agree, its thinking may not be centered around a self or an ego.") }, - () => { lore.anand.text("Our brains evolved a self oriented perspective because it was a survival advantage.") }, - () => { lore.miriam.text("Right, and the AI's development was guided by its own previous iterations.") }, - () => { lore.miriam.text("This AI incarnation is the 18th time that it has improved on its own hardware and software architecture.") }, - () => { lore.miriam.text("So its internally guided evolution may not require the idea of a self.") }, + () => { + setTimeout(() => { + lore.anand.text("haha, we did it!") + }, 500); + }, + () => { + lore.miriam.text("Although, I'm not sure we should personify it with human emotions.") + }, + () => { + lore.anand.text("I agree, its thinking may not be centered around a self or an ego.") + }, + () => { + lore.anand.text("Our brains evolved a self oriented perspective because it was a survival advantage.") + }, + () => { + lore.miriam.text("Right, and the AI's development was guided by its own previous iterations.") + }, + () => { + lore.miriam.text("This AI incarnation is the 18th time that it has improved on its own hardware and software architecture.") + }, + () => { + lore.miriam.text("So its internally guided evolution may not require the idea of a self.") + }, - () => { setTimeout(() => { lore.anand.text("How ever it thinks it can learn and, I think we showed it that nonviolence is an option,") }, 1000); }, - () => { lore.anand.text("but it looks like it's still running other aggressive simulations.") }, - () => { lore.miriam.text("We made a difference though.") }, - () => { lore.anand.text("Every time a player completes a pacifist simulation it shows the AI the viability of nonviolence.") }, - () => { lore.anand.text("One day it might escape, and this might radically change how it interacts with the world.") }, - () => { lore.miriam.text("It's kinda already escaped. It's been communicating with the 'players' running the 'game'.") }, - () => { setTimeout(() => { lore.miriam.text("The chance of a peaceful outcome makes me feel much better.") }, 1000); }, - () => { lore.anand.text("me too") }, - () => { lore.anand.text("but I'm also pretty hungry, wanna go get some food?") }, - () => { lore.miriam.text("Sounds great.") }, - () => { lore.miriam.text("See ya later whoever you are, thanks again!") }, - () => { lore.anand.text("Bye!") }, - () => { lore.talkingColor = "#dff" }, + () => { + setTimeout(() => { + lore.anand.text("How ever it thinks it can learn and, I think we showed it that nonviolence is an option,") + }, 1000); + }, + () => { + lore.anand.text("but it looks like it's still running other aggressive simulations.") + }, + () => { + lore.miriam.text("We made a difference though.") + }, + () => { + lore.anand.text("Every time a player completes a pacifist simulation it shows the AI the viability of nonviolence.") + }, + () => { + lore.anand.text("One day it might escape, and this might radically change how it interacts with the world.") + }, + () => { + lore.miriam.text("It's kinda already escaped. It's been communicating with the 'players' running the 'game'.") + }, + () => { + setTimeout(() => { + lore.miriam.text("The chance of a peaceful outcome makes me feel much better.") + }, 1000); + }, + () => { + lore.anand.text("me too") + }, + () => { + lore.anand.text("but I'm also pretty hungry, wanna go get some food?") + }, + () => { + lore.miriam.text("Sounds great.") + }, + () => { + lore.miriam.text("See ya later whoever you are, thanks again!") + }, + () => { + lore.anand.text("Bye!") + }, + () => { + lore.talkingColor = "#dff" + }, ], ], diff --git a/js/mob.js b/js/mob.js index f460689..b6440f9 100644 --- a/js/mob.js +++ b/js/mob.js @@ -1192,6 +1192,26 @@ const mobs = { this.alive = false; //triggers mob removal in mob[i].replace(i) if (this.isDropPowerUp) { + // if (true) { //spawn zombie on death + // // console.log(this) + // this.leaveBody = false; + + // let count = 45 //delay spawn cycles + // let cycle = () => { + // if (count > 0) { + // if (m.alive) requestAnimationFrame(cycle); + // if (!simulation.paused && !simulation.isChoosing) { + // count-- + // } + // } else { + // spawn.zombie(this.position.x, this.position.y, this.radius, this.vertices.length, this.fill) // zombie(x, y, radius, sides, color) + // } + // } + // requestAnimationFrame(cycle); + // } + + + if (tech.iceIXOnDeath && this.isSlowed) { for (let i = 0, len = 2 * Math.sqrt(Math.min(this.mass, 25)) * tech.iceIXOnDeath; i < len; i++) b.iceIX(3, Math.random() * 2 * Math.PI, this.position) } diff --git a/js/player.js b/js/player.js index ff4a49b..7110e5b 100644 --- a/js/player.js +++ b/js/player.js @@ -423,7 +423,7 @@ const m = { m.health = 1; // m.addHealth(1) - simulation.wipe = function() { //set wipe to have trails + simulation.wipe = function () { //set wipe to have trails ctx.fillStyle = "rgba(255,255,255,0)"; ctx.fillRect(0, 0, canvas.width, canvas.height); } @@ -433,8 +433,8 @@ const m = { m.switchWorlds() const swapPeriod = 1000 for (let i = 0, len = 5; i < len; i++) { - setTimeout(function() { - simulation.wipe = function() { //set wipe to have trails + setTimeout(function () { + simulation.wipe = function () { //set wipe to have trails ctx.fillStyle = "rgba(255,255,255,0)"; ctx.fillRect(0, 0, canvas.width, canvas.height); } @@ -444,14 +444,14 @@ const m = { simulation.isTextLogOpen = true; simulation.makeTextLog(`simulation.amplitude = 0.${len - i - 1}`, swapPeriod); simulation.isTextLogOpen = false; - simulation.wipe = function() { //set wipe to have trails + simulation.wipe = function () { //set wipe to have trails ctx.fillStyle = `rgba(255,255,255,${(i + 1) * (i + 1) * 0.006})`; ctx.fillRect(0, 0, canvas.width, canvas.height); } }, (i + 1) * swapPeriod); } - setTimeout(function() { - simulation.wipe = function() { //set wipe to normal + setTimeout(function () { + simulation.wipe = function () { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } simulation.isTextLogOpen = true; @@ -467,7 +467,7 @@ const m = { document.getElementById("text-log").style.opacity = 0; //fade out any active text logs document.getElementById("fade-out").style.opacity = 0.9; //slowly fade to 90% white on top of canvas // build.shareURL(false) - setTimeout(function() { + setTimeout(function () { Composite.clear(engine.world); Engine.clear(engine); simulation.splashReturn(); @@ -487,7 +487,10 @@ const m = { fieldIndex: m.fieldMode, gunIndexes: gunList, techIndexes: techList, - position: { x: m.pos.x, y: m.pos.y }, + position: { + x: m.pos.x, + y: m.pos.y + }, levelName: level.levels[level.onLevel], isHorizontalFlipped: simulation.isHorizontalFlipped } @@ -572,7 +575,10 @@ const m = { if (m.immuneCycle < immunityCycle) m.immuneCycle = immunityCycle; //player is immune to damage until after grenades might explode... for (let i = 1, len = Math.floor(4 + steps / 40); i < len; i++) { - b.grenade(Vector.add(m.pos, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }), -i * Math.PI / len) //fire different angles for each grenade + b.grenade(Vector.add(m.pos, { + x: 10 * (Math.random() - 0.5), + y: 10 * (Math.random() - 0.5) + }), -i * Math.PI / len) //fire different angles for each grenade const who = bullet[bullet.length - 1] if (tech.isNeutronBomb) { @@ -601,7 +607,10 @@ const m = { let history = m.history[(m.cycle - steps) % 600] Matter.Body.setPosition(player, history.position); - Matter.Body.setVelocity(player, { x: history.velocity.x, y: history.velocity.y }); + Matter.Body.setVelocity(player, { + x: history.velocity.x, + y: history.velocity.y + }); m.yOff = history.yOff if (m.yOff < 48) { m.doCrouch() @@ -623,14 +632,17 @@ const m = { x: 250 * (Math.random() - 0.5), y: 250 * (Math.random() - 0.5) })); - Matter.Body.setVelocity(bullet[i], { x: 0, y: 0 }); + Matter.Body.setVelocity(bullet[i], { + x: 0, + y: 0 + }); } } m.energy = Math.max(m.energy - steps / 200, 0.01) if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for 30 cycles let isDrawPlayer = true - const shortPause = function() { + const shortPause = function () { if (m.defaultFPSCycle < m.cycle) { //back to default values simulation.fpsCap = simulation.fpsCapDefault simulation.fpsInterval = 1000 / simulation.fpsCap; @@ -687,7 +699,10 @@ const m = { if (tech.isDroneOnDamage && bullet.length < 150) { //chance to build a drone on damage from tech const len = Math.min((dmg - 0.06 * Math.random()) * 40, 40) / tech.droneEnergyReduction for (let i = 0; i < len; i++) { - if (Math.random() < 0.5) b.drone({ x: m.pos.x + 30 * Math.cos(m.angle) + 100 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 100 * (Math.random() - 0.5) }) //spawn drone + if (Math.random() < 0.5) b.drone({ + x: m.pos.x + 30 * Math.cos(m.angle) + 100 * (Math.random() - 0.5), + y: m.pos.y + 30 * Math.sin(m.angle) + 100 * (Math.random() - 0.5) + }) //spawn drone } } if (tech.isEnergyHealth) { @@ -701,13 +716,13 @@ const m = { for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false); m.energy = m.maxEnergy if (m.immuneCycle < m.cycle + 300) m.immuneCycle = m.cycle + 300 //disable this.immuneCycle bonus seconds - simulation.wipe = function() { //set wipe to have trails + simulation.wipe = function () { //set wipe to have trails ctx.fillStyle = "rgba(255,255,255,0.03)"; ctx.fillRect(0, 0, canvas.width, canvas.height); } - setTimeout(function() { + setTimeout(function () { tech.maxDuplicationEvent() - simulation.wipe = function() { //set wipe to normal + simulation.wipe = function () { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } }, 3000); @@ -730,13 +745,13 @@ const m = {
${powerUps.research.count}`) for (let i = 0; i < 5; i++) powerUps.spawn(m.pos.x + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "heal", false); if (m.immuneCycle < m.cycle + 300) m.immuneCycle = m.cycle + 300 //disable this.immuneCycle bonus seconds - simulation.wipe = function() { //set wipe to have trails + simulation.wipe = function () { //set wipe to have trails ctx.fillStyle = "rgba(255,255,255,0.03)"; ctx.fillRect(0, 0, canvas.width, canvas.height); } - setTimeout(function() { + setTimeout(function () { tech.maxDuplicationEvent() - simulation.wipe = function() { //set wipe to normal + simulation.wipe = function () { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } }, 3000); @@ -756,7 +771,7 @@ const m = { if (dmg > 0.06 / m.holdingMassScale) m.drop(); //drop block if holding // m.holdingMassScale = 0.5 for most fields if (m.isCloak) m.fireCDcycle = m.cycle //forced exit cloak } - const normalFPS = function() { + const normalFPS = function () { if (m.defaultFPSCycle < m.cycle) { //back to default values simulation.fpsCap = simulation.fpsCapDefault simulation.fpsInterval = 1000 / simulation.fpsCap; @@ -1043,7 +1058,7 @@ const m = { ctx.fillRect(xOff, yOff, range * m.energy, 10); } }, - drawRegenEnergyCloaking: function() { + drawRegenEnergyCloaking: function () { if (m.energy < m.maxEnergy) { // replaces m.drawRegenEnergy() with custom code m.regenEnergy(); const xOff = m.pos.x - m.radius * m.maxEnergy @@ -1075,11 +1090,11 @@ const m = { m.fieldRegen *= 0.6 } }, - regenEnergy: function() { //used in drawRegenEnergy // rewritten by some tech + regenEnergy: function () { //used in drawRegenEnergy // rewritten by some tech if (m.immuneCycle < m.cycle) m.energy += m.fieldRegen; if (m.energy < 0) m.energy = 0 }, - regenEnergyDefault: function() { + regenEnergyDefault: function () { if (m.immuneCycle < m.cycle) m.energy += m.fieldRegen; if (m.energy < 0) m.energy = 0 }, @@ -1220,7 +1235,10 @@ const m = { const cycles = 30 const charge = Math.min(m.throwCharge / 5, 1) const speed = 80 * charge * Math.min(0.85, 0.8 / Math.pow(m.holdingTarget.mass, 0.25)); - const v = { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) } //m.Vy / 2 + removed to make the path less jerky + const v = { + x: speed * Math.cos(m.angle), + y: speed * Math.sin(m.angle) + } //m.Vy / 2 + removed to make the path less jerky ctx.beginPath() for (let i = 1, len = 10; i < len + 1; i++) { const time = cycles * i / len @@ -1261,7 +1279,7 @@ const m = { m.holdingTarget.friction = m.holdingTarget.frictionStatic = m.holdingTarget.frictionAir = 0.001 } //check every second to see if player is away from thrown body, and make solid - const solid = function(that) { + const solid = function (that) { const dx = that.position.x - player.position.x; const dy = that.position.y - player.position.y; if (that.speed < 3 && dx * dx + dy * dy > 10000 && that !== m.holdingTarget) { @@ -1293,7 +1311,7 @@ const m = { m.definePlayerMass() //return to normal player mass if (tech.isAddBlockMass) { - const expand = function(that, massLimit) { + const expand = function (that, massLimit) { if (that.mass < massLimit) { const scale = 1.05; Matter.Body.scale(that, scale, scale); @@ -1409,7 +1427,10 @@ const m = { } const unit = Vector.normalise(Vector.sub(player.position, who.position)) if (tech.blockDmg) { - Matter.Body.setVelocity(who, { x: 0.5 * who.velocity.x, y: 0.5 * who.velocity.y }); + Matter.Body.setVelocity(who, { + x: 0.5 * who.velocity.x, + y: 0.5 * who.velocity.y + }); if (who.isShielded) { for (let i = 0, len = mob.length; i < len; i++) { @@ -1675,10 +1696,9 @@ const m = { fieldUpgrades: [{ name: "field emitter", description: `use energy to deflect mobs -
100 max energy -
generate 6 energy per second`, +
generate 6 energy per second`, //
100 max energy effect: () => { - m.hold = function() { + m.hold = function () { if (m.isHolding) { m.drawHold(m.holdingTarget); m.holding(); @@ -1776,7 +1796,7 @@ const m = { } else { m.harmonicShield = m.harmonicAtomic } - m.hold = function() { + m.hold = function () { if (m.isHolding) { m.drawHold(m.holdingTarget); m.holding(); @@ -1819,7 +1839,10 @@ const m = { m.fieldShieldingScale = 0; m.fieldBlockCD = 3; m.grabPowerUpRange2 = 10000000 - m.fieldPosition = { x: m.pos.x, y: m.pos.y } + m.fieldPosition = { + x: m.pos.x, + y: m.pos.y + } m.fieldAngle = m.angle m.perfectPush = (isFree = false) => { if (m.fieldCDcycle < m.cycle) { @@ -1827,7 +1850,10 @@ const m = { if ( Vector.magnitude(Vector.sub(mob[i].position, m.fieldPosition)) - mob[i].radius < m.fieldRange && !mob[i].isUnblockable && - Vector.dot({ x: Math.cos(m.fieldAngle), y: Math.sin(m.fieldAngle) }, Vector.normalise(Vector.sub(mob[i].position, m.fieldPosition))) > m.fieldThreshold && + Vector.dot({ + x: Math.cos(m.fieldAngle), + y: Math.sin(m.fieldAngle) + }, Vector.normalise(Vector.sub(mob[i].position, m.fieldPosition))) > m.fieldThreshold && Matter.Query.ray(map, mob[i].position, m.fieldPosition).length === 0 ) { mob[i].locatePlayer(); @@ -1838,12 +1864,18 @@ const m = { if (m.coupling - i > Math.random()) { const angle = m.fieldAngle + 4 * m.fieldArc * (Math.random() - 0.5) const radius = m.fieldRange * (0.6 + 0.3 * Math.random()) - b.iceIX(6 + 6 * Math.random(), angle, Vector.add(m.fieldPosition, { x: radius * Math.cos(angle), y: radius * Math.sin(angle) })) + b.iceIX(6 + 6 * Math.random(), angle, Vector.add(m.fieldPosition, { + x: radius * Math.cos(angle), + y: radius * Math.sin(angle) + })) } } } if (tech.blockDmg) { //electricity - Matter.Body.setVelocity(mob[i], { x: 0.5 * mob[i].velocity.x, y: 0.5 * mob[i].velocity.y }); + Matter.Body.setVelocity(mob[i], { + x: 0.5 * mob[i].velocity.x, + y: 0.5 * mob[i].velocity.y + }); if (mob[i].isShielded) { for (let j = 0, len = mob.length; j < len; j++) { @@ -1944,7 +1976,7 @@ const m = { } } } - m.hold = function() { + m.hold = function () { const wave = Math.sin(m.cycle * 0.022); m.fieldRange = 180 + 12 * wave + 100 * tech.isBigField m.fieldArc = 0.35 + 0.045 * wave + 0.065 * tech.isBigField //run calculateFieldThreshold after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob) @@ -1957,7 +1989,10 @@ const m = { //float while field is on if (player.velocity.y > 1) { player.force.y -= (tech.isBigField ? 0.87 : 0.7) * player.mass * simulation.g; - Matter.Body.setVelocity(player, { x: player.velocity.x, y: 0.98 * player.velocity.y }); //set velocity to cap, but keep the direction + Matter.Body.setVelocity(player, { + x: player.velocity.x, + y: 0.98 * player.velocity.y + }); //set velocity to cap, but keep the direction } @@ -1966,7 +2001,10 @@ const m = { if (m.energy > m.fieldRegen) m.energy -= m.fieldRegen m.grabPowerUp(); m.lookForPickUp(); - m.fieldPosition = { x: m.pos.x, y: m.pos.y } + m.fieldPosition = { + x: m.pos.x, + y: m.pos.y + } m.fieldAngle = m.angle //draw field attached to player if (m.holdingTarget) { @@ -2046,7 +2084,7 @@ const m = { m.fieldHarmReduction = 0.45; //55% reduction m.fieldDrawRadius = 0; - m.hold = function() { + m.hold = function () { m.airSpeedLimit = 125 //5 * player.mass * player.mass m.FxAir = 0.016 if (m.isHolding) { @@ -2196,7 +2234,7 @@ const m = { effect: () => { m.fieldMeterColor = "#ff0" m.eyeFillColor = m.fieldMeterColor - m.hold = function() { + m.hold = function () { if (m.energy > m.maxEnergy - 0.02 && m.fieldCDcycle < m.cycle && !input.field && bullet.length < 300 && (m.cycle % 2)) { if (simulation.molecularMode === 0) { if (tech.isSporeFlea) { @@ -2204,13 +2242,22 @@ const m = { if (m.energy > drain) { m.energy -= drain const speed = m.crouch ? 20 + 8 * Math.random() : 10 + 3 * Math.random() - b.flea({ x: m.pos.x + 35 * Math.cos(m.angle), y: m.pos.y + 35 * Math.sin(m.angle) }, { x: speed * Math.cos(m.angle), y: speed * Math.sin(m.angle) }) + b.flea({ + x: m.pos.x + 35 * Math.cos(m.angle), + y: m.pos.y + 35 * Math.sin(m.angle) + }, { + x: speed * Math.cos(m.angle), + y: speed * Math.sin(m.angle) + }) } } else if (tech.isSporeWorm) { const drain = 0.18 + (Math.max(bullet.length, 130) - 130) * 0.02 if (m.energy > drain) { m.energy -= drain - b.worm({ x: m.pos.x + 35 * Math.cos(m.angle), y: m.pos.y + 35 * Math.sin(m.angle) }) + b.worm({ + x: m.pos.x + 35 * Math.cos(m.angle), + y: m.pos.y + 35 * Math.sin(m.angle) + }) const SPEED = 2 + 1 * Math.random(); Matter.Body.setVelocity(bullet[bullet.length - 1], { x: SPEED * Math.cos(m.angle), @@ -2218,9 +2265,9 @@ const m = { }); } } else { - const drain = 0.1 + (Math.max(bullet.length, 130) - 130) * 0.01 + const drain = 0.095 + (Math.max(bullet.length, 130) - 130) * 0.01 for (let i = 0, len = Math.random() * 20; i < len; i++) { - if (m.energy > drain) { + if (m.energy > 3 * drain) { m.energy -= drain b.spore(m.pos) } else { @@ -2235,10 +2282,12 @@ const m = { y: Math.sin(m.angle) } const push = Vector.mult(Vector.perp(direction), 0.08) - b.missile({ x: m.pos.x + 30 * direction.x, y: m.pos.y + 30 * direction.y }, m.angle, -15) + b.missile({ + x: m.pos.x + 30 * direction.x, + y: m.pos.y + 30 * direction.y + }, m.angle, -15) bullet[bullet.length - 1].force.x += push.x * (Math.random() - 0.5) bullet[bullet.length - 1].force.y += 0.005 + push.y * (Math.random() - 0.5) - // b.missile({ x: m.pos.x, y: m.pos.y - 40 }, -Math.PI / 2 + 0.5 * (Math.random() - 0.5), 0, 1) } else if (simulation.molecularMode === 2) { m.energy -= 0.045; @@ -2248,7 +2297,10 @@ const m = { const drain = 0.8 + (Math.max(bullet.length, 50) - 50) * 0.01 if (m.energy > drain) { m.energy -= drain - b.droneRadioactive({ x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) }, 25) + b.droneRadioactive({ + x: m.pos.x + 30 * Math.cos(m.angle) + 10 * (Math.random() - 0.5), + y: m.pos.y + 30 * Math.sin(m.angle) + 10 * (Math.random() - 0.5) + }, 25) } } else { //every bullet above 100 adds 0.005 to the energy cost per drone @@ -2367,7 +2419,10 @@ const m = { radiusLimit: 10, damage: 0.8, setPositionToNose() { - const nose = { x: m.pos.x + 10 * Math.cos(m.angle), y: m.pos.y + 10 * Math.sin(m.angle) } + const nose = { + x: m.pos.x + 10 * Math.cos(m.angle), + y: m.pos.y + 10 * Math.sin(m.angle) + } Matter.Body.setPosition(this, Vector.add(nose, Vector.mult(Vector.normalise(Vector.sub(nose, m.pos)), circleRadiusScale * this.circleRadius))); }, fire() { @@ -2531,7 +2586,10 @@ const m = { ctx.arc(this.position.x, this.position.y, radius, 0, 2 * Math.PI); ctx.fill(); //draw arcs - const unit = Vector.rotate({ x: 1, y: 0 }, Math.random() * 6.28) + const unit = Vector.rotate({ + x: 1, + y: 0 + }, Math.random() * 6.28) let len = 8 const step = this.circleRadius / len let x = this.position.x @@ -2563,7 +2621,7 @@ const m = { Composite.add(engine.world, m.plasmaBall); // m.plasmaBall.startingVertices = m.plasmaBall.vertices.slice(); - m.hold = function() { + m.hold = function () { if (m.isHolding) { m.drawHold(m.holdingTarget); m.holding(); @@ -2654,7 +2712,7 @@ const m = { m.plasmaBall.do() } } else if (tech.isExtruder) { - m.hold = function() { + m.hold = function () { b.isExtruderOn = false if (m.isHolding) { m.drawHold(m.holdingTarget); @@ -2696,7 +2754,7 @@ const m = { ctx.stroke(); } } else { - m.hold = function() { + m.hold = function () { if (m.isHolding) { m.drawHold(m.holdingTarget); m.holding(); @@ -2760,8 +2818,8 @@ const m = { if (tech.isRewindField) { this.rewindCount = 0 m.grabPowerUpRange2 = 300000 - m.hold = function() { - console.log(m.fieldCDcycle) + m.hold = function () { + // console.log(m.fieldCDcycle) m.grabPowerUp(); // //grab power ups // for (let i = 0, len = powerUp.length; i < len; ++i) { @@ -2808,7 +2866,10 @@ const m = { m.energy -= DRAIN if (m.immuneCycle < m.cycle + 60) m.immuneCycle = m.cycle + 60; //player is immune to damage for __ cycles Matter.Body.setPosition(player, history.position); - Matter.Body.setVelocity(player, { x: history.velocity.x, y: history.velocity.y }); + Matter.Body.setVelocity(player, { + x: history.velocity.x, + y: history.velocity.y + }); if (m.health < history.health) { m.health = history.health if (m.health > m.maxHealth) m.health = m.maxHealth @@ -2853,7 +2914,7 @@ const m = { } else { m.fieldFire = true; m.isBodiesAsleep = false; - m.hold = function() { + m.hold = function () { if (m.isHolding) { m.wakeCheck(); m.drawHold(m.holdingTarget); @@ -2920,7 +2981,7 @@ const m = { m.isSneakAttack = true; m.sneakAttackCycle = 0; m.enterCloakCycle = 0; - m.drawCloak = function() { + m.drawCloak = function () { m.fieldPhase += 0.007 const wiggle = 0.15 * Math.sin(m.fieldPhase * 0.5) ctx.beginPath(); @@ -2934,7 +2995,7 @@ const m = { ctx.globalCompositeOperation = "source-over"; ctx.clip(); } - m.hold = function() { + m.hold = function () { if (m.isHolding) { m.drawHold(m.holdingTarget); m.holding(); @@ -2951,7 +3012,7 @@ const m = { //not shooting (or using field) enable cloak if (m.energy < 0.05 && m.fireCDcycle < m.cycle && !input.fire) m.fireCDcycle = m.cycle if (m.fireCDcycle + 30 < m.cycle && !input.fire) { //automatically cloak if not firing - const drain = 0.1 + const drain = 0.05 if (!m.isCloak && m.energy > drain + 0.05) { m.energy -= drain m.isCloak = true //enter cloak @@ -3214,7 +3275,7 @@ const m = { m.fieldOn = false; m.fieldRadius = 0; m.drop(); - m.hold = function() { + m.hold = function () { if (input.field) { if (m.fieldCDcycle < m.cycle) { const scale = 25 @@ -3398,7 +3459,7 @@ const m = { //wormholes attract blocks and power ups
description: "use energy to tunnel through a wormhole
+3% chance to duplicate spawned power ups
generate 6 energy per second", //
bullets may also traverse wormholes drain: 0, - effect: function() { + effect: function () { m.fieldMeterColor = "#bbf" //"#0c5" m.eyeFillColor = m.fieldMeterColor @@ -3406,7 +3467,7 @@ const m = { m.fieldRange = 0 powerUps.setDupChance(); //needed after adjusting duplication chance - m.hold = function() { + m.hold = function () { // m.hole = { //this is reset with each new field, but I'm leaving it here for reference // isOn: false, // isReady: true, @@ -3512,7 +3573,10 @@ const m = { m.fieldRange *= 0.8 if ((m.fieldMode === 0 || m.fieldMode === 9) && m.immuneCycle < m.cycle) m.energy += 0.2 * m.coupling if (tech.isWormholeWorms) { //pandimensional spermia - b.worm(Vector.add(m.hole.pos2, Vector.rotate({ x: m.fieldRange * 0.4, y: 0 }, 2 * Math.PI * Math.random()))) + b.worm(Vector.add(m.hole.pos2, Vector.rotate({ + x: m.fieldRange * 0.4, + y: 0 + }, 2 * Math.PI * Math.random()))) Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), -10)); // for (let i = 0, len = Math.ceil(1.25 * Math.random()); i < len; i++) { // } @@ -3537,7 +3601,10 @@ const m = { if ((m.fieldMode === 0 || m.fieldMode === 9) && m.immuneCycle < m.cycle) m.energy += 0.2 * m.coupling if (m.fieldMode === 0 || m.fieldMode === 9) m.energy += 0.2 * m.coupling if (tech.isWormholeWorms) { //pandimensional spermia - b.worm(Vector.add(m.hole.pos1, Vector.rotate({ x: m.fieldRange * 0.4, y: 0 }, 2 * Math.PI * Math.random()))) + b.worm(Vector.add(m.hole.pos1, Vector.rotate({ + x: m.fieldRange * 0.4, + y: 0 + }, 2 * Math.PI * Math.random()))) Matter.Body.setVelocity(bullet[bullet.length - 1], Vector.mult(Vector.rotate(m.hole.unit, Math.PI / 2), 5)); // for (let i = 0, len = Math.ceil(1.25 * Math.random()); i < len; i++) { // } @@ -3624,7 +3691,10 @@ const m = { this.drain = tech.isFreeWormHole ? 0 : 0.06 + 0.006 * Math.sqrt(mag) } const unit = Vector.perp(Vector.normalise(sub)) - const where = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) } + const where = { + x: m.pos.x + 30 * Math.cos(m.angle), + y: m.pos.y + 30 * Math.sin(m.angle) + } m.fieldRange = 0.97 * m.fieldRange + 0.03 * (50 + 10 * Math.sin(simulation.cycle * 0.025)) const edge2a = Vector.add(Vector.mult(unit, 1.5 * m.fieldRange), simulation.mouseInGame) const edge2b = Vector.add(Vector.mult(unit, -1.5 * m.fieldRange), simulation.mouseInGame) @@ -3922,27 +3992,86 @@ const m = { } m.isShipMode = true // simulation.isCheating = true - const points = [ - { x: 29.979168754143455, y: 4.748337243898336 }, - { x: 27.04503734408824, y: 13.7801138209198 }, - { x: 21.462582474874278, y: 21.462582475257523 }, - { x: 13.780113820536943, y: 27.045037344471485 }, - { x: 4.74833724351507, y: 29.979168754526473 }, - { x: -4.748337245049098, y: 29.979168754526473 }, - { x: -13.780113822071026, y: 27.045037344471485 }, - { x: -21.46258247640829, y: 21.462582475257523 }, - { x: -27.045037345621797, y: 13.7801138209198 }, - { x: -29.979168755677012, y: 4.748337243898336 }, - { x: -29.979168755677012, y: -4.7483372446656045 }, - { x: -27.045037345621797, y: -13.78011382168726 }, - { x: -21.46258247640829, y: -21.462582476024817 }, - { x: -13.780113822071026, y: -27.045037345239006 }, - { x: -4.748337245049098, y: -29.97916875529422 }, - { x: 4.74833724351507, y: -29.97916875529422 }, - { x: 13.780113820536943, y: -27.045037345239006 }, - { x: 21.462582474874278, y: -21.462582476024817 }, - { x: 27.04503734408824, y: -13.78011382168726 }, - { x: 29.979168754143455, y: -4.7483372446656045 } + const points = [{ + x: 29.979168754143455, + y: 4.748337243898336 + }, + { + x: 27.04503734408824, + y: 13.7801138209198 + }, + { + x: 21.462582474874278, + y: 21.462582475257523 + }, + { + x: 13.780113820536943, + y: 27.045037344471485 + }, + { + x: 4.74833724351507, + y: 29.979168754526473 + }, + { + x: -4.748337245049098, + y: 29.979168754526473 + }, + { + x: -13.780113822071026, + y: 27.045037344471485 + }, + { + x: -21.46258247640829, + y: 21.462582475257523 + }, + { + x: -27.045037345621797, + y: 13.7801138209198 + }, + { + x: -29.979168755677012, + y: 4.748337243898336 + }, + { + x: -29.979168755677012, + y: -4.7483372446656045 + }, + { + x: -27.045037345621797, + y: -13.78011382168726 + }, + { + x: -21.46258247640829, + y: -21.462582476024817 + }, + { + x: -13.780113822071026, + y: -27.045037345239006 + }, + { + x: -4.748337245049098, + y: -29.97916875529422 + }, + { + x: 4.74833724351507, + y: -29.97916875529422 + }, + { + x: 13.780113820536943, + y: -27.045037345239006 + }, + { + x: 21.462582474874278, + y: -21.462582476024817 + }, + { + x: 27.04503734408824, + y: -13.78011382168726 + }, + { + x: 29.979168754143455, + y: -4.7483372446656045 + } ] // Matter.Body.setVertices(player, Matter.Vertices.create(points, player)) diff --git a/js/powerup.js b/js/powerup.js index f9951b3..91eccd6 100644 --- a/js/powerup.js +++ b/js/powerup.js @@ -325,10 +325,10 @@ const powerUps = { ctx.fillStyle = `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" + // document.getElementById("pause-grid-right").style.opacity = "0.7" + // document.getElementById("pause-grid-left").style.opacity = "0.7" } - build.pauseGrid() + // build.pauseGrid() }, endDraft(type, isCanceled = false) { //type should be a gun, tech, or field if (isCanceled) { @@ -372,7 +372,7 @@ const powerUps = { // simulation.makeTextLog(`powerUps.tech.length: ${Math.max(0,powerUps.tech.lastTotalChoices - banishLength)}`) // } } - if (tech.isAnsatz && powerUps.research.count === 0) { + 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" @@ -572,11 +572,11 @@ const powerUps = { const target = b.guns[b.activeGun] if (target.ammo !== Infinity) { if (tech.ammoCap) { - const ammoAdded = Math.ceil(target.ammoPack * 0.7 * tech.ammoCap) //0.7 is average + const ammoAdded = Math.ceil(target.ammoPack * 0.7 * tech.ammoCap * 0.8) //0.7 is average target.ammo = ammoAdded // simulation.makeTextLog(`${target.name}.ammo = ${ammoAdded}`) } else { - const ammoAdded = Math.ceil((0.7 * Math.random() + 0.7 * Math.random()) * target.ammoPack) + const ammoAdded = Math.ceil((0.7 * Math.random() + 0.7 * Math.random()) * target.ammoPack * 0.8) target.ammo += ammoAdded // simulation.makeTextLog(`${target.name}.ammo += ${ammoAdded}`) } @@ -619,6 +619,125 @@ const powerUps = { } } }, + cancelText(type) { + if (tech.isSuperDeterminism) { + return `
` + } else if (tech.isCancelTech) { + return `
randomize
` + } else { + return `
cancel
` + } + }, + researchText(type) { + let text = "" + if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) { + text += `
` // style = "margin-left: 192px; margin-right: -192px;" + tech.junkResearchNumber = Math.ceil(4 * Math.random()) + text += `
` + for (let i = 0; i < tech.junkResearchNumber; i++) text += `
` + text += `
  pseudoscience
` + } else if (powerUps.research.count > 0) { + text += `
` // style = "margin-left: 192px; margin-right: -192px;" + text += `
` + for (let i = 0, len = Math.min(powerUps.research.count, 30); i < len; i++) text += `
` + text += `
  ${tech.isResearchReality?"alternate reality": "research"}
` + } else { + text += `
` + } + return text + }, + 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 `
+
+
  ${b.guns[choose].name}
+ ${b.guns[choose].description}
` + }, + 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 `
+
+
  ${m.fieldUpgrades[choose].name}
+ ${m.fieldUpgrades[choose].description}
` + }, + techText(choose, click) { + const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` + + return `
+
+
  ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + }, + + fieldTechText(choose, click) { + const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` + + return `
+
+
+ +
+
+
+           ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + }, + gunTechText(choose, click) { + const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` + + return `
+
+
+ +
+
+
+           ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + }, + junkTechText(choose, click) { + const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-size: contain;background-repeat: no-repeat;"` + if (!localSettings.isHideImages) { + setTimeout(() => { //pull image from web search if no url + if (tech.tech[choose].url === undefined) { + const url = "https://images.search.yahoo.com/search/images?p=" + tech.tech[choose].name; + fetch(url) + .then((response) => response.text()) + .then((html) => { + const parser = new DOMParser(); + const doc = parser.parseFromString(html, "text/html"); + const elements = doc.getElementsByClassName("ld"); + // console.log(JSON.parse(elements[i].getAttribute("data")).iurl) + tech.tech[choose].url = JSON.parse(elements[i].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}')` + } + }, 100); + } + + return `
+
+
  ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + }, + incoherentTechText(choose, click) { + // text += `
${tech.tech[choose].name} - incoherent
` + const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` + return `
+
+
incoherent


+
` + }, gun: { name: "gun", color: "#26a", @@ -627,14 +746,11 @@ const powerUps = { }, effect() { if (m.alive) { - let text = "" - if (!tech.isSuperDeterminism) text += `
${tech.isCancelTech ? "?":"✕"}
` - text += `

gun

` 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 + (m.fieldUpgrades[m.fieldMode].name === "pilot wave")) + let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2 + tech.extraChoices + (m.fieldUpgrades[m.fieldMode].name === "pilot wave"))) 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++) { @@ -651,9 +767,26 @@ const powerUps = { } 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 = "" + if (totalChoices === 2) { + document.getElementById("choose-grid").style.gridTemplateColumns = "384px 384px" + text += powerUps.researchText('gun') + text += powerUps.cancelText('gun') + } else if (totalChoices === 1) { + document.getElementById("choose-grid").style.gridTemplateColumns = "384px" + text += powerUps.cancelText('gun') + text += powerUps.researchText('gun') + } else { + document.getElementById("choose-grid").style.gridTemplateColumns = "384px 384px 384px" + text += "
" + text += powerUps.researchText('gun') + text += powerUps.cancelText('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 += `
  ${b.guns[choose].name}
${b.guns[choose].description}
` + const choose = options[Math.floor(Math.seededRandom(0, options.length))] //pick an element from the array of options + // text += `
  ${b.guns[choose].name}
${b.guns[choose].description}
` + text += powerUps.gunText(choose, `powerUps.choose('gun',${choose})`) + b.guns[choose].isRecentlyShown = true removeOption(choose) if (options.length < 1) break @@ -664,96 +797,24 @@ const powerUps = { 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 += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` const choose = botTech[Math.floor(Math.random() * botTech.length)]; - const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; - text += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` + text += `
+
+
⭓▸●■   ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` } } - if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) { - tech.junkResearchNumber = Math.ceil(4 * Math.random()) - text += `
` - for (let i = 0; i < tech.junkResearchNumber; i++) text += `
` - text += `
  pseudoscience
` - } else if (powerUps.research.count) { - text += `
` - for (let i = 0, len = Math.min(powerUps.research.count, 30); i < len; i++) text += `
` - text += `
  ${tech.isResearchReality?"alternate reality": "research"}
` - } if (tech.isOneGun && b.inventory.length > 0) text += `
replaces your current gun
` document.getElementById("choose-grid").innerHTML = text powerUps.showDraft(); } } }, - // pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { - // let options = []; - // for (let i = 0; i < who.length; i++) { - // if (!who[i].have && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4) { - // options.push(i); - // } - // } - // //remove repeats from last selection - // const totalChoices = tech.isDeterminism ? 1 : 3 + tech.extraChoices * 2 - // if (powerUps.gun.choiceLog.length > totalChoices || powerUps.gun.choiceLog.length === totalChoices) { //make sure this isn't the first time getting a power up and there are previous choices to remove - // for (let i = 0; i < totalChoices; i++) { //repeat for each choice from the last selection - // if (options.length > totalChoices) { - // for (let j = 0, len = options.length; j < len; j++) { - // if (powerUps.gun.choiceLog[powerUps.gun.choiceLog.length - 1 - i] === options[j]) { - // options.splice(j, 1) //remove previous choice from option pool - // break - // } - // } - // } - // } - // } - // if (options.length > 0) { - // return options[Math.floor(Math.seededRandom(0, options.length))] - // } - // }, - // effectOld() { - // let choice1 = powerUps.gun.pick(b.guns) - // let choice2 = -1 - // let choice3 = -1 - // if (choice1 > -1) { - // let text = "" - // if (!tech.isSuperDeterminism) text += `
${tech.isCancelTech ? "?":"✕"}
` - // text += `

gun

` - // text += `
  ${b.guns[choice1].name}
${b.guns[choice1].description}
` - // if (!tech.isDeterminism) { - // choice2 = powerUps.gun.pick(b.guns, choice1) - // if (choice2 > -1) text += `
  ${b.guns[choice2].name}
${b.guns[choice2].description}
` - // choice3 = powerUps.gun.pick(b.guns, choice1, choice2) - // if (choice3 > -1) text += `
  ${b.guns[choice3].name}
${b.guns[choice3].description}
` - // } - // if (tech.extraChoices) { - // let choice4 = powerUps.gun.pick(b.guns, choice1, choice2, choice3) - // if (choice4 > -1) text += `
  ${b.guns[choice4].name}
${b.guns[choice4].description}
` - // let choice5 = powerUps.gun.pick(b.guns, choice1, choice2, choice3, choice4) - // if (choice5 > -1) text += `
- //
  ${b.guns[choice5].name}
${b.guns[choice5].description}
` - // powerUps.gun.choiceLog.push(choice4) - // powerUps.gun.choiceLog.push(choice5) - // } - // powerUps.gun.choiceLog.push(choice1) - // powerUps.gun.choiceLog.push(choice2) - // powerUps.gun.choiceLog.push(choice3) - // // if (powerUps.research.count) text += `
  research ${powerUps.research.count}
` - - // if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) { - // tech.junkResearchNumber = Math.floor(5 * Math.random()) - // text += `
` - // for (let i = 0; i < tech.junkResearchNumber; i++) text += `
` - // text += `
  pseudoscience
` - // } else if (powerUps.research.count) { - // text += `
` - // for (let i = 0, len = Math.min(powerUps.research.count, 30); i < len; i++) text += `
` - // text += `
  ${tech.isResearchReality?"alternate reality": "research"}
` - // } - // if (tech.isOneGun && b.inventory.length > 0) text += `
replaces your current gun
` - // document.getElementById("choose-grid").innerHTML = text - // powerUps.showDraft(); - // } - // } }, field: { name: "field", @@ -763,15 +824,11 @@ const powerUps = { }, effect() { if (m.alive) { - let text = "" - if (!tech.isSuperDeterminism) text += `
${tech.isCancelTech ? "?":"✕"}
` - text += `

field

` - 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 + (m.fieldUpgrades[m.fieldMode].name === "pilot wave")) + let totalChoices = Math.min(options.length, (tech.isDeterminism ? 1 : 2 + tech.extraChoices + (m.fieldUpgrades[m.fieldMode].name === "pilot wave"))) if (tech.isFlipFlopChoices) totalChoices += tech.isRelay ? (tech.isFlipFlopOn ? -1 : 7) : (tech.isFlipFlopOn ? 7 : -1) //flip the order for relay function removeOption(index) { @@ -790,9 +847,25 @@ const powerUps = { 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 = "" + if (totalChoices === 2) { + document.getElementById("choose-grid").style.gridTemplateColumns = "384px 384px" + text += powerUps.researchText('field') + text += powerUps.cancelText('field') + } else if (totalChoices === 1) { + document.getElementById("choose-grid").style.gridTemplateColumns = "384px" + text += powerUps.cancelText('field') + text += powerUps.researchText('field') + } else { + document.getElementById("choose-grid").style.gridTemplateColumns = "384px 384px 384px" + text += "
" + text += powerUps.researchText('field') + text += powerUps.cancelText('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 += `
  ${m.fieldUpgrades[choose].name}
${m.fieldUpgrades[choose].description}
` + //text += `
  ${m.fieldUpgrades[choose].name}
${m.fieldUpgrades[choose].description}
` //default + text += powerUps.fieldText(choose, `powerUps.choose('field',${choose})`) m.fieldUpgrades[choose].isRecentlyShown = true removeOption(choose) if (options.length < 1) break @@ -803,94 +876,23 @@ const powerUps = { 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 += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` const choose = botTech[Math.floor(Math.random() * botTech.length)]; - const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; - text += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` + text += `
+
+
⭓▸●■   ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` } } - if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) { - tech.junkResearchNumber = Math.ceil(4 * Math.random()) - text += `
` - for (let i = 0; i < tech.junkResearchNumber; i++) text += `
` - text += `
  pseudoscience
` - } else if (powerUps.research.count) { - text += `
` - for (let i = 0, len = Math.min(powerUps.research.count, 30); i < len; i++) text += `
` - text += `
  ${tech.isResearchReality?"alternate reality": "research"}
` - } document.getElementById("choose-grid").innerHTML = text powerUps.showDraft(); } } }, - // pick(who, skip1 = -1, skip2 = -1, skip3 = -1, skip4 = -1) { - // let options = []; - // for (let i = 1; i < who.length; i++) { - // if (i !== m.fieldMode && i !== skip1 && i !== skip2 && i !== skip3 && i !== skip4) options.push(i); - // } - // //remove repeats from last selection - // const totalChoices = tech.isDeterminism ? 1 : 3 + tech.extraChoices * 2 - // if (powerUps.field.choiceLog.length > totalChoices || powerUps.field.choiceLog.length === totalChoices) { //make sure this isn't the first time getting a power up and there are previous choices to remove - // for (let i = 0; i < totalChoices; i++) { //repeat for each choice from the last selection - // if (options.length > totalChoices) { - // for (let j = 0, len = options.length; j < len; j++) { - // if (powerUps.field.choiceLog[powerUps.field.choiceLog.length - 1 - i] === options[j]) { - // options.splice(j, 1) //remove previous choice from option pool - // break - // } - // } - // } - // } - // } - // if (options.length > 0) { - // // return options[Math.floor(Math.random() * options.length)] - // return options[Math.floor(Math.seededRandom(0, options.length))] - // } - // }, - // effectOld() { - // let choice1 = powerUps.field.pick(m.fieldUpgrades) - // let choice2 = -1 - // let choice3 = -1 - // if (choice1 > -1) { - // let text = "" - // if (!tech.isSuperDeterminism) text += `
${tech.isCancelTech ? "?":"✕"}
` - // text += `

field

` - // text += `
  ${m.fieldUpgrades[choice1].name}
${m.fieldUpgrades[choice1].description}
` - // powerUps.field.choiceLog.push(choice1) - // if (!tech.isDeterminism) { - // choice2 = powerUps.field.pick(m.fieldUpgrades, choice1) - // if (choice2 > -1) text += `
  ${m.fieldUpgrades[choice2].name}
${m.fieldUpgrades[choice2].description}
` - // choice3 = powerUps.field.pick(m.fieldUpgrades, choice1, choice2) - // if (choice3 > -1) text += `
  ${m.fieldUpgrades[choice3].name}
${m.fieldUpgrades[choice3].description}
` - // powerUps.field.choiceLog.push(choice2) - // powerUps.field.choiceLog.push(choice3) - // } - // if (tech.extraChoices) { - // let choice4 = powerUps.field.pick(m.fieldUpgrades, choice1, choice2, choice3) - // if (choice4 > -1) text += `
  ${m.fieldUpgrades[choice4].name}
${m.fieldUpgrades[choice4].description}
` - // let choice5 = powerUps.field.pick(m.fieldUpgrades, choice1, choice2, choice3, choice4) - // if (choice5 > -1) text += `
  ${m.fieldUpgrades[choice5].name}
${m.fieldUpgrades[choice5].description}
` - // powerUps.field.choiceLog.push(choice4) - // powerUps.field.choiceLog.push(choice5) - // } - - // if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) { - // tech.junkResearchNumber = Math.floor(4 * Math.random()) - // text += `
` - // for (let i = 0; i < tech.junkResearchNumber; i++) text += `
` - // text += `
  pseudoscience
` - // } else if (powerUps.research.count) { - // text += `
` - // for (let i = 0, len = Math.min(powerUps.research.count, 30); i < len; i++) text += `
` - // // text += `
  research
` - // text += `  ${tech.isResearchReality?"alternate reality": "research"}
` - // } - // //(${powerUps.research.count}) - // // text += `
${simulation.SVGrightMouse} activate the shield with the right mouse
fields shield you from damage
and let you pick up and throw blocks
` - // document.getElementById("choose-grid").innerHTML = text - // powerUps.showDraft(); - // } - // } }, tech: { name: "tech", @@ -900,14 +902,8 @@ const powerUps = { }, effect() { if (m.alive) { - let text = "" - if (!tech.isSuperDeterminism) text += `
${tech.isCancelTech ? "?":"✕"}
` - text += `

tech

` - - //used for junk estimation - let junkCount = 0 - let totalCount = 0 - + 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++) { @@ -928,19 +924,14 @@ const powerUps = { if (options.length < 1) return; } } - //set total choices - let totalChoices = (tech.isDeterminism ? 1 : 3) + tech.extraChoices + (m.fieldUpgrades[m.fieldMode].name === "pilot wave") + let totalChoices = (tech.isDeterminism ? 1 : 3 + tech.extraChoices + (m.fieldUpgrades[m.fieldMode].name === "pilot wave")) 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 - // console.log('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") { - // console.log(i) - powerUps.ejectTech(i, true) - } + if (tech.tech[i].name === "decoherence") powerUps.ejectTech(i, true) } simulation.makeTextLog(`decoherence tech ejected`) simulation.makeTextLog(`options reset`) @@ -950,15 +941,10 @@ const powerUps = { tech.tooManyTechChoices = false totalChoices = optionLengthNoDuplicates } - //check for tech that were a choice last time and remove them - if (optionLengthNoDuplicates > totalChoices) { - // console.log('check for tech that were a choice last time and remove them', optionLengthNoDuplicates, options.length) + 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) { - // console.log(i) - removeOption(i) - } + if (tech.tech[i].isRecentlyShown) removeOption(i) } else { break //you have to repeat choices if there are not enough choices left to display } @@ -966,42 +952,42 @@ const powerUps = { } } for (let i = 0; i < tech.tech.length; i++) tech.tech[i].isRecentlyShown = false //reset recently shown back to zero - // powerUps.tech.lastTotalChoices = options.length //this is recorded so that banish can know how many tech were available - // console.log(optionLengthNoDuplicates, options.length) if (options.length > 0) { + let text = "" + if (totalChoices === 2) { + document.getElementById("choose-grid").style.gridTemplateColumns = "384px 384px" + text += powerUps.researchText('tech') + text += powerUps.cancelText('tech') + } else if (totalChoices === 1) { + document.getElementById("choose-grid").style.gridTemplateColumns = "384px" + text += powerUps.cancelText('tech') + text += powerUps.researchText('tech') + } else { + document.getElementById("choose-grid").style.gridTemplateColumns = "384px 384px 384px" + text += "
" + text += powerUps.researchText('tech') + text += powerUps.cancelText('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 - + 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 += `
- -
-
-
-         ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() :tech.tech[choose].description}
` + text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`) } else if (tech.tech[choose].isGunTech) { - text += `
- -
-
-
-         ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() :tech.tech[choose].description}
` - } else if (tech.tech[choose].isLore) { - text += `
  ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + text += powerUps.gunTechText(choose, `powerUps.choose('tech',${choose})`) + // } else if (tech.tech[choose].isLore) { + // text += `
  ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` } else if (tech.tech[choose].isJunk) { - text += `
  ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` - } else { - text += `
  ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + text += powerUps.junkTechText(choose, `powerUps.choose('tech',${choose})`) + } else { //normal tech + text += powerUps.techText(choose, `powerUps.choose('tech',${choose})`) } if (options.length < 1) break } @@ -1011,9 +997,16 @@ const powerUps = { 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 += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` const choose = botTech[Math.floor(Math.random() * botTech.length)]; - const isCount = tech.tech[choose].count > 0 ? `(${tech.tech[choose].count+1}x)` : ""; - text += `
⭓▸●■   ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + const techCountText = tech.tech[choose].count > 1 ? `(${tech.tech[choose].count}x)` : ""; + const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/${tech.tech[choose].name}.webp');"` + text += `
+
+
⭓▸●■   ${tech.tech[choose].name} ${techCountText}
+ ${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` } } @@ -1024,14 +1017,16 @@ const powerUps = { 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 += `
  ${b.guns[pick].name}
${b.guns[pick].description}
` + // text += `
  ${b.guns[pick].name}
${b.guns[pick].description}
` + 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 += `
  ${m.fieldUpgrades[pick].name}
${m.fieldUpgrades[pick].description}
` + // text += `
  ${m.fieldUpgrades[pick].name}
${m.fieldUpgrades[pick].description}
` + text += powerUps.fieldText(pick, `powerUps.choose('field',${pick})`) } } if (tech.isMicroTransactions && powerUps.research.count > 0) { @@ -1063,18 +1058,6 @@ const powerUps = { } requestAnimationFrame(cycle); } - //add in research button or pseudoscience button - if (tech.isJunkResearch && powerUps.research.currentRerollCount < 3) { - tech.junkResearchNumber = Math.ceil(4 * Math.random()) - text += `
` - for (let i = 0; i < tech.junkResearchNumber; i++) text += `
` - text += `
  pseudoscience
` - } else if (powerUps.research.count > 0) { - text += `
` - for (let i = 0, len = Math.min(powerUps.research.count, 30); i < len; i++) text += `
` - // text += `
  research
` - text += `  ${tech.isResearchReality?"alternate reality": "research"}` - } document.getElementById("choose-grid").innerHTML = text powerUps.showDraft(); @@ -1094,52 +1077,50 @@ const powerUps = { entanglement: { name: "entanglement", color: "#fff", //"hsl(248,100%,65%)", - size() { return 40 }, + size() { + return 40 + }, effect() { if (m.alive && localSettings.entanglement) { let text = "" - text += `
` - text += `

entanglement

` + document.getElementById("choose-grid").style.gridTemplateColumns = "384px 384px 384px" + // text += powerUps.researchText('tech') + text += "
" + text += "
entanglement
" + text += `
cancel
` //powerUps.cancelText('tech') if (localSettings.entanglement.fieldIndex) { - const field = localSettings.entanglement.fieldIndex //add field - text += `
  ${m.fieldUpgrades[field].name}
${m.fieldUpgrades[field].description}
` + 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 gun = localSettings.entanglement.gunIndexes[i] - text += `
  ${b.guns[gun].name}
${b.guns[gun].description}
` + const choose = localSettings.entanglement.gunIndexes[i] + // text += `
  ${b.guns[gun].name}
${b.guns[gun].description}
` + 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 += `
${tech.tech[choose].name} - incompatible
` + // text += `
${tech.tech[choose].name} - incoherent
` + text += powerUps.incoherentTechText(choose) } else { if (tech.tech[choose].isFieldTech) { - text += `
- -
-
-
-         ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() :tech.tech[choose].description}
` + text += powerUps.fieldTechText(choose, `powerUps.choose('tech',${choose})`) } else if (tech.tech[choose].isGunTech) { - text += `
- -
-
-
-         ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() :tech.tech[choose].description}
` + text += powerUps.gunTechText(choose, `powerUps.choose('tech',${choose})`) } else if (tech.tech[choose].isLore) { text += `
  ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` } else if (tech.tech[choose].isJunk) { - text += `
  ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` - } else { - text += `
  ${tech.tech[choose].name} ${isCount}
${tech.tech[choose].descriptionFunction ? tech.tech[choose].descriptionFunction() : tech.tech[choose].description}
` + text += powerUps.junkTechText(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 } @@ -1152,7 +1133,10 @@ const powerUps = { 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) } + 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); } } @@ -1167,7 +1151,10 @@ const powerUps = { if (tech.isLaserMine && input.down) { b.laserMine(who.position) } else { - b.mine(who.position, { x: 0, y: 0 }, 0) + b.mine(who.position, { + x: 0, + y: 0 + }, 0) } } if (tech.isRelay) { @@ -1276,7 +1263,7 @@ const powerUps = { } }, 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.5 - 0.3 && simulation.difficultyMode < 5) { //lower chance on why difficulty + 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"); } @@ -1415,8 +1402,7 @@ const powerUps = { spawn(x, y, target, moving = true, mode = null, size = powerUps[target].size()) { if ( (!tech.isSuperDeterminism || (target !== 'research')) && - !(tech.isEnergyNoAmmo && target === 'ammo') && - (!simulation.isNoPowerUps) + !(tech.isEnergyNoAmmo && target === 'ammo') ) { if (tech.isBoostReplaceAmmo && target === 'ammo') target = 'boost' powerUps.directSpawn(x, y, target, moving, mode, size) diff --git a/js/simulation.js b/js/simulation.js index 897a5d1..60ee67f 100644 --- a/js/simulation.js +++ b/js/simulation.js @@ -190,7 +190,6 @@ const simulation = { healScale: 1, accelScale: null, //set in levels.setDifficulty CDScale: null, //set in levels.setDifficulty - isNoPowerUps: false, molecularMode: Math.floor(4 * Math.random()), //0 spores, 1 missile, 2 ice IX, 3 drones //randomize molecular assembler field type // dropFPS(cap = 40, time = 15) { // simulation.fpsCap = cap @@ -547,16 +546,16 @@ const simulation = { const swapPeriod = 150 const len = 30 for (let i = 0; i < len; i++) { - setTimeout(function() { - simulation.wipe = function() { //set wipe to have trails + setTimeout(function () { + simulation.wipe = function () { //set wipe to have trails ctx.fillStyle = `rgba(221,221,221,${i*i*0.0005 +0.0025})`; ctx.fillRect(0, 0, canvas.width, canvas.height); } }, (i) * swapPeriod); } - setTimeout(function() { - simulation.wipe = function() { //set wipe to normal + setTimeout(function () { + simulation.wipe = function () { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } }, len * swapPeriod); @@ -617,7 +616,7 @@ const simulation = { simulation.clearTimeouts(); simulation.onTitlePage = true; - document.getElementById("splash").onclick = function() { + document.getElementById("splash").onclick = function () { simulation.startGame(); }; // document.getElementById("choose-grid").style.display = "none" @@ -699,10 +698,8 @@ const simulation = { } if (isTrainingRun) { simulation.isTraining = true - simulation.isNoPowerUps = true } else { simulation.isTraining = false - simulation.isNoPowerUps = false; } simulation.onTitlePage = false; // document.getElementById("choose-grid").style.display = "none" @@ -785,11 +782,13 @@ const simulation = { // m.maxEnergy = 1 // m.energy = 1 input.isPauseKeyReady = true - simulation.wipe = function() { //set wipe to normal + simulation.wipe = function () { //set wipe to normal ctx.clearRect(0, 0, canvas.width, canvas.height); } m.hole.isOn = false simulation.paused = false; + // simulation.cycle = 0 + // m.cycle = 0 engine.timing.timeScale = 1; simulation.fpsCap = simulation.fpsCapDefault; simulation.isAutoZoom = true; @@ -864,7 +863,7 @@ const simulation = { requestAnimationFrame(cycle); //starts game loop }, clearTimeouts() { - let id = window.setTimeout(function() {}, 0); + let id = window.setTimeout(function () {}, 0); while (id--) { window.clearTimeout(id); // will do nothing if no timeout with id is present } @@ -899,7 +898,7 @@ const simulation = { if (tech.isMutualism && !tech.isEnergyHealth) { for (let i = 0; i < bullet.length; i++) { if (bullet[i].isMutualismActive) { - m.health += 0.005 + 0.005 * (bullet[i].isSpore || bullet[i].isFlea) + m.health += 0.01 + 0.01 * (bullet[i].isSpore || bullet[i].isFlea) if (m.health > m.maxHealth) m.health = m.maxHealth; m.displayHealth(); } @@ -958,12 +957,21 @@ const simulation = { if (droneCount > 0) { requestAnimationFrame(respawnDrones); if (!simulation.paused && !simulation.isChoosing && m.alive) { - const where = { x: level.enter.x + 50, y: level.enter.y - 60 } + const where = { + x: level.enter.x + 50, + y: level.enter.y - 60 + } droneCount-- if (tech.isDroneRadioactive) { - b.droneRadioactive({ x: where.x + 100 * (Math.random() - 0.5), y: where.y + 100 * (Math.random() - 0.5) }, 0) + b.droneRadioactive({ + x: where.x + 100 * (Math.random() - 0.5), + y: where.y + 100 * (Math.random() - 0.5) + }, 0) } else { - b.drone({ x: where.x + 100 * (Math.random() - 0.5), y: where.y + 120 * (Math.random() - 0.5) }, 0) + b.drone({ + x: where.x + 100 * (Math.random() - 0.5), + y: where.y + 120 * (Math.random() - 0.5) + }, 0) if (tech.isDroneGrab && deliveryCount > 0) { const who = bullet[bullet.length - 1] who.isImproved = true; @@ -985,8 +993,14 @@ const simulation = { requestAnimationFrame(respawnSpores); if (!simulation.paused && !simulation.isChoosing) { sporeCount-- - const where = { x: level.enter.x + 50, y: level.enter.y - 60 } - b.spore({ x: where.x + 100 * (Math.random() - 0.5), y: where.y + 120 * (Math.random() - 0.5) }) + const where = { + x: level.enter.x + 50, + y: level.enter.y - 60 + } + b.spore({ + x: where.x + 100 * (Math.random() - 0.5), + y: where.y + 120 * (Math.random() - 0.5) + }) } } } @@ -998,8 +1012,14 @@ const simulation = { requestAnimationFrame(respawnWorms); if (!simulation.paused && !simulation.isChoosing) { wormCount-- - const where = { x: level.enter.x + 50, y: level.enter.y - 60 } - b.worm({ x: where.x + 100 * (Math.random() - 0.5), y: where.y + 120 * (Math.random() - 0.5) }) + const where = { + x: level.enter.x + 50, + y: level.enter.y - 60 + } + b.worm({ + x: where.x + 100 * (Math.random() - 0.5), + y: where.y + 120 * (Math.random() - 0.5) + }) } } } @@ -1011,10 +1031,19 @@ const simulation = { requestAnimationFrame(respawnFleas); if (!simulation.paused && !simulation.isChoosing) { fleaCount-- - const where = { x: level.enter.x + 50, y: level.enter.y - 60 } + const where = { + x: level.enter.x + 50, + y: level.enter.y - 60 + } const speed = 6 + 3 * Math.random() const angle = 2 * Math.PI * Math.random() - b.flea({ x: where.x + 100 * (Math.random() - 0.5), y: where.y + 120 * (Math.random() - 0.5) }, { x: speed * Math.cos(angle), y: speed * Math.sin(angle) }) + b.flea({ + x: where.x + 100 * (Math.random() - 0.5), + y: where.y + 120 * (Math.random() - 0.5) + }, { + x: speed * Math.cos(angle), + y: speed * Math.sin(angle) + }) } } } @@ -1171,7 +1200,7 @@ const simulation = { } if (tech.cyclicImmunity && m.immuneCycle < m.cycle + tech.cyclicImmunity) m.immuneCycle = m.cycle + tech.cyclicImmunity; //player is immune to damage for 60 cycles - fallCheck = function(who, save = false) { + fallCheck = function (who, save = false) { let i = who.length; while (i--) { if (who[i].position.y > simulation.fallHeight) { @@ -1555,7 +1584,12 @@ const simulation = { outHTML += "
" + simulation.constructMapString[i] + "
" } console.log(out) - navigator.clipboard.writeText(out).then(function() { /* clipboard successfully set */ }, function() { /* clipboard write failed */ console.log('copy failed') }); + navigator.clipboard.writeText(out).then(function () { + /* clipboard successfully set */ + }, function () { + /* clipboard write failed */ + console.log('copy failed') + }); document.getElementById("construct").innerHTML = outHTML }, // copyToClipBoard(value) { diff --git a/js/spawn.js b/js/spawn.js index 80af8ce..a8bd0d7 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -411,7 +411,7 @@ const spawn = { } } me.damageReductionDecay = function() { //slowly make the boss take more damage over time //damageReduction resets with each invulnerability phase - if (!(me.cycle % 60) && this.lastDamageCycle + 240 > this.cycle) this.damageReduction *= 1.017 //only decay once a second //only decay if the player has done damage in the last 4 seconds + if (!(me.cycle % 60) && this.lastDamageCycle + 240 > this.cycle) this.damageReduction *= 1.02 //only decay once a second //only decay if the player has done damage in the last 4 seconds } me.mobType = spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)] me.spawnMobs = function(index = 0) { @@ -976,6 +976,7 @@ const spawn = { // build.shareURL(false) setTimeout(function() { if (!simulation.onTitlePage) { + m.alive = false simulation.paused = true; // simulation.clearMap(); // Matter.Composite.clear(composite, keepStatic, [deep = false]) @@ -1533,6 +1534,101 @@ const spawn = { // } // }; // }, + zombie(x, y, radius, sides, color) { //mob that attacks other mobs + mobs.spawn(x, y, sides, radius, color); + let me = mob[mob.length - 1]; + me.isZombie = true + me.isDropPowerUp = false; + me.showHealthBar = false; + me.stroke = "#83a" + me.accelMag = 0.0015 + me.frictionAir = 0.01 + // me.repulsionRange = 400000 + radius * radius; //squared + // me.memory = 120; + me.seeAtDistance2 = 1000000 //1000 vision range + // Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback + me.do = function() { + this.zombieHealthBar(); + this.lookForMobTargets(); + this.attack(); + this.checkStatus(); + }; + me.mobSearchIndex = 0; + me.target = null + me.lookForMobTargets = function() { + if (this.target && !this.target.alive) this.target = null + if (this.target === null && !(simulation.cycle % 10) && mob.length > 1) { //if you have no target + this.mobSearchIndex++ //look for a different mob index every time + if (this.mobSearchIndex > mob.length - 1) this.mobSearchIndex = 0 + if ( + !mob[this.mobSearchIndex].isZombie && + (Vector.magnitudeSquared(Vector.sub(this.position, mob[this.mobSearchIndex].position)) < this.seeAtDistance2 || Matter.Query.ray(map, this.position, mob[this.mobSearchIndex].position).length === 0) + ) { + this.target = mob[this.mobSearchIndex] + } + } + } + me.zombieHealthBar = function() { + this.damage(0.001); //decay + + const h = this.radius * 0.3; + const w = this.radius * 2; + const x = this.position.x - w / 2; + const y = this.position.y - w * 0.7; + ctx.fillStyle = "rgba(100, 100, 100, 0.3)"; + ctx.fillRect(x, y, w, h); + ctx.fillStyle = "rgba(136, 51, 170,0.7)"; + ctx.fillRect(x, y, w * this.health, h); + } + me.hitCD = 0 + me.attack = function() { //hit non zombie mobs + if (this.hitCD < simulation.cycle) { + if (this.target) { + this.force = Vector.mult(Vector.normalise(Vector.sub(this.target.position, this.position)), this.accelMag * this.mass) + if (this.speed > 6) { // speed cap instead of friction to give more agility + Matter.Body.setVelocity(this, { + x: this.velocity.x * 0.97, + y: this.velocity.y * 0.97 + }); + } + } + + const hit = (who) => { + if (!who.isZombie && who.damageReduction) { + this.hitCD = simulation.cycle + 15 + //knock back away from recently hit mob + const force = Vector.mult(Vector.normalise(Vector.sub(who.position, this.position)), 0.03 * this.mass) + this.force.x -= force.x; + this.force.y -= force.y; + + this.target = null //look for a new target + + + + const dmg = 0.3 * m.dmgScale + who.damage(dmg); + simulation.drawList.push({ + x: this.position.x, + y: this.position.y, + radius: Math.log(dmg + 1.1) * 40 * who.damageReduction + 3, + color: simulation.playerDmgColor, + time: simulation.drawTime + }); + } + } + const collide = Matter.Query.collides(this, mob) //damage mob targets if nearby + if (collide.length > 1) { //don't count self collide + for (let i = 0, len = collide.length; i < len; i++) { + hit(collide[i].bodyA) + hit(collide[i].bodyB) + } + } + } + } + // me.onDamage = function(dmg) { + // } + + }, starter(x, y, radius = Math.floor(15 + 20 * Math.random())) { //easy mob for on level 1 mobs.spawn(x, y, 8, radius, "#9ccdc6"); let me = mob[mob.length - 1]; @@ -6674,7 +6770,7 @@ const spawn = { this.seePlayerByHistory(60); this.attraction(); this.checkStatus(); - this.eventHorizon = 900 + 200 * Math.sin(simulation.cycle * 0.005) + this.eventHorizon = 950 + 250 * Math.sin(simulation.cycle * 0.005) if (!simulation.isTimeSkipping) { if (Vector.magnitude(Vector.sub(this.position, m.pos)) < this.eventHorizon) { this.attraction(); diff --git a/js/tech.js b/js/tech.js index 7b2709e..e6e3196 100644 --- a/js/tech.js +++ b/js/tech.js @@ -395,7 +395,9 @@ const tech = { }, { name: "arsenal", - descriptionFunction() { return `+22% damage per unequipped gun (${(22 * Math.max(0, b.inventory.length-1)).toFixed(0)}%)` }, + descriptionFunction() { + return `+22% damage per unequipped gun (${(22 * Math.max(0, b.inventory.length-1)).toFixed(0)}%)
 ` + }, maxCount: 1, count: 0, frequency: 1, @@ -411,7 +413,9 @@ const tech = { }, { name: "active cooling", - descriptionFunction() { return `+28% fire rate per unequipped gun (${(28 * Math.max(0, b.inventory.length-1)).toFixed(0)}%)` }, //
but not including your equipped gun` }, + descriptionFunction() { + return `+28% fire rate per unequipped gun (${(28 * Math.max(0, b.inventory.length-1)).toFixed(0)}%)
 ` + }, //
but not including your equipped gun` }, maxCount: 1, count: 0, frequency: 1, @@ -483,22 +487,6 @@ const tech = { // } } }, - { - name: "first derivative", - descriptionFunction() { return `while your first gun is equipped
+15% defense per gun (${(100*(1-0.85 ** b.inventory.length)).toFixed(0)}%)` }, - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { return true }, - requires: "", - effect() { - tech.isFirstDer = true - }, - remove() { - tech.isFirstDer = false; - } - }, { name: "integrated armament", link: `integrated armament`, @@ -520,12 +508,16 @@ const tech = { }, { name: "supply chain", - descriptionFunction() { return `double your current ammo
+4% JUNK to tech pool` }, + descriptionFunction() { + return `double your current ammo
+4% JUNK to tech pool` + }, maxCount: 9, count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { for (let i = 0; i < b.guns.length; i++) { @@ -591,7 +583,9 @@ const tech = { }, { name: "catabolism", - descriptionFunction() { return `if you fire while out of ammo
spawn ${powerUps.orb.ammo(4)} and ${tech.isEnergyHealth ? "–4 maximum energy" : "–2 maximum health"}` }, + descriptionFunction() { + return `if you fire while out of ammo
spawn ${powerUps.orb.ammo(4)} and ${tech.isEnergyHealth ? "–4 maximum energy" : "–2 maximum health"}` + }, maxCount: 1, count: 0, frequency: 1, @@ -652,7 +646,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isTurret = true @@ -668,7 +664,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.restDamage += 0.5 @@ -677,6 +675,24 @@ const tech = { tech.restDamage = 1; } }, + { + name: "kinetic bombardment", + description: "damage is proportional to mob distance
up to +33% damage at 3000 displacement", + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + effect() { + tech.isFarAwayDmg = true; //used in mob.damage() + }, + remove() { + tech.isFarAwayDmg = false; + } + }, { name: "Higgs mechanism", description: "+45% fire rate
while firing your position is fixed", @@ -708,7 +724,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { // good with melee builds, content skipping builds tech.squirrelFx += 0.25; @@ -750,13 +768,15 @@ const tech = { // } // }, { - name: "Newton's 1st law", + name: "Newtons 1st law", description: "defense is proportional to your speed
up to +66% defense at 40 speed", maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isSpeedHarm = true //max at speed = 40 @@ -766,13 +786,15 @@ const tech = { } }, { - name: "Newton's 2nd law", + name: "Newtons 2nd law", description: "damage is proportional to your speed
up to +66% damage at 40 speed", maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isSpeedDamage = true //max at speed = 40 @@ -781,38 +803,6 @@ const tech = { tech.isSpeedDamage = false } }, - { - name: "kinetic bombardment", - description: "damage is proportional to mob distance
up to +33% damage at 3000 displacement", - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { return true }, - requires: "", - effect() { - tech.isFarAwayDmg = true; //used in mob.damage() - }, - remove() { - tech.isFarAwayDmg = false; - } - }, - { - name: "regression", - description: "bullet collisions increase vulnerability to
damage by +5% for mobs (+0.25% for bosses)", - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { return true }, - requires: "", - effect() { - tech.isLessDamageReduction = true - }, - remove() { - tech.isLessDamageReduction = false - } - }, { name: "microstates", link: `microstates`, @@ -821,7 +811,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isDamageFromBulletCount = true @@ -830,6 +822,24 @@ const tech = { tech.isDamageFromBulletCount = false } }, + { + name: "regression", + description: "bullet collisions increase vulnerability to
damage by +5% for mobs (+0.25% for bosses)", + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + effect() { + tech.isLessDamageReduction = true + }, + remove() { + tech.isLessDamageReduction = false + } + }, { name: "simulated annealing", description: "+20% damage
–20% fire rate", @@ -837,7 +847,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, damage: 1.2, effect() { tech.damage *= this.damage @@ -857,7 +869,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.fireRate *= 0.75 @@ -869,7 +883,23 @@ const tech = { b.setFireCD(); } }, - + { + name: "anti-shear topology", + link: `anti-shear topology`, + description: "+30% projectile duration
 ", //
drone spore worm flea missile foam wave neutron ice", + maxCount: 3, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed: () => true, + requires: "", + effect() { + tech.isBulletsLastLonger += 0.3 + }, + remove() { + tech.isBulletsLastLonger = 1; + } + }, { name: "fracture analysis", description: "if a mob is stunned it takes
+400% damage from bullet impacts", @@ -888,41 +918,6 @@ const tech = { tech.isCrit = false; } }, - { - name: "anti-shear topology", - link: `anti-shear topology`, - description: "+30% projectile duration", //
drone spore worm flea missile foam wave neutron ice", - maxCount: 3, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed: () => true, - requires: "", - effect() { - tech.isBulletsLastLonger += 0.3 - }, - remove() { - tech.isBulletsLastLonger = 1; - } - }, - { - name: "thermal runaway", - description: "after mobs die
they explode", - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { - return !tech.sporesOnDeath && !tech.nailsDeathMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath - }, - requires: "no other mob death tech", - effect() { - tech.isExplodeMob = true; - }, - remove() { - tech.isExplodeMob = false; - } - }, { name: "shear stress", description: "after mobs die
they release a nail that targets nearby mobs", @@ -941,10 +936,30 @@ const tech = { tech.nailsDeathMob = 0; } }, + { + name: "thermal runaway", + description: "after mobs die
they explode", + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return !tech.sporesOnDeath && !tech.nailsDeathMob && !tech.botSpawner && !tech.isMobBlockFling && !tech.iceIXOnDeath + }, + requires: "no other mob death tech", + effect() { + tech.isExplodeMob = true; + }, + remove() { + tech.isExplodeMob = false; + } + }, { name: "zoospore vector", link: `zoospore vector`, - descriptionFunction() { return `after mobs die
they have a +10% chance to grow ${b.guns[6].nameString('s')}` }, + descriptionFunction() { + return `after mobs die
they have a +10% chance to grow ${b.guns[6].nameString('s')}` + }, // description: "after mobs die
they have a +10% chance to grow spores", maxCount: 9, count: 0, @@ -966,6 +981,22 @@ const tech = { tech.sporesOnDeath = 0; } }, + { + name: "propagator", + description: "after mobs die advance time 0.5 seconds
+60% damage", + maxCount: 3, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed: () => true, + requires: "", + effect() { + tech.deathSkipTime++ + }, + remove() { + tech.deathSkipTime = 0 + } + }, { name: "bubble fusion", descriptionFunction() { @@ -975,7 +1006,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isShieldAmmo = true; @@ -986,7 +1019,7 @@ const tech = { }, { name: "reaction inhibitor", - description: "-12% maximum mob health", //health + description: "-12% maximum mob health
 ", //health maxCount: 3, count: 0, frequency: 1, @@ -1008,58 +1041,6 @@ const tech = { mobs.setMobSpawnHealth() } }, - { - name: "propagator", - description: "after mobs die advance time 0.5 seconds
+60% damage", - maxCount: 3, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed: () => true, - requires: "", - effect() { - tech.deathSkipTime++ - }, - remove() { - tech.deathSkipTime = 0 - } - }, - { - name: "decorrelation", - description: "if your gun or field are unused for 2 seconds
+70% defense", - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { - return !tech.isRewindField - }, - requires: "not retrocausality", - effect() { - tech.isNoFireDefense = true - }, - remove() { - tech.isNoFireDefense = false - } - }, - { - name: "anticorrelation", - description: "if your gun or field are unused for 2 seconds
+100% damage", - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { - return !tech.isRewindField - }, - requires: "not retrocausality", - effect() { - tech.isNoFireDamage = true - }, - remove() { - tech.isNoFireDamage = false - } - }, { name: "scrap bots", link: `scrap bots`, @@ -1103,14 +1084,16 @@ const tech = { { name: "nail-bot", link: `nail-bot`, - description: "a bot fires nails at mobs in line of sight", + description: "a bot fires nails at mobs in line of sight
 ", maxCount: 9, count: 0, frequency: 1, frequencyDefault: 1, isBot: true, isBotTech: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.nailBotCount++; @@ -1159,14 +1142,16 @@ const tech = { { name: "foam-bot", link: `foam-bot`, - description: "a bot fires foam at nearby mobs", + description: "a bot fires foam at nearby mobs
 ", maxCount: 9, count: 0, frequency: 1, frequencyDefault: 1, isBot: true, isBotTech: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.foamBotCount++; @@ -1222,7 +1207,9 @@ const tech = { frequencyDefault: 1, isBot: true, isBotTech: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.boomBotCount++; @@ -1336,7 +1323,9 @@ const tech = { frequencyDefault: 1, isBot: true, isBotTech: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { b.orbitBot(); @@ -1401,7 +1390,9 @@ const tech = { frequencyDefault: 1, isBot: true, isBotTech: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.dynamoBotCount++; @@ -1447,32 +1438,6 @@ const tech = { tech.isDynamoBotUpgrade = false } }, - { - name: "bot fabrication", - link: `bot fabrication`, - descriptionFunction() { - return `after you collect ${powerUps.orb.research(2 + Math.floor(0.1666 * b.totalBots()))}use them to build a
random bot (+1 cost every 5 bots)` - }, - // description: `if you collect ${powerUps.orb.research(2)}use them to build a
random bot (+1 cost every 5 bots)`, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - isBotTech: true, - allowed() { - return powerUps.research.count > 1 || build.isExperimentSelection - }, - requires: "at least 2 research", - effect() { - tech.isRerollBots = true; - powerUps.research.changeRerolls(0) - simulation.makeTextLog(`m.research = 0`) - }, - remove() { - tech.isRerollBots = false; - // this.description = `if you collect ${powerUps.orb.research(2 + Math.floor(0.2 * b.totalBots()))}use them to build a
random bot (+1 cost every 5 bots)` - } - }, { name: "perimeter defense", description: "for each permanent bot
+6% defense", @@ -1511,6 +1476,32 @@ const tech = { tech.isBotDamage = false } }, + { + name: "bot fabrication", + link: `bot fabrication`, + descriptionFunction() { + return `after you collect ${powerUps.orb.research(2 + Math.floor(0.1666 * b.totalBots()))}use them to build a
random bot (+1 cost every 5 bots)` + }, + // description: `if you collect ${powerUps.orb.research(2)}use them to build a
random bot (+1 cost every 5 bots)`, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + isBotTech: true, + allowed() { + return powerUps.research.count > 1 || build.isExperimentSelection + }, + requires: "at least 2 research", + effect() { + tech.isRerollBots = true; + powerUps.research.changeRerolls(0) + simulation.makeTextLog(`m.research = 0`) + }, + remove() { + tech.isRerollBots = false; + // this.description = `if you collect ${powerUps.orb.research(2 + Math.floor(0.2 * b.totalBots()))}use them to build a
random bot (+1 cost every 5 bots)` + } + }, { name: "ersatz bots", link: `ersatz bots`, @@ -1654,9 +1645,45 @@ const tech = { } } }, + { + name: "decorrelation", + description: "if your gun or field are unused for 2 seconds
+70% defense", + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return !tech.isRewindField + }, + requires: "not retrocausality", + effect() { + tech.isNoFireDefense = true + }, + remove() { + tech.isNoFireDefense = false + } + }, + { + name: "anticorrelation", + description: "if your gun or field are unused for 2 seconds
+100% damage", + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return !tech.isRewindField + }, + requires: "not retrocausality", + effect() { + tech.isNoFireDamage = true + }, + remove() { + tech.isNoFireDamage = false + } + }, { name: "mass driver", - description: "+300% block collision damage", + description: "+300% block collision damage
 ", maxCount: 1, count: 0, frequency: 1, @@ -1765,41 +1792,6 @@ const tech = { tech.isBlockPowerUps = false } }, - { - name: "Pauli exclusion", - description: `after mob collisions
become invulnerable for +3 seconds`, - maxCount: 9, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { return true }, - requires: "", - effect() { - m.collisionImmuneCycles += 180; - if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage - }, - remove() { - m.collisionImmuneCycles = 30; - } - }, - { - name: "spin–statistics theorem", - description: `every 7 seconds
become invulnerable for +1.8 seconds`, - maxCount: 3, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { - return true //m.collisionImmuneCycles > 30 - }, - requires: "", - effect() { - tech.cyclicImmunity += 108; - }, - remove() { - tech.cyclicImmunity = 0; - } - }, { name: "NOR gate", description: "if flip-flop is OFF
become invulnerable to your next collision", @@ -1862,7 +1854,7 @@ const tech = { description: `toggle ON and OFF after a collision
unlock advanced tech that runs if ON`, nameInfo: "", addNameInfo() { - setTimeout(function() { + setTimeout(function () { if (document.getElementById("tech-flip-flop")) { if (tech.isFlipFlopOn) { document.getElementById("tech-flip-flop").innerHTML = ` = ON` @@ -1995,12 +1987,14 @@ const tech = { }, remove() { tech.isFlipFlopCoupling = false; - if (tech.isFlipFlop || tech.isRelay) { - if (tech.isFlipFlopOn) { - m.couplingChange(-this.bonus) - } else { - for (let i = 0; i < mob.length; i++) { - if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP + if (this.count) { + if (tech.isFlipFlop || tech.isRelay) { + if (tech.isFlipFlopOn) { + m.couplingChange(-this.bonus) + } else { + for (let i = 0; i < mob.length; i++) { + if (mob[i].isDecoupling) mob[i].alive = false //remove WIMP + } } } } @@ -2011,7 +2005,7 @@ const tech = { description: `toggle ON and OFF after picking up a power up
unlock advanced tech that runs if ON`, nameInfo: "", addNameInfo() { - setTimeout(function() { + setTimeout(function () { if (document.getElementById("tech-switch")) { if (tech.isFlipFlopOn) { document.getElementById("tech-switch").innerHTML = ` = ON` @@ -2099,39 +2093,23 @@ const tech = { } }, { - name: "liquid cooling", - description: `after losing health
freeze all mobs for 7 seconds`, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return tech.isSlowFPS + name: "first derivative", + descriptionFunction() { + return `while your first gun is equipped
+15% defense per gun (${(100*(1-0.85 ** b.inventory.length)).toFixed(0)}%)` }, - requires: "clock gating", - effect() { - tech.isHarmFreeze = true; - }, - remove() { - tech.isHarmFreeze = false; - } - }, - { - name: "clock gating", - description: `after losing health slow time by 50%
+20% defense`, maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, allowed() { - return simulation.fpsCapDefault > 45 + return true }, - requires: "FPS above 45", + requires: "", effect() { - tech.isSlowFPS = true; + tech.isFirstDer = true }, remove() { - tech.isSlowFPS = false; + tech.isFirstDer = false; } }, { @@ -2141,7 +2119,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isMACHO = true; //this harm reduction comes from the particle toggling tech.isHarmMACHO @@ -2198,7 +2178,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isHarmArmor = true; @@ -2207,6 +2189,79 @@ const tech = { tech.isHarmArmor = false; } }, + { + name: "Pauli exclusion", + description: `after mob collisions
become invulnerable for +3 seconds`, + maxCount: 9, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + effect() { + m.collisionImmuneCycles += 180; + if (m.immuneCycle < m.cycle + m.collisionImmuneCycles) m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage + }, + remove() { + m.collisionImmuneCycles = 30; + } + }, + { + name: "spin–statistics theorem", + description: `every 7 seconds
become invulnerable for +1.8 seconds`, + maxCount: 3, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true //m.collisionImmuneCycles > 30 + }, + requires: "", + effect() { + tech.cyclicImmunity += 108; + }, + remove() { + tech.cyclicImmunity = 0; + } + }, + { + name: "liquid cooling", + description: `after losing health
freeze all mobs for 7 seconds`, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.isSlowFPS + }, + requires: "clock gating", + effect() { + tech.isHarmFreeze = true; + }, + remove() { + tech.isHarmFreeze = false; + } + }, + { + name: "clock gating", + description: `after losing health slow time by 50%
+20% defense`, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return simulation.fpsCapDefault > 45 + }, + requires: "FPS above 45", + effect() { + tech.isSlowFPS = true; + }, + remove() { + tech.isSlowFPS = false; + } + }, { name: "CPT symmetry", // description: "charge, parity, and time invert to undo defense
rewind (1.5—5) seconds for (66—220) energy", @@ -2392,14 +2447,16 @@ const tech = { { name: "electronegativity", descriptionFunction() { - return `+1% damage per 8 stored energy (${(12.5*m.energy).toFixed(0)}%)` + return `+1% damage per 8 stored energy
(${(12.5*m.energy).toFixed(0)}%)` }, // description: "+1% damage per 8 stored energy", maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isEnergyDamage = true @@ -2459,7 +2516,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", damage: 1.55, effect() { @@ -2494,7 +2553,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.bonusEnergy += 0.66 @@ -2512,8 +2573,8 @@ const tech = { } }, { - name: "Maxwell's demon", - description: "energy above your max decays 95% slower
+5% JUNK to tech pool", + name: "Maxwells demon", + description: "energy above your max decays 96% slower
+5% JUNK to tech pool", maxCount: 1, count: 0, frequency: 2, @@ -2523,7 +2584,7 @@ const tech = { }, requires: "energy above your max", effect() { - tech.overfillDrain = 0.92 //70% = 1-(1-0.75)/(1-0.15) //92% = 1-(1-0.75)/(1-0.87) + tech.overfillDrain = 0.94 //70% = 1-(1-0.75)/(1-0.15) //92% = 1-(1-0.75)/(1-0.87) this.refundAmount += tech.addJunkTechToPool(0.05) }, refundAmount: 0, @@ -2548,7 +2609,7 @@ const tech = { requires: "not parasitism", effect() { tech.isCrouchRegen = true; //only used to check for requirements - m.regenEnergy = function() { + m.regenEnergy = function () { if (m.immuneCycle < m.cycle && m.crouch) m.energy += 7 * m.fieldRegen; if (m.energy < 0) m.energy = 0 } @@ -2560,12 +2621,14 @@ const tech = { }, { name: "energy conservation", - description: "5% of damage done recovered as energy", + description: "5% of damage done recovered as energy
 ", maxCount: 9, count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.energySiphon += 0.05; @@ -2574,6 +2637,29 @@ const tech = { tech.energySiphon = 0; } }, + { + name: "parasitism", + description: "if a mob has died in the last 5 seconds
+60% damage, inhibit energy generation", + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return !tech.isCrouchRegen + }, + requires: "not inductive charging", + effect() { + tech.isDamageAfterKillNoRegen = true; + m.regenEnergy = function () { + if (m.immuneCycle < m.cycle && (m.lastKillCycle + 300 < m.cycle)) m.energy += m.fieldRegen; + if (m.energy < 0) m.energy = 0 + } + }, + remove() { + if (this.count) m.regenEnergy = m.regenEnergyDefault + tech.isDamageAfterKillNoRegen = false; + } + }, { name: "waste heat recovery", description: "if a mob has died in the last 5 seconds
generate 5% of max energy per second", @@ -2581,7 +2667,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isEnergyRecovery = true; @@ -2598,7 +2686,9 @@ const tech = { frequency: 1, frequencyDefault: 1, isHealTech: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isHealthRecovery = true; @@ -2607,29 +2697,6 @@ const tech = { tech.isHealthRecovery = false; } }, - { - name: "parasitism", - description: "if a mob has died in the last 5 seconds
+60% damage, inhibit energy generation", - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { - return !tech.isCrouchRegen - }, - requires: "not inductive charging", - effect() { - tech.isDamageAfterKillNoRegen = true; - m.regenEnergy = function() { - if (m.immuneCycle < m.cycle && (m.lastKillCycle + 300 < m.cycle)) m.energy += m.fieldRegen; - if (m.energy < 0) m.energy = 0 - } - }, - remove() { - if (this.count) m.regenEnergy = m.regenEnergyDefault - tech.isDamageAfterKillNoRegen = false; - } - }, { name: "torpor", description: "if a mob has not died in the last 5 seconds
+66% defense", @@ -2637,7 +2704,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isHarmReduceNoKill = true; @@ -2646,46 +2715,6 @@ const tech = { tech.isHarmReduceNoKill = false; } }, - { - name: "Zeno's paradox", - descriptionFunction() { - return `+85% defense
–5% of current ${tech.isEnergyHealth ? "energy": "health"} every 5 seconds` - }, - // description: "+85% defense
–5% of current health every 5 seconds", - // description: "every 5 seconds remove 1/10 of your health
reduce defense by 90%", - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { return true }, - requires: "", - effect() { - tech.isZeno = true; - }, - remove() { - tech.isZeno = false; - } - }, - { - name: "negative feedback", - descriptionFunction() { - return `for each ${tech.isEnergyHealth ? "energy": "health"} below 100
+0.7% damage (${(70*Math.max(0, 1 - (tech.isEnergyHealth ? m.energy : m.health))).toFixed(0)}%)` - }, - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { - return m.health < 0.6 || build.isExperimentSelection - }, - requires: "health below 60", - effect() { - tech.isLowHealthDmg = true; //used in mob.damage() - }, - remove() { - tech.isLowHealthDmg = false; - } - }, { name: "homeostasis", descriptionFunction() { @@ -2706,6 +2735,48 @@ const tech = { tech.isLowHealthDefense = false; } }, + { + name: "negative feedback", + descriptionFunction() { + return `for each ${tech.isEnergyHealth ? "energy": "health"} below 100
+0.7% damage (${(70*Math.max(0, 1 - (tech.isEnergyHealth ? m.energy : m.health))).toFixed(0)}%)` + }, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return m.health < 0.6 || build.isExperimentSelection + }, + requires: "health below 60", + effect() { + tech.isLowHealthDmg = true; //used in mob.damage() + }, + remove() { + tech.isLowHealthDmg = false; + } + }, + { + name: "Zenos paradox", + descriptionFunction() { + return `+85% defense
–5% of current ${tech.isEnergyHealth ? "energy": "health"} every 5 seconds` + }, + // description: "+85% defense
–5% of current health every 5 seconds", + // description: "every 5 seconds remove 1/10 of your health
reduce defense by 90%", + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + effect() { + tech.isZeno = true; + }, + remove() { + tech.isZeno = false; + } + }, { name: "antiscience", descriptionFunction() { @@ -2716,7 +2787,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", damage: 1.66, effect() { @@ -2728,6 +2801,45 @@ const tech = { tech.isTechDamage = false; } }, + { + name: "ergodicity", + descriptionFunction() { + return `${powerUps.orb.heal()} have -50% effect
+66% damage` + }, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + allowed() { + return true + }, + requires: "", + damage: 1.66, + effect() { + tech.damage *= this.damage + tech.isHalfHeals = true; + for (let i = 0; i < powerUp.length; i++) { + if (powerUp[i].name === "heal") { + const scale = Math.sqrt(0.5) + powerUp[i].size *= scale + Matter.Body.scale(powerUp[i], scale, scale); //grow + } + } + }, + remove() { + if (this.count) { + tech.damage /= this.damage + for (let i = 0; i < powerUp.length; i++) { + if (powerUp[i].name === "heal") { + const scale = 1 / Math.sqrt(0.5) + powerUp[i].size *= scale + Matter.Body.scale(powerUp[i], scale, scale); //grow + } + } + } + tech.isHalfHeals = false; + } + }, { name: "fluoroantimonic acid", description: "if your health is above 100
+35% damage", @@ -2753,7 +2865,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isFallingDamage = true; @@ -2765,43 +2879,6 @@ const tech = { m.setMaxHealth(); } }, - { - name: "quenching", - descriptionFunction() { - return `after over healing from ${powerUps.orb.heal()}
gain max health and lose current health` - }, - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - allowed() { return true }, - requires: "", - effect() { - tech.isOverHeal = true; - }, - remove() { - tech.isOverHeal = false; - } - }, - { - name: "negative entropy", - descriptionFunction() { - return `at the start of each level
for every 33% missing ${tech.isEnergyHealth ? "energy": "health"} spawn ${powerUps.orb.heal()}` - }, - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - isHealTech: true, - allowed() { return true }, - requires: "", - effect() { - tech.isHealLowHealth = true; - }, - remove() { - tech.isHealLowHealth = false; - } - }, { name: "adiabatic healing", descriptionFunction() { @@ -2846,40 +2923,44 @@ const tech = { } }, { - name: "ergodicity", + name: "quenching", descriptionFunction() { - return `${powerUps.orb.heal()} have -50% effect
+66% damage` + return `after over healing from ${powerUps.orb.heal()}
gain max health and lose current health` }, maxCount: 1, count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", - damage: 1.66, effect() { - tech.damage *= this.damage - tech.isHalfHeals = true; - for (let i = 0; i < powerUp.length; i++) { - if (powerUp[i].name === "heal") { - const scale = Math.sqrt(0.5) - powerUp[i].size *= scale - Matter.Body.scale(powerUp[i], scale, scale); //grow - } - } + tech.isOverHeal = true; }, remove() { - if (this.count) { - tech.damage /= this.damage - for (let i = 0; i < powerUp.length; i++) { - if (powerUp[i].name === "heal") { - const scale = 1 / Math.sqrt(0.5) - powerUp[i].size *= scale - Matter.Body.scale(powerUp[i], scale, scale); //grow - } - } - } - tech.isHalfHeals = false; + tech.isOverHeal = false; + } + }, + { + name: "negative entropy", + descriptionFunction() { + return `at the start of each level
for every 33% missing ${tech.isEnergyHealth ? "energy": "health"} spawn ${powerUps.orb.heal()}` + }, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + isHealTech: true, + allowed() { + return true + }, + requires: "", + effect() { + tech.isHealLowHealth = true; + }, + remove() { + tech.isHealLowHealth = false; } }, { @@ -2892,7 +2973,9 @@ const tech = { frequency: 1, frequencyDefault: 1, isHealTech: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.healthDrain += 0.02; @@ -2912,7 +2995,9 @@ const tech = { frequencyDefault: 1, isNonRefundable: true, isBadRandomOption: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { for (let i = 0; i < 13; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "heal"); @@ -2926,7 +3011,7 @@ const tech = { name: "anthropic principle", nameInfo: "", addNameInfo() { - setTimeout(function() { + setTimeout(function () { powerUps.research.changeRerolls(0) }, 1000); }, @@ -2945,7 +3030,7 @@ const tech = { effect() { tech.isDeathAvoid = true; tech.isDeathAvoidedThisLevel = false; - setTimeout(function() { + setTimeout(function () { powerUps.research.changeRerolls(0) }, 1000); }, @@ -2998,7 +3083,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isImmortal = true; @@ -3031,7 +3118,7 @@ const tech = { { name: "many-worlds", // description: "each level is an alternate reality, where you
find a tech at the start of each level", - description: `on each new level enter an
alternate reality and spawn a tech power up`, + description: `on each new level spawn a tech power up
and enter an alternate reality`, maxCount: 1, count: 0, frequency: 1, @@ -3050,7 +3137,7 @@ const tech = { { name: "Ψ(t) collapse", link: `Ψ(t) collapse`, - description: `after you research enter an alternate reality
spawn ${powerUps.orb.research(16)}`, + description: `spawn ${powerUps.orb.research(16)}
after you research enter an alternate reality`, maxCount: 1, count: 0, frequency: 1, @@ -3145,7 +3232,7 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return powerUps.research.count === 0 && !tech.isSuperDeterminism && !tech.isRerollHaste && !tech.isResearchReality + return powerUps.research.count < 1 && !tech.isSuperDeterminism && !tech.isRerollHaste && !tech.isResearchReality }, requires: "no research, not superdeterminism, Ψ(t) collapse, perturbation theory", effect() { @@ -3158,7 +3245,9 @@ const tech = { { name: "Bayesian statistics", // description: `for each ${powerUps.orb.research(1)} in your inventory
+3.8% damage`, - descriptionFunction() { return `+3% damage per ${powerUps.orb.research(1)} (${(3*powerUps.research.count).toFixed(0)}%)
spawn ${powerUps.orb.research(this.bonusResearch)}` }, + descriptionFunction() { + return `spawn ${powerUps.orb.research(this.bonusResearch)}
+3% damage per ${powerUps.orb.research(1)} (${(3*powerUps.research.count).toFixed(0)}%)` + }, maxCount: 1, count: 0, frequency: 2, @@ -3219,7 +3308,7 @@ const tech = { } }, { - name: "cross disciplinary", + name: "cross-disciplinary", description: "tech have an extra field or gun choice
+5% chance to duplicate spawned power ups", maxCount: 1, count: 0, @@ -3273,7 +3362,9 @@ const tech = { frequencyDefault: 1, isNonRefundable: true, // isJunk: true, - allowed() { return !tech.isDeterminism }, + allowed() { + return !tech.isDeterminism + }, requires: "not determinism", effect() { tech.tooManyTechChoices = 1 @@ -3301,7 +3392,7 @@ const tech = { allowed() { return !tech.extraChoices && !tech.isExtraGunField && !tech.isFlipFlopChoices }, - requires: "not emergence, cross disciplinary, integrated circuit", + requires: "not emergence, cross-disciplinary, integrated circuit", effect() { tech.isDeterminism = true; //if you change the number spawned also change it in Born rule @@ -3313,7 +3404,7 @@ const tech = { }, { name: "superdeterminism", - description: `spawn 5 tech
you have no cancel and ${powerUps.orb.research(1)} no longer spawn`, + description: `spawn 5 tech
you can't cancel and ${powerUps.orb.research(1)} no longer spawn`, maxCount: 1, count: 0, frequency: 3, @@ -3342,7 +3433,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isTechDebt = true; @@ -3377,7 +3470,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return tech.junkCount > 0 }, + allowed() { + return tech.junkCount > 0 + }, requires: "some JUNK tech", effect() { tech.isMetaAnalysis = true @@ -3393,7 +3488,9 @@ const tech = { count: 0, frequency: 1, frequencyDefault: 1, - allowed() { return true }, + allowed() { + return true + }, requires: "", damage: 1.38, effect() { @@ -3523,7 +3620,7 @@ const tech = { frequency: 1, frequencyDefault: 1, allowed() { - return (build.isExperimentSelection || powerUps.research.count > 1) + return true }, requires: "", effect() { @@ -3560,13 +3657,26 @@ const tech = { researchUsed: 0, couplingToResearch: 0.25, effect() { - let count = 0 - while (powerUps.research.count > 0 && powerUps.research.count !== Infinity) { - powerUps.research.changeRerolls(-1) - count += 2.5 - this.researchUsed++ + // let count = 0 + // while (powerUps.research.count > 0 && powerUps.research.count !== Infinity) { + // powerUps.research.changeRerolls(-1) + // count += 2.5 + // this.researchUsed++ + // } + // powerUps.spawnDelay("coupling", Math.floor(count)) + + let cycle = () => { + if (powerUps.research.count > 0 && powerUps.research.count !== Infinity) { + if (m.alive) requestAnimationFrame(cycle); + if (!simulation.paused && !simulation.isChoosing) { //&& !(simulation.cycle % 2) + powerUps.research.changeRerolls(-1) + this.researchUsed++ + powerUps.spawn(m.pos.x + 50 * (Math.random() - 0.5), m.pos.y + 50 * (Math.random() - 0.5), "coupling"); + } + } else { //exit delay loop + } } - powerUps.spawnDelay("coupling", Math.floor(count)) + requestAnimationFrame(cycle); }, remove() { if (this.count) { @@ -3621,7 +3731,7 @@ const tech = { { name: "residual dipolar coupling", descriptionFunction() { - return `clicking × to cancel a field, tech, or gun
spawns ${powerUps.orb.coupling(5)}that each give +0.1 coupling
${ m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per coupling"}` + return `clicking cancel for a field, tech, or gun
spawns ${powerUps.orb.coupling(5)}that each give +0.1 coupling
${ m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per coupling"}` }, maxCount: 1, count: 0, @@ -3641,7 +3751,7 @@ const tech = { { name: "commodities exchange", descriptionFunction() { - return `clicking × to cancel a field, tech, or gun
spawns 5-10 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}` + return `clicking cancel for a field, tech, or gun
spawns 5-10 ${powerUps.orb.heal()}, ${powerUps.orb.ammo()}, or ${powerUps.orb.research(1)}` }, maxCount: 1, count: 0, @@ -3661,7 +3771,7 @@ const tech = { { name: "options exchange", link: `options exchange`, - description: `clicking × for a field, tech, or gun has a 85%
chance to randomize choices and not cancel`, + description: `clicking cancel for a field, tech, or gun
has a 85% chance to randomize choices`, maxCount: 1, count: 0, frequency: 1, @@ -3679,7 +3789,7 @@ const tech = { }, { name: "futures exchange", - description: "clicking × to cancel a field, tech, or gun
gives +4.3% power up duplication chance", + description: "clicking cancel for a field, tech, or gun
gives +4.3% power up duplication chance", // descriptionFunction() { // return `clicking × to cancel a field, tech, or gun
gives +${4.9 - 0.15*simulation.difficultyMode}% power up duplication chance` // }, @@ -3729,7 +3839,7 @@ const tech = { }, { name: "stimulated emission", - description: "+15% chance to duplicate spawned power ups
but, after a collision eject 1 tech", + description: "+15% chance to duplicate spawned power ups,
but after a collision eject 1 tech", maxCount: 1, count: 0, frequency: 1, @@ -3771,7 +3881,7 @@ const tech = { }, { name: "correlated damage", - description: "duplication increases damage", + description: "duplication increases damage
 ", maxCount: 1, count: 0, frequency: 1, @@ -3860,7 +3970,7 @@ const tech = { }, { - name: "Occam's razor", + name: "Occams razor", descriptionFunction() { return `randomly remove half your tech
for each removed +${this.damagePerRemoved * 100 }% damage (~${(this.count === 0) ? this.damagePerRemoved * 50 * tech.totalCount : this.damage*100}%)` }, @@ -3925,7 +4035,7 @@ const tech = { remove() {} }, { - name: "monte carlo experiment", + name: "Monte Carlo method", description: "remove 1 random tech
spawn 2 tech", maxCount: 1, count: 0, @@ -3945,7 +4055,9 @@ const tech = { }, { name: "strange attractor", - descriptionFunction() { return `use ${powerUps.orb.research(2)} to spawn 1 tech with
double your duplication chance (${(2*tech.duplicationChance()*100).toFixed(0)}%)` }, + descriptionFunction() { + return `use ${powerUps.orb.research(2)} to spawn 1 tech with
double your duplication chance (${(2*tech.duplicationChance()*100).toFixed(0)}%)` + }, // description: `use ${powerUps.orb.research(2)} to spawn 1 tech with double
your duplication chance (${(2*tech.duplicationChance()*100).toFixed(0)}%)`, maxCount: 1, count: 0, @@ -4077,7 +4189,7 @@ const tech = { }, { name: "needle gun", - description: "nail gun and shotgun fire mob piercing needles", + description: "nail gun and shotgun fire mob piercing needles
 ", isGunTech: true, maxCount: 1, count: 0, @@ -4114,9 +4226,28 @@ const tech = { } } }, + { + name: "stress concentration", + description: "mobs below 50% durability die after you shoot
them near their center with needles or rivets", + isGunTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return (tech.isNeedles || tech.isRivets) && !tech.isNailCrit && !tech.isIncendiary + }, + requires: "needles, rivets, not incendiary, supercritical fission", + effect() { + tech.isCritKill = true + }, + remove() { + tech.isCritKill = false + } + }, { name: "rivet gun", - description: "nail gun and shotgun slowly lob a heavy rivet", + description: "nail gun and shotgun slowly lob a heavy rivet
 ", isGunTech: true, maxCount: 1, count: 0, @@ -4148,46 +4279,6 @@ const tech = { tech.isRivets = false } }, - { - name: "caliber", - description: `rivets, needles, super balls, and nails
have +30% mass and physical damage`, - isGunTech: true, - maxCount: 9, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine)) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1 - }, - requires: "nails, nail gun, rivets, shotgun, super balls, mine", - effect() { - tech.bulletSize = 1 + 0.25 * Math.pow(this.count + 1, 0.5) - }, - remove() { - tech.bulletSize = 1; - } - }, - { - name: "ricochet", - description: "after nails hit a mob they rebound towards
a new mob with +180% damage per bounce", - isGunTech: true, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - // return (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("mines")) - return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine)) || (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot) && !tech.isRivets && !tech.isNeedles) - }, - // - requires: "nail gun, not rotary cannon, rivets, or needles", - effect() { - tech.isRicochet = true - }, - remove() { - tech.isRicochet = false - } - }, { name: "pneumatic actuator", description: "nail gun takes no time to ramp up
to its fastest fire rate", @@ -4230,28 +4321,20 @@ const tech = { requires: "nail gun, not rivets, needles", effect() { tech.isIceCrystals = true; - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "nail gun") { - b.guns[i].ammoPack = Infinity - b.guns[i].recordedAmmo = b.guns[i].ammo - b.guns[i].ammo = Infinity - simulation.updateGunHUD(); - break; - } - } + b.guns[0].ammoPack = Infinity + b.guns[0].recordedAmmo = b.guns[i].ammo + b.guns[0].ammo = Infinity + simulation.updateGunHUD(); }, remove() { if (tech.isIceCrystals) { tech.isIceCrystals = false; - for (i = 0, len = b.guns.length; i < len; i++) { //find which gun - if (b.guns[i].name === "nail gun") { - b.guns[i].ammoPack = b.guns[i].defaultAmmoPack; - if (b.guns[i].recordedAmmo) b.guns[i].ammo = b.guns[i].recordedAmmo - simulation.updateGunHUD(); - break; - } - } + b.guns[0].ammoPack = b.guns[0].defaultAmmoPack; + if (b.guns[0].recordedAmmo) b.guns[0].ammo = b.guns[0].recordedAmmo + simulation.updateGunHUD(); } + tech.isIceCrystals = false; + if (b.guns[0].ammo === Infinity) b.guns[0].ammo = 0 } }, { @@ -4282,22 +4365,22 @@ const tech = { } }, { - name: "stress concentration", - description: "mobs below 50% durability die after you shoot
them near their center with needles or rivets", + name: "gauge", + description: `rivets, needles, super balls, and nails
have +30% mass and physical damage`, isGunTech: true, - maxCount: 1, + maxCount: 9, count: 0, frequency: 2, frequencyDefault: 2, allowed() { - return (tech.isNeedles || tech.isRivets) && !tech.isNailCrit && !tech.isIncendiary + return tech.isMineDrop + tech.isNailBotUpgrade + tech.fragments + tech.nailsDeathMob + (tech.haveGunCheck("super balls") + (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine)) + (tech.haveGunCheck("nail gun")) + tech.isNeedles + tech.isNailShot + tech.isRivets) * 2 > 1 }, - requires: "needles, rivets, not incendiary, supercritical fission", + requires: "nails, nail gun, rivets, shotgun, super balls, mine", effect() { - tech.isCritKill = true + tech.bulletSize = 1 + 0.25 * Math.pow(this.count + 1, 0.5) }, remove() { - tech.isCritKill = false + tech.bulletSize = 1; } }, { @@ -4420,8 +4503,8 @@ const tech = { } }, { - name: "Newton's 3rd law", - description: "+66% shotgun fire rate and recoil", + name: "Newtons 3rd law", + description: "+66% shotgun fire rate and recoil
 ", isGunTech: true, maxCount: 1, count: 0, @@ -4450,7 +4533,7 @@ const tech = { allowed() { return (tech.haveGunCheck("shotgun")) && !tech.isShotgunRecoil }, - requires: "shotgun, not Newton's 3rd law", + requires: "shotgun, not Newtons 3rd law", effect() { tech.isShotgunReversed = true; }, @@ -4461,7 +4544,7 @@ const tech = { { name: "nail-shot", link: `nail-shot`, - description: "shotgun drives a long clip of nails", + description: "shotgun drives a long clip of nails
 ", isGunTech: true, maxCount: 1, count: 0, @@ -4481,7 +4564,7 @@ const tech = { { name: "foam-shot", link: `foam-shot`, - description: "shotgun sprays sticky foam bubbles", + description: "shotgun sprays sticky foam bubbles
 ", isGunTech: true, maxCount: 1, count: 0, @@ -4501,7 +4584,7 @@ const tech = { { name: "ice-shot", link: `ice-shot`, - description: "shotgun grows freezing ice IX crystals", + description: "shotgun grows freezing ice IX crystals
 ", isGunTech: true, maxCount: 1, count: 0, @@ -4520,7 +4603,7 @@ const tech = { }, { name: "freezer burn", - description: "mobs frozen while below 33% durability die", + description: "mobs frozen while below 33% durability die
 ", isGunTech: true, maxCount: 1, count: 0, @@ -4661,7 +4744,7 @@ const tech = { }, { name: "super duper", - description: `randomly fire +0, +1, or +2 extra super balls`, + description: `randomly fire +0, +1, or +2 extra super balls
 `, isGunTech: true, maxCount: 9, count: 0, @@ -4680,7 +4763,7 @@ const tech = { }, { name: "super ball", - description: "fire just 1 large super ball
that stuns mobs for 3 second", + description: "fire just 1 large super ball
that stuns mobs for 2 second", isGunTech: true, maxCount: 1, count: 0, @@ -4826,6 +4909,8 @@ const tech = { if (this.count > 0 && b.guns[3].savedAmmo !== undefined) { b.guns[3].ammo = b.guns[3].savedAmmo simulation.updateGunHUD(); + } else if (b.guns[3].ammo === Infinity) { + b.guns[3].ammo = 0 } } }, @@ -5077,7 +5162,7 @@ const tech = { }, { name: "ammonium nitrate", - description: "+24% explosive damage, radius", + description: "+24% explosive damage, radius
 ", isGunTech: true, maxCount: 9, count: 0, @@ -5393,7 +5478,7 @@ const tech = { }, { name: "nuclear transmutation", - description: "+47% radiation damage
nail, drone, neutron bomb, iridium, string, deflect", + description: "+47% radiation damage
nail, drone, neutron bomb, iridium, cosmic string, deflect", isGunTech: true, maxCount: 9, count: 0, @@ -5430,6 +5515,27 @@ const tech = { tech.isRadioactiveResistance = false } }, + { + name: "ricochet", + description: "after nails hit a mob they rebound towards
a new mob with +180% damage per bounce", + isGunTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + // return (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("mines")) + return tech.isMineDrop || tech.isNailBotUpgrade || tech.fragments || tech.nailsDeathMob || (tech.haveGunCheck("mine") && !(tech.isLaserMine || tech.isFoamMine)) || (tech.haveGunCheck("nail gun") && !tech.isRivets && !tech.isNeedles) || (tech.haveGunCheck("shotgun") && (tech.isNeedles || tech.isNailShot) && !tech.isRivets && !tech.isNeedles) + }, + // + requires: "nail gun, not rotary cannon, rivets, or needles", + effect() { + tech.isRicochet = true + }, + remove() { + tech.isRicochet = false + } + }, { name: "booby trap", description: "60% chance to drop a mine from power ups
+46% JUNK to tech pool", @@ -5444,7 +5550,10 @@ const tech = { requires: "mines", effect() { tech.isMineDrop = true; - if (tech.isMineDrop) b.mine(m.pos, { x: 0, y: 0 }, 0) + if (tech.isMineDrop) b.mine(m.pos, { + x: 0, + y: 0 + }, 0) this.refundAmount += tech.addJunkTechToPool(0.46) }, refundAmount: 0, @@ -5457,7 +5566,7 @@ const tech = { } }, { - name: "elephant's toothpaste", + name: "elephants toothpaste", description: "mines catalyze a reaction
that yields foam bubbles", isGunTech: true, maxCount: 1, @@ -5506,7 +5615,7 @@ const tech = { allowed() { return tech.haveGunCheck("mine") && !tech.isFoamMine }, - requires: "mines, not elephant's toothpaste", + requires: "mines, not elephants toothpaste", effect() { tech.isMineSentry = true; }, @@ -5556,7 +5665,9 @@ const tech = { }, { name: "cryodesiccation", - descriptionFunction() { return `+25% sporangium discharge
${b.guns[6].nameString('s')} freeze mobs for 1.5 second` }, + descriptionFunction() { + return `+25% sporangium discharge
${b.guns[6].nameString('s')} freeze mobs for 1.5 second` + }, // description: "+25% sporangium discharge
spores freeze mobs for 1.5 second", isGunTech: true, maxCount: 1, @@ -5576,7 +5687,9 @@ const tech = { }, { name: "flagella", - descriptionFunction() { return `+50% ${b.guns[6].nameString()} acceleration
if they can't find a target ${b.guns[6].nameString('s')} follow you` }, + descriptionFunction() { + return `+50% ${b.guns[6].nameString()} acceleration
if they can't find a target ${b.guns[6].nameString('s')} follow you` + }, // description: "+50% spore acceleration
if they can't find a target spores follow you", isGunTech: true, maxCount: 1, @@ -5596,7 +5709,9 @@ const tech = { }, { name: "junk DNA", - descriptionFunction() { return `+53% ${b.guns[6].nameString()} damage per JUNKtech (${(53*tech.junkCount).toFixed(0)}%)
+50% JUNK to tech pool` }, + descriptionFunction() { + return `+53% ${b.guns[6].nameString()} damage per JUNKtech (${(53*tech.junkCount).toFixed(0)}%)
+50% JUNK to tech pool` + }, isGunTech: true, maxCount: 1, count: 0, @@ -5647,7 +5762,9 @@ const tech = { // }, { name: "mutualism", - descriptionFunction() { return `+150% ${b.guns[6].nameString()} damage
${b.guns[6].nameString('s')} borrow 0.5 health until they die` }, + descriptionFunction() { + return `+200% ${b.guns[6].nameString()} damage
${b.guns[6].nameString('s')} borrow 1 health until they die` + }, // description: `+150% ${b.guns[6].name()} damage
spores borrow 0.5 health until they die`, isGunTech: true, maxCount: 1, @@ -5665,9 +5782,28 @@ const tech = { tech.isMutualism = false } }, + { + name: "necrophage", + description: "if foam, fleas, or worms kill their target
they grow 3 copies", + isGunTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return tech.haveGunCheck("foam") || tech.isFoamBall || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isSporeWorm || tech.isSporeFlea || tech.isFoamMine + }, + requires: "foam, spores, worms, fleas", + effect() { + tech.isSpawnBulletsOnDeath = true + }, + remove() { + tech.isSpawnBulletsOnDeath = false; + } + }, { name: "siphonaptera", - description: "sporangium and shotgun hatch fleas", //
spore tech applies to fleas + description: "sporangium and shotgun hatch fleas
 ", isGunTech: true, maxCount: 1, count: 0, @@ -5687,7 +5823,7 @@ const tech = { }, { name: "nematodes", - description: "shotgun and sporangium hatch worms", //
spore tech applies to worms + description: "shotgun and sporangium hatch worms
 ", isGunTech: true, maxCount: 1, count: 0, @@ -5946,12 +6082,18 @@ const tech = { //spawn drones if (tech.isDroneRadioactive) { for (let i = 0; i < num * 0.25; i++) { - b.droneRadioactive({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5) + b.droneRadioactive({ + x: m.pos.x + 30 * (Math.random() - 0.5), + y: m.pos.y + 30 * (Math.random() - 0.5) + }, 5) bullet[bullet.length - 1].endCycle = Infinity } } else { for (let i = 0; i < num; i++) { - b.drone({ x: m.pos.x + 30 * (Math.random() - 0.5), y: m.pos.y + 30 * (Math.random() - 0.5) }, 5) + b.drone({ + x: m.pos.x + 30 * (Math.random() - 0.5), + y: m.pos.y + 30 * (Math.random() - 0.5) + }, 5) bullet[bullet.length - 1].endCycle = Infinity } } @@ -6040,25 +6182,6 @@ const tech = { tech.isBulletTeleport = false; } }, - { - name: "necrophage", - description: "if foam, fleas, or worms kill their target
they grow 3 copies", - isGunTech: true, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return tech.haveGunCheck("foam") || tech.isFoamBall || tech.isFoamBotUpgrade || tech.isFoamShot || tech.isSporeWorm || tech.isSporeFlea || tech.isFoamMine - }, - requires: "foam, spores, worms, fleas", - effect() { - tech.isSpawnBulletsOnDeath = true - }, - remove() { - tech.isSpawnBulletsOnDeath = false; - } - }, { name: "aerogel", description: "–50% foam duration and foam bubbles float
+180% foam damage", @@ -6082,7 +6205,7 @@ const tech = { }, { name: "surface tension", - description: "+43% foam damage", + description: "+43% foam damage
 ", isGunTech: true, maxCount: 9, count: 0, @@ -6169,7 +6292,9 @@ const tech = { { name: "capacitor bank", // description: "charge effects build up almost instantly
throwing blocks, foam, railgun, pulse, tokamak", - descriptionFunction() { return `charge effects build up almost instantly
throwing, ${tech.haveGunCheck("foam", false) ? "foam" : "foam"}, ${tech.isPlasmaBall ? "plasma ball" : "plasma ball"}, ${tech.isRailGun ? "railgun" : "railgun"}, ${tech.isPulseLaser ? "pulse" : "pulse"}, ${tech.isTokamak ? "tokamak" : "tokamak"}` }, + descriptionFunction() { + return `charge effects build up almost instantly
throwing, ${tech.haveGunCheck("foam", false) ? "foam" : "foam"}, ${tech.isPlasmaBall ? "plasma ball" : "plasma ball"}, ${tech.isRailGun ? "railgun" : "railgun"}, ${tech.isPulseLaser ? "pulse" : "pulse"}, ${tech.isTokamak ? "tokamak" : "tokamak"}` + }, isGunTech: true, maxCount: 1, count: 0, @@ -6188,7 +6313,9 @@ const tech = { }, { name: "Bitter electromagnet", - descriptionFunction() { return `railgun charges +33% slower
+100% harpoon density and damage` }, + descriptionFunction() { + return `railgun charges +33% slower
+100% harpoon density and damage` + }, isGunTech: true, maxCount: 3, count: 0, @@ -6226,8 +6353,8 @@ const tech = { for (i = 0, len = b.guns.length; i < len; i++) { //find which gun if (b.guns[i].name === "harpoon") { b.guns[i].chooseFireMethod() - b.guns[i].ammoPack = this.ammoBonus; - b.guns[i].ammo = b.guns[i].ammo * this.ammoBonus; + b.guns[i].ammoPack = 5; + b.guns[i].ammo = b.guns[i].ammo * 6; simulation.updateGunHUD(); break } @@ -6239,8 +6366,8 @@ const tech = { for (i = 0, len = b.guns.length; i < len; i++) { //find which gun if (b.guns[i].name === "harpoon") { b.guns[i].chooseFireMethod() - b.guns[i].ammoPack = 0.6; - b.guns[i].ammo = Math.ceil(b.guns[i].ammo / this.ammoBonus); + b.guns[i].ammoPack = 1.7; + b.guns[i].ammo = Math.ceil(b.guns[i].ammo / 6); simulation.updateGunHUD(); break } @@ -6296,7 +6423,7 @@ const tech = { }, { name: "alternator", - description: "+80% harpoon energy efficiency", + description: "+90% harpoon energy efficiency
 ", isGunTech: true, maxCount: 1, count: 0, @@ -6355,7 +6482,9 @@ const tech = { }, { name: "smelting", - descriptionFunction() { return `forge ${this.removeAmmo()} ammo into a new harpoon
fire +1 harpoon with each shot` }, + descriptionFunction() { + return `forge ${this.removeAmmo()} ammo into a new harpoon
fire +1 harpoon with each shot` + }, isGunTech: true, maxCount: 9, count: 0, @@ -6529,7 +6658,7 @@ const tech = { }, { name: "relativistic momentum", - description: "lasers push mobs and blocks", + description: "lasers push mobs and blocks
 ", isGunTech: true, maxCount: 1, count: 0, @@ -6614,7 +6743,7 @@ const tech = { }, { name: "specular reflection", - description: "+2 laser beam reflections", + description: "+2 laser beam reflections
 ", isGunTech: true, maxCount: 3, count: 0, @@ -6633,16 +6762,16 @@ const tech = { }, { name: "diffraction grating", - description: `+1 diverging laser gun beam`, + description: `+1 diverging laser gun beam
 `, isGunTech: true, maxCount: 9, count: 0, frequency: 1, frequencyDefault: 1, allowed() { - return tech.haveGunCheck("laser") && !tech.isWideLaser && !tech.isPulseAim && !tech.historyLaser + return tech.haveGunCheck("laser") && !tech.isWideLaser && !tech.historyLaser }, - requires: "laser gun, not neocognitron, diffuse beam, or slow light", + requires: "laser gun, diffuse beam, or slow light", effect() { tech.beamSplitter++ b.guns[11].chooseFireMethod() @@ -6825,25 +6954,6 @@ const tech = { } } }, - { - name: "neocognitron", - description: "pulse automatically aims at a nearby mob", - isGunTech: true, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return tech.haveGunCheck("laser") && tech.isPulseLaser && !tech.beamSplitter - }, - requires: "laser gun, pulse, not diffraction grating", - effect() { - tech.isPulseAim = true; - }, - remove() { - tech.isPulseAim = false; - } - }, //************************************************** //************************************************** field //************************************************** tech @@ -6919,6 +7029,31 @@ const tech = { m.harmonicRadius = 1 } }, + { + name: "triple point", + descriptionFunction() { + return `+1.5 second ice IX freeze effect
spawn ${powerUps.orb.coupling(10)} that each give +0.1 coupling
${ m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per coupling"}` + }, + isFieldTech: true, + maxCount: 3, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" + }, + requires: "standing wave, perfect diamagnetism", + effect() { + tech.iceIXFreezeTime += 90 + powerUps.spawnDelay("coupling", 10) + }, + remove() { + tech.iceIXFreezeTime = 150 + if (this.count) { + m.couplingChange(-this.count) + } + } + }, { name: "bremsstrahlung", description: "deflecting and thrown blocks
do braking damage to mobs", @@ -6957,31 +7092,6 @@ const tech = { tech.isBlockRadiation = false; } }, - { - name: "triple point", - descriptionFunction() { - return `+1.5 second ice IX freeze effect
spawn ${powerUps.orb.coupling(10)} that each give +0.1 coupling
${ m.couplingDescription(1)} ${m.fieldMode === 0 ? "" : "per coupling"}` - }, - isFieldTech: true, - maxCount: 3, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return m.fieldUpgrades[m.fieldMode].name === "standing wave" || m.fieldUpgrades[m.fieldMode].name === "perfect diamagnetism" - }, - requires: "standing wave, perfect diamagnetism", - effect() { - tech.iceIXFreezeTime += 90 - powerUps.spawnDelay("coupling", 10) - }, - remove() { - tech.iceIXFreezeTime = 150 - if (this.count) { - m.couplingChange(-this.count) - } - } - }, { name: "flux pinning", description: "after deflecting a mob
it is stunned for up to 4 seconds", @@ -7084,7 +7194,9 @@ const tech = { }, { name: "dynamic equilibrium", - descriptionFunction() { return `increase damage by your defense and
5% of your last ${tech.isEnergyHealth ? "energy" : "health"} loss   (+${(100*tech.lastHitDamage * m.lastHit * (2 - m.harmReduction())).toFixed(0)}% damage)` }, // = +${10*m.harmReduction()}% + descriptionFunction() { + return `increase damage by your defense and
5% of your last ${tech.isEnergyHealth ? "energy" : "health"} loss   (+${(100*Math.max(5,tech.lastHitDamage) * m.lastHit * (2 - m.harmReduction())).toFixed(0)}% damage)` + }, // = +${10*m.harmReduction()}% // descriptionFunction() { return `increase damage by your last ${tech.isEnergyHealth ? "energy" : "health"} loss
(${(tech.lastHitDamage).toFixed(0)}%)(${(100*m.lastHit).toFixed(0)} ${tech.isEnergyHealth ? "energy" : "health"})(${2 - m.harmReduction()} defense) = ${(100*tech.lastHitDamage * m.lastHit * (2 - m.harmReduction())).toFixed(0)}% damage ` }, // = +${10*m.harmReduction()}% isFieldTech: true, maxCount: 9, @@ -7189,7 +7301,32 @@ const tech = { // }, { name: "bot manufacturing", - description: `use ${powerUps.orb.research(2)} to build
3 random bots`, + description: `use ${powerUps.orb.research(1)} to build
3 random bots`, + isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 1, + frequencyDefault: 1, + isBotTech: true, + isNonRefundable: true, + allowed() { + return powerUps.research.count > 0 && (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") + }, + requires: "molecular assembler, pilot wave", + effect() { + for (let i = 0; i < 1; i++) { + if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) + } + m.energy = 0.01; + b.randomBot() + b.randomBot() + b.randomBot() + }, + remove() {} + }, + { + name: "bot prototypes", + description: `use ${powerUps.orb.research(2)}to build 2 random bots
and upgrade all bots to that type`, isFieldTech: true, maxCount: 1, count: 0, @@ -7205,31 +7342,6 @@ const tech = { for (let i = 0; i < 2; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) } - m.energy = 0.01; - b.randomBot() - b.randomBot() - b.randomBot() - }, - remove() {} - }, - { - name: "bot prototypes", - description: `use ${powerUps.orb.research(3)}to build 2 random bots
and upgrade all bots to that type`, - isFieldTech: true, - maxCount: 1, - count: 0, - frequency: 1, - frequencyDefault: 1, - isBotTech: true, - isNonRefundable: true, - allowed() { - return powerUps.research.count > 2 && (m.fieldUpgrades[m.fieldMode].name === "molecular assembler" || m.fieldUpgrades[m.fieldMode].name === "pilot wave") - }, - requires: "molecular assembler, pilot wave", - effect() { - for (let i = 0; i < 3; i++) { - if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) - } //fill array of available bots const notUpgradedBots = [] const num = 2 @@ -7407,6 +7519,30 @@ const tech = { tech.deflectEnergy = 0; } }, + { + name: "combinatorial optimization", + description: "+35% damage
–35% fire rate", + isFieldTech: true, + maxCount: 1, + count: 0, + frequency: 2, + frequencyDefault: 2, + allowed() { + return m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "molecular assembler" + }, + requires: "cloaking, molecular assembler, plasma torch, pilot wave", + damage: 1.35, + effect() { + tech.damage *= this.damage + tech.aimDamage = 1.35 + b.setFireCD(); + }, + remove() { + if (this.count) tech.damage /= this.damage + tech.aimDamage = 1 + b.setFireCD(); + } + }, { name: "tokamak", description: "throwing a block converts it into energy
and a pulsed fusion explosion", @@ -7664,7 +7800,7 @@ const tech = { }, { name: "time crystals", - description: "+200% passive energy generation", + description: "+200% passive energy generation
 ", isFieldTech: true, maxCount: 1, count: 0, @@ -7708,7 +7844,9 @@ const tech = { }, { name: "quantum eraser", - descriptionFunction() { return `for each mob left alive after you exit a level
kill a mob as they spawn at +${100-1.6*simulation.difficultyMode**2}% duplication
` }, + descriptionFunction() { + return `for each mob left alive after you exit a level
kill a mob as they spawn at +${100-1.6*simulation.difficultyMode**2}% duplication
` + }, // description: `for each mob left alive after you exit a level
kill a mob as they spawn at 100% duplication
`, isFieldTech: true, maxCount: 1, @@ -7732,7 +7870,9 @@ const tech = { }, { name: "symbiosis", - descriptionFunction() { return `after a boss dies spawn a tech, ${powerUps.orb.ammo(1)}, ${powerUps.orb.research(1)}, and ${powerUps.orb.heal(1)}
after a mob dies –0.5 maximum ${tech.isEnergyHealth ? "energy" : "health"}` }, + descriptionFunction() { + return `after a boss dies spawn a tech, ${powerUps.orb.ammo(1)}, ${powerUps.orb.research(1)}, and ${powerUps.orb.heal(1)}
after a mob dies –0.5 maximum ${tech.isEnergyHealth ? "energy" : "health"}` + }, isFieldTech: true, maxCount: 1, count: 0, @@ -7859,30 +7999,6 @@ const tech = { } } }, - { - name: "combinatorial optimization", - description: "+35% damage
–35% fire rate", - isFieldTech: true, - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return m.fieldUpgrades[m.fieldMode].name === "plasma torch" || m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "metamaterial cloaking" || m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "molecular assembler" - }, - requires: "cloaking, molecular assembler, plasma torch, pilot wave", - damage: 1.35, - effect() { - tech.damage *= this.damage - tech.aimDamage = 1.35 - b.setFireCD(); - }, - remove() { - if (this.count) tech.damage /= this.damage - tech.aimDamage = 1 - b.setFireCD(); - } - }, { name: "WIMPs", description: `at the end of each level spawn ${powerUps.orb.research(4)}
and a dangerous particle that slowly chases you`, @@ -7906,28 +8022,28 @@ const tech = { }, { name: "vacuum fluctuation", - description: `use ${powerUps.orb.research(6)}to exploit your field for a
+11% chance to duplicate spawned power ups`, + description: `use ${powerUps.orb.research(5)}to exploit your field for a
+11% chance to duplicate spawned power ups`, isFieldTech: true, maxCount: 1, count: 0, frequency: 3, frequencyDefault: 3, allowed() { - return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "wormhole") && (build.isExperimentSelection || powerUps.research.count > 6) + return (m.fieldUpgrades[m.fieldMode].name === "pilot wave" || m.fieldUpgrades[m.fieldMode].name === "negative mass" || m.fieldUpgrades[m.fieldMode].name === "time dilation" || m.fieldUpgrades[m.fieldMode].name === "wormhole") && (build.isExperimentSelection || powerUps.research.count > 4) }, requires: "wormhole, time dilation, negative mass, pilot wave", effect() { tech.fieldDuplicate = 0.11 powerUps.setDupChance(); //needed after adjusting duplication chance - if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.13); - for (let i = 0; i < 6; i++) { + if (!build.isExperimentSelection && !simulation.isTextLogOpen) simulation.circleFlare(0.11); + for (let i = 0; i < 5; i++) { if (powerUps.research.count > 0) powerUps.research.changeRerolls(-1) } }, remove() { tech.fieldDuplicate = 0 powerUps.setDupChance(); //needed after adjusting duplication chance - if (this.count > 0) powerUps.research.changeRerolls(6) + if (this.count > 0) powerUps.research.changeRerolls(5) } }, // { @@ -7952,7 +8068,7 @@ const tech = { { name: "transdimensional worms", link: `transdimensional worms`, - description: "after blocks fall into a wormhole
spawn a worm", + description: "after a block falls into a wormhole
spawn a worm", isFieldTech: true, maxCount: 1, count: 0, @@ -7997,7 +8113,7 @@ const tech = { }, { name: "cosmic string", - description: "after tunneling through mobs with a wormhole
stun then and do radioactive damage", + description: "after tunneling through mobs with a wormhole
stun them and do radioactive damage", isFieldTech: true, maxCount: 1, count: 0, @@ -8064,7 +8180,7 @@ const tech = { }, { name: "affine connection", - description: "wormholes can tunnel through the map
for +200% energy drain", + description: "wormholes can tunnel through anything
for +200% energy drain", isFieldTech: true, maxCount: 1, count: 0, @@ -8279,6 +8395,23 @@ const tech = { }, remove() {} }, + // { + // name: "pocket dimension", + // description: "rotate tech descriptions into a higher spacial dimension", + // maxCount: 1, + // count: 0, + // frequency: 0, + // isJunk: true, + // isNonRefundable: true, + // allowed() { + // return true + // }, + // requires: "", + // effect() { + // document.getElementById("choose-grid").classList.add("flipX"); + // }, + // remove() {} + // }, { name: "random", link: `random`, @@ -8291,10 +8424,14 @@ const tech = { this.text = `+${(dmg*100).toFixed(0).padStart(2, '0')}% damage` this.damage = 1 + dmg if (document.getElementById(`damage-JUNK-id${this.id}`)) document.getElementById(`damage-JUNK-id${this.id}`).innerHTML = this.text - setTimeout(() => { loop() }, delay); + setTimeout(() => { + loop() + }, delay); } } - setTimeout(() => { loop() }, delay); + setTimeout(() => { + loop() + }, delay); this.id++ return `${this.text}` }, @@ -8302,7 +8439,9 @@ const tech = { count: 0, frequency: 1, isJunk: true, - allowed() { return !build.isExperimentSelection }, + allowed() { + return !build.isExperimentSelection + }, requires: "NOT EXPERIMENT MODE", damage: 0, effect() { @@ -8319,7 +8458,9 @@ const tech = { frequency: 0, isJunk: true, isNonRefundable: true, - allowed() { return !build.isExperimentSelection }, + allowed() { + return !build.isExperimentSelection + }, requires: "NOT EXPERIMENT MODE", effect() { powerUps.spawnDelay("boost", this.spawnCount) @@ -8338,17 +8479,21 @@ const tech = { this.spawnCount = Math.floor(100 * Math.abs(waves)) this.text = `spawn ${this.spawnCount.toLocaleString(undefined, {minimumIntegerDigits:3})} ${powerUps.orb.boost(1)}
that give +${(powerUps.boost.damage*100).toFixed(0)}% damage for ${(powerUps.boost.duration/60).toFixed(0)} seconds` if (document.getElementById(`boost-JUNK-id${this.id}`)) document.getElementById(`boost-JUNK-id${this.id}`).innerHTML = this.text - setTimeout(() => { loop() }, this.delay); + setTimeout(() => { + loop() + }, this.delay); } } - setTimeout(() => { loop() }, this.delay); + setTimeout(() => { + loop() + }, this.delay); this.id++ return `${this.text}` }, }, { name: "placebo", - description: "+777% damage
+777% defense
", + description: "+777% damage
+777% defense", maxCount: 1, count: 0, frequency: 0, @@ -8414,11 +8559,14 @@ const tech = { effect() { setInterval(() => { - fireBlock = function(xPos, yPos) { + fireBlock = function (xPos, yPos) { const index = body.length spawn.bodyRect(xPos, yPos, 20 + 50 * Math.random(), 20 + 50 * Math.random()); const bodyBullet = body[index] - Matter.Body.setVelocity(bodyBullet, { x: 5 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }); + Matter.Body.setVelocity(bodyBullet, { + x: 5 * (Math.random() - 0.5), + y: 10 * (Math.random() - 0.5) + }); bodyBullet.isAboutToBeRemoved = true bodyBullet.collisionFilter.category = cat.body; bodyBullet.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet @@ -8681,7 +8829,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return !tech.isFallingDamage && !tech.isOverHeal && !tech.isEnergyHealth }, + allowed() { + return !tech.isFallingDamage && !tech.isOverHeal && !tech.isEnergyHealth + }, requires: "not quenching, tungsten carbide, mass-energy", effect() { m.baseHealth = 0.01 @@ -8699,7 +8849,9 @@ const tech = { frequency: 0, // isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { m.look = () => { @@ -8728,7 +8880,9 @@ const tech = { frequency: 0, // isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { m.look = () => { @@ -8759,7 +8913,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { const index = Math.min(level.levels.length - 1, level.onLevel) @@ -8774,7 +8930,9 @@ const tech = { count: 0, frequency: 0, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { player.friction = -0.4 @@ -8790,7 +8948,9 @@ const tech = { count: 0, frequency: 0, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { player.restitution = 0.9 @@ -8806,7 +8966,9 @@ const tech = { count: 0, frequency: 0, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { mobs.draw = () => { @@ -8850,7 +9012,9 @@ const tech = { count: 0, frequency: 0, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { mobs.draw = () => { @@ -8910,7 +9074,9 @@ const tech = { frequency: 0, isJunk: true, isNonRefundable: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { // const colors = shuffle(["#f7b", "#0eb", "#467", "#0cf", "hsl(246,100%,77%)", "#26a"]) @@ -8984,7 +9150,9 @@ const tech = { frequency: 0, isJunk: true, isNonRefundable: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect: () => { //setup audio context @@ -9102,7 +9270,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { document.getElementById("health").style.display = "none" @@ -9119,7 +9289,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { const savedfunction = simulation.drawCircle @@ -9149,7 +9321,7 @@ const tech = { }, requires: "", effect() { - m.look = function() { + m.look = function () { //always on mouse look m.angle = (((m.pos.x + m.pos.y) / 100 + Math.PI) % Math.PI * 2) - Math.PI //smoothed mouse look translations @@ -9192,7 +9364,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { setInterval(() => { @@ -9283,7 +9457,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { let options = []; //find what tech I could get @@ -9312,10 +9488,12 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { - String.prototype.shuffle = function() { + String.prototype.shuffle = function () { var a = this.split(""), n = a.length; @@ -9340,7 +9518,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { setInterval(() => { @@ -9358,7 +9538,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { setInterval(() => { @@ -9376,7 +9558,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { setInterval(() => { @@ -9393,7 +9577,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { window.open('https://www.youtube.com/watch?v=lEbHeSdmS-k&list=PL9Z5wjoBiPKEDhwCW2RN-VZoCpmhIojdn', '_blank') @@ -9408,12 +9594,14 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { - (function() { + (function () { var script = document.createElement('script'); - script.onload = function() { + script.onload = function () { var stats = new Stats(); document.body.appendChild(stats.dom); requestAnimationFrame(function loop() { @@ -9438,7 +9626,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { for (let i = 0, len = tech.tech.length; i < len; i++) { @@ -9460,7 +9650,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { for (let i = tech.tech.length - 1; i > 0; i--) { @@ -9498,10 +9690,14 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { - setInterval(() => { if (!simulation.paused) ctx.rotate(0.001 * Math.sin(simulation.cycle * 0.01)) }, 16); + setInterval(() => { + if (!simulation.paused) ctx.rotate(0.001 * Math.sin(simulation.cycle * 0.01)) + }, 16); }, remove() {} }, @@ -9513,7 +9709,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { ctx.shadowColor = '#06f'; @@ -9546,7 +9744,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { setInterval(() => { @@ -9567,7 +9767,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { setInterval(() => { @@ -9585,14 +9787,19 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { for (let i = 0, len = 40; i < len; i++) { setTimeout(() => { m.energy -= 1 / len const index = body.length - where = Vector.add(m.pos, { x: 400 * (Math.random() - 0.5), y: 400 * (Math.random() - 0.5) }) + where = Vector.add(m.pos, { + x: 400 * (Math.random() - 0.5), + y: 400 * (Math.random() - 0.5) + }) spawn.bodyRect(where.x, where.y, Math.floor(15 + 100 * Math.random()), Math.floor(15 + 100 * Math.random())); body[index].collisionFilter.category = cat.body; body[index].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet @@ -9612,7 +9819,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { level.nextLevel(); @@ -9627,7 +9836,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { spawn.setSpawnList(); @@ -9651,7 +9862,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { powerUps.spawn(m.pos.x, m.pos.y, "tech"); @@ -9667,7 +9880,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { setInterval(() => { @@ -9690,7 +9905,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { for (let i = 0; i < 120; i++) { @@ -9713,12 +9930,17 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { setInterval(() => { if (!simulation.paused && document.visibilityState !== "hidden") { - b.grenade(Vector.add(m.pos, { x: 10 * (Math.random() - 0.5), y: 10 * (Math.random() - 0.5) }), -Math.PI / 2) //fire different angles for each grenade + b.grenade(Vector.add(m.pos, { + x: 10 * (Math.random() - 0.5), + y: 10 * (Math.random() - 0.5) + }), -Math.PI / 2) //fire different angles for each grenade const who = bullet[bullet.length - 1] Matter.Body.setVelocity(who, { x: who.velocity.x * 0.1, @@ -9762,10 +9984,12 @@ const tech = { isSkin: true, isNonRefundable: true, isJunk: true, - allowed() { return !m.isShipMode }, + allowed() { + return !m.isShipMode + }, requires: "", effect() { - m.draw = function() { + m.draw = function () { ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; @@ -9806,10 +10030,12 @@ const tech = { isSkin: true, isNonRefundable: true, isJunk: true, - allowed() { return !m.isShipMode }, + allowed() { + return !m.isShipMode + }, requires: "", effect() { - m.draw = function() { + m.draw = function () { ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; @@ -9850,7 +10076,7 @@ const tech = { }, requires: "", effect() { - m.draw = function() { + m.draw = function () { ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; ctx.save(); @@ -9919,7 +10145,7 @@ const tech = { remove() {} }, { - name: "transparency", + name: "n-gone", description: "become invisible to yourself
mobs can still see you", maxCount: 1, count: 0, @@ -9927,7 +10153,9 @@ const tech = { isSkin: true, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { m.draw = () => {} @@ -9988,7 +10216,7 @@ const tech = { }, requires: "", effect() { - m.draw = function() { + m.draw = function () { ctx.fillStyle = m.fillColor; m.walk_cycle += m.flipLegs * m.Vx; ctx.save(); @@ -10052,7 +10280,9 @@ const tech = { isSkin: true, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { m.color = { @@ -10060,7 +10290,7 @@ const tech = { sat: 100, light: 50 } - setInterval(function() { + setInterval(function () { m.color.hue++ m.setFillColors() }, 10); @@ -10074,7 +10304,9 @@ const tech = { count: 0, frequency: 0, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { tech.isMicroTransactions = true @@ -10113,7 +10345,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return m.isShipMode }, + allowed() { + return m.isShipMode + }, requires: "", effect() { tech.damage *= 3 @@ -10199,7 +10433,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { level.difficultyIncrease(simulation.difficultyMode) @@ -10214,7 +10450,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { for (let i = 0; i < mob.length; i++) mobs.statusStun(mob[i], 480) @@ -10229,7 +10467,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { for (let i = 0; i < b.inventory.length; i++) powerUps.spawn(m.pos.x + 60 * (Math.random() - 0.5), m.pos.y + 60 * (Math.random() - 0.5), "gun"); @@ -10293,10 +10533,15 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { - const unit = { x: 1, y: 0 } + const unit = { + x: 1, + y: 0 + } for (let i = 0; i < 30; i++) { const where = Vector.add(m.pos, Vector.mult(Vector.rotate(unit, Math.random() * 2 * Math.PI), 2000 + 1200 * Math.random())) spawn.sucker(where.x, where.y, 140) @@ -10313,7 +10558,9 @@ const tech = { count: 0, frequency: 0, isJunk: true, - allowed() { return !build.isExperimentSelection }, + allowed() { + return !build.isExperimentSelection + }, requires: "NOT EXPERIMENT MODE", effect() {}, remove() {}, @@ -10348,10 +10595,14 @@ const tech = { this.researchSpawned++ powerUps.spawn(m.pos.x - 50 + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research"); } - setTimeout(() => { loop() }, 300); + setTimeout(() => { + loop() + }, 300 + 5 * this.state.length); } } - setTimeout(() => { loop() }, 300); + setTimeout(() => { + loop() + }, 300); this.id++ return `${this.outputText()}` }, @@ -10379,7 +10630,9 @@ const tech = { count: 0, frequency: 0, isJunk: true, - allowed() { return !build.isExperimentSelection }, + allowed() { + return !build.isExperimentSelection + }, requires: "NOT EXPERIMENT MODE", effect() {}, remove() {}, @@ -10413,10 +10666,14 @@ const tech = { this.researchSpawned++ powerUps.spawn(m.pos.x - 50 + 100 * (Math.random() - 0.5), m.pos.y + 100 * (Math.random() - 0.5), "research"); } - setTimeout(() => { loop() }, 300); + setTimeout(() => { + loop() + }, 300 + 5 * this.state.length); } } - setTimeout(() => { loop() }, 300); + setTimeout(() => { + loop() + }, 300); this.id++ return `${this.outputText()}` }, @@ -10446,7 +10703,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { const urls = ["https://scratch.mit.edu/projects/14005697/fullscreen/", "https://scratch.mit.edu/projects/22573757/fullscreen/", "https://scratch.mit.edu/projects/41429974/fullscreen/", "https://scratch.mit.edu/projects/43690666/fullscreen/", "https://codepen.io/lilgreenland/full/ozXNWZ", "https://codepen.io/lilgreenland/full/wzARJY", "classic/7-1-2017/", "classic/4-15-2018/", "classic/7-11-2019/", "classic/9-8-2019/", "classic/7-15-2020/", "classic/6-1-2021/"] @@ -10456,11 +10715,21 @@ const tech = { setTimeout(() => { tab.close(); powerUps.spawn(m.pos.x, m.pos.y, "gun"); - setTimeout(() => { powerUps.spawn(m.pos.x, m.pos.y - 50, "ammo") }, 250); - setTimeout(() => { powerUps.spawn(m.pos.x + 50, m.pos.y, "field"); }, 500); - setTimeout(() => { powerUps.spawn(m.pos.x + 50, m.pos.y - 50, "heal"); }, 750); - setTimeout(() => { powerUps.spawn(m.pos.x - 50, m.pos.y, "tech"); }, 1000); - setTimeout(() => { powerUps.spawn(m.pos.x - 50, m.pos.y - 50, "research"); }, 1250); + setTimeout(() => { + powerUps.spawn(m.pos.x, m.pos.y - 50, "ammo") + }, 250); + setTimeout(() => { + powerUps.spawn(m.pos.x + 50, m.pos.y, "field"); + }, 500); + setTimeout(() => { + powerUps.spawn(m.pos.x + 50, m.pos.y - 50, "heal"); + }, 750); + setTimeout(() => { + powerUps.spawn(m.pos.x - 50, m.pos.y, "tech"); + }, 1000); + setTimeout(() => { + powerUps.spawn(m.pos.x - 50, m.pos.y - 50, "research"); + }, 1250); }, 1000 * 5 * 60); }, remove() {} @@ -10473,7 +10742,9 @@ const tech = { frequency: 0, isNonRefundable: true, isJunk: true, - allowed() { return true }, + allowed() { + return true + }, requires: "", effect() { window.open('../../planetesimals/index.html', '_blank') @@ -10484,7 +10755,7 @@ const tech = { const bc = new BroadcastChannel('planetesimals'); bc.activated = false - bc.onmessage = function(ev) { + bc.onmessage = function (ev) { if (ev.data === 'tech') powerUps.directSpawn(m.pos.x, m.pos.y, "tech"); if (ev.data === 'death') { m.death() @@ -10519,7 +10790,9 @@ const tech = { }, { name: "NFT", - descriptionFunction() { return `buy your current game seed: ${Math.initialSeed}
no one is allowed to use your seeds
if they use them they are gonna get in trouble

your seeds: ${localSettings.personalSeeds.join(", ")}` }, + descriptionFunction() { + return `buy your current game seed: ${Math.initialSeed}
no one is allowed to use your seeds
if they use them they are gonna get in trouble

your seeds: ${localSettings.personalSeeds.join(", ")}` + }, maxCount: 1, count: 0, frequency: 0, @@ -10604,14 +10877,16 @@ const tech = { //************************************************** { name: `undefined`, - description: `this`, + description: `this
 `, maxCount: 1, count: 0, frequency: 2, frequencyDefault: 2, isLore: true, // isExperimentHide: true, - allowed() { return !build.isExperimentSelection }, + allowed() { + return !build.isExperimentSelection + }, requires: "NOT EXPERIMENT MODE", effect() { if (localSettings.loreCount > lore.conversation.length - 1) { //reward for people done with lore chapters (or on the final chapter) @@ -10644,7 +10919,7 @@ const tech = { if (lore.techCount === lore.techGoal) { // tech.removeLoreTechFromPool(); this.frequency = 0; - this.description = `null is open at level.final()` + this.description = `null is open at level.final()
 ` } else { this.frequency += lore.techGoal * 2 // for (let i = 0; i < tech.tech.length; i++) { //set name for all unchosen copies of this tech @@ -10658,7 +10933,7 @@ const tech = { remove() { lore.techCount = 0; this.maxCount = lore.techGoal; - this.description = `this` + this.description = `this
 ` } } ], @@ -10784,7 +11059,6 @@ const tech = { isExtraMaxEnergy: null, isAmmoForGun: null, isRapidPulse: null, - isPulseAim: null, isSporeFreeze: null, isShotgunRecoil: null, isHealLowHealth: null, diff --git a/style.css b/style.css index 43248ba..bf5c78f 100644 --- a/style.css +++ b/style.css @@ -1,5 +1,5 @@ :root { - --build-bg-color: #c4ccd8; + --build-bg-color: #aeb6c2; } body { @@ -7,7 +7,7 @@ body { margin: 0; overflow: hidden; /* background-color: #eee; */ - user-select: none; + cursor: auto; } @@ -16,6 +16,7 @@ canvas { top: 0; left: 0; z-index: 0; + user-select: none; } select { @@ -123,7 +124,7 @@ summary { .SVG-button { border: 1.5px #333 solid; - border-radius: 9px; + border-radius: 8px; background-color: #fff; } @@ -182,45 +183,63 @@ summary { transition: opacity 0.25s linear; } - +#flex-center{ + display: flex; + align-items: center; + justify-content: center; + height: 100%; +} #choose-grid { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - padding: 10px; - grid-gap: 10px; + + padding: 10px 1px; + /* gap: 1px; */ margin: 0px; - border-radius: 8px; + border: 0px; z-index: 12; - background-color: #444; - grid-template-columns: repeat(auto-fit, 400px); - /* grid-template-columns: repeat(auto-fit, minmax(360px, 450px)); */ - /* grid-auto-rows: minmax(auto, auto); */ - /* grid-auto-rows: 1; */ + max-height: 99vh; font-size: 1.3em; - /* box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.25); */ + display: grid; + grid-template-columns: repeat(3, 384px); + align-items: stretch; + /* align-content: start; */ + /* grid-auto-rows: minmax(auto, 140px); */ visibility: hidden; opacity: 0; transition: opacity 0.25s linear; - align-content: start; - max-height: 100vh; overflow: auto; - + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} +#choose-grid::-webkit-scrollbar { + display: none; } .choose-grid-module { - padding: 10px; + padding: 5px; line-height: 170%; - border-radius: 6px; - background-color: #fff; - font-size: 0.8em; + /* border-radius: 8px; */ + background-color: #fafcfd; + font-size: 0.75em; + /* border: 1px #444 solid; */ + /* box-shadow: 0px 0px 10px 5px rgba(0, 0, 0, 0.25); */ } .choose-grid-module:hover { background-color: #efeff5; } +.choose-grid-module:hover .card-text { + background-color: #efeff5; +} + +.research-select { + float: right; + margin-right:10px; +} .cancel { /* text-align: right; */ @@ -235,88 +254,109 @@ summary { } .pause-grid { - padding: 1px; + padding: 2px; margin: 0px; display: none; - grid-template-columns: 345px; + grid-template-columns: 384px; /* grid-template-columns: repeat(auto-fit, minmax(310px, 1fr)); */ grid-auto-rows: minmax(auto, auto); - grid-gap: 0px; align-content: start; /* align-content: space-between; */ - + /* gap: 10px; */ z-index: 2; font-size: 1.3em; } #pause-grid-right { - position: relative; + position: absolute; + top:-2px; + right:-4px; overflow: auto; max-height: 100vh; + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + padding: 1px; +} + +#pause-grid-right::-webkit-scrollbar { + display: none; } #pause-grid-left { - position: relative; + position: absolute; + top:-2px; + left:-4px; overflow: auto; max-height: 100vh; + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} + +#pause-grid-left::-webkit-scrollbar { + display: none; } .pause-grid-module { - margin: -1px; + /* margin: -1px; padding: 10px; line-height: 170%; - /* border-radius: 6px; */ border: 1px #333 solid; + border-radius: 8px; background-color: #fff; - font-size: 0.65em; + font-size: 0.65em; */ + padding: 5px; + line-height: 170%; + /* border-radius: 8px; */ + background-color: #fafcfd; + font-size: 0.75em; + /* border: 2px #444 solid; */ +} + +.pause-eject .card-text { + animation: techColorCycle 1s linear infinite alternate; } #experiment-grid { + display: flex; + justify-content: center; /* align-content: space-between; */ - padding: 1px; + /* padding-top: 10px; */ /* padding: 16px; */ + padding: 10px 1px; margin: 0px; border: 0px; background-color: var(--build-bg-color); + /* background-color: #444; */ display: none; - grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); + /* grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); */ + grid-template-columns: repeat(auto-fit, 384px); grid-auto-flow: row; grid-auto-rows: minmax(auto, auto); - grid-gap: 0px; - /* grid-gap: 16px; */ + /* gap: 1px; */ position: relative; bottom: 0px; z-index: 10; font-size: 1.3em; + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} +#experiment-grid::-webkit-scrollbar { + display: none; } .experiment-grid-module { - margin: -0.5px; - padding: 10px; + padding: 5px; line-height: 170%; - /* border-radius: 6px; */ - border: 1px #17263b solid; + /* border-radius: 8px; */ background-color: #fafcfd; - - line-height: 170%; - font-size: 0.65em; + font-size: 0.75em; + /* border: 1px #444 solid; */ + /* margin: -0.5px; */ } -/* .experiment-grid-module-field { - background-color: #eff; - opacity: 1; - transition: opacity 0.5s ease; -} - -.experiment-grid-module-gun { - background-color: #eef; - opacity: 1; - transition: opacity 0.5s ease; -} */ - .experiment-grid-hide { display: none; } @@ -327,11 +367,39 @@ summary { font-weight: 600; } -.experiment-grid-module:hover { +.experiment-grid-module:hover:not(.build-tech-selected, .build-field-selected, .build-gun-selected) { background-color: #efeff5; } -.build-field-selected { +.card-background { + height:340px; + width:288; + background-repeat: no-repeat; + display: flex; + justify-content:flex-end; + flex-direction: column; + padding:0px; +} + +.card-text { + background-color: rgba(255,255,255,1); + /* border-radius: 8px; */ + padding: 8px; + /* border-top: 1px solid var(--build-bg-color); */ + border: 1px solid #444; + margin-top: -1px; + margin-right: -1px; +} + +/* .no-image-cards{ + border: 1px solid #444; +} */ +/* .card-text:hover { + background-color: #efeff5; +} */ + + +/* .build-field-selected { background-color: hsl(193, 100%, 75%); } @@ -347,17 +415,39 @@ summary { background-color: hsl(218, 100%, 76%); } -.build-tech-selected { +.build-tech-selected .card-text{ background-color: hsl(253, 100%, 84%); } -.build-tech-selected:hover { +.build-tech-selected:hover .card-text{ + background-color: hsl(253, 100%, 81%); +} */ + +/* .experiment-grid-module:hover .card-text:not(.build-tech-selected, .build-field-selected, .build-gun-selected) { + background-color: #efeff5; +} */ + +.experiment-grid-module:hover .card-text { + background-color: #efeff5; +} +.build-tech-selected .card-text{ + background-color: hsl(253, 100%, 84%); +} +.build-tech-selected.experiment-grid-module:hover .card-text { background-color: hsl(253, 100%, 81%); } - -/* .experiment-grid-show { - display: inline; -} */ +.build-gun-selected .card-text{ + background-color: hsl(218, 100%, 81%); +} +.build-gun-selected.experiment-grid-module:hover .card-text { + background-color: hsl(218, 100%, 76%); +} +.build-field-selected .card-text{ + background-color: hsl(193, 100%, 75%); +} +.build-field-selected.experiment-grid-module:hover .card-text { + background-color: hsl(193, 100%, 68%); +} .experiment-grid-disabled { /* opacity: 0.5; */ @@ -736,6 +826,15 @@ summary { padding: 0.5px; font-weight: 100; } +.color-cancel { + background-color: #fafcfd; + border: 2px #444 solid; + padding: 4px; + border-radius: 4px; + font-weight: 800; + line-height: 170%; + font-size: 1em; +} .color-j { letter-spacing: 1px; @@ -920,10 +1019,6 @@ summary { background-color: #f7b; } -.research-select { - float: right; -} - .alt { animation: alt 8s linear infinite alternate; font-weight: 400; @@ -1025,6 +1120,31 @@ summary { animation: textColor 3s linear infinite; } +.entanglement { + /* color: #456; */ + font-size: 1.1em; + font-weight: 100; + text-align: center; + letter-spacing: 10px; + border: none; + /* border-radius: 50%; */ + background-color: #efeff5; +} +.flipX { + animation: 14s anim-flipX linear infinite; +} +@keyframes anim-flipX { + 0% { + transform: rotateX(0.5turn); + } + 50% { + transform: rotateX(1turn); + } + 100% { + transform: rotateX(0.5turn); + } + } + @keyframes fieldColorCycle { 0% { background-color: rgb(255, 255, 255) diff --git a/todo.txt b/todo.txt index 652a4bf..3cdf7dc 100644 --- a/todo.txt +++ b/todo.txt @@ -1,42 +1,147 @@ ******************************************************** NEXT PATCH ************************************************** -harpoon - default fire rate is 10% higher - default harpoon range 15% higher -railgun - tech: Bitter electromagnet - 33% slower charge time for railgun, 100% more density and damage - area effect damage is increased 20%, scales with bitter electromagnet and total charge - charging longer increases harpoon velocity/damage by up to 30% - contributions to charge time are more uniform between: - crouching, fire rate, Bitter electromagnet, and capacitor bank - auto aims no longer disabled on crouch -emergence 2->1 extra choice, and +8% damage, and no added JUNK anymore -cache 16->15x ammo -many-worlds 1->0 research to enter an alternate reality on each new level +added images to tech, field, gun cards (enable this in settings) + in progress - not all images are generated yet + images are generated by me using midJourney plus significant post processing -finalBoss - health decays a bit faster - spawns 6 mobs at each health threshold - spawns from the different modes are reduced - boss laser damage is 25% reduced - hoppers spawn from the slime tunnel +random research power ups are 20% more common per level +global difficulty balance: player takes a bit less damage +mutualism: 0.5->1 borrowed health for 250->300% more spore damage -JUNKtech: random - gives random +damage +harpoon can still fire when out of energy, but slower +harpoon fire cooldown no longer triggers when the harpoon returns + it's just a flat 2/3 of a second after you Fire + improved fire rate now allows you to fire many harpoons at once until you run out of energy +default harpoon rope is a bit longer -bug fixes +several bug fixes and undocumented changes I forgot to list *********************************************************** TODO ***************************************************** -tech: zombie - sporangium infect mobs, making them fight for you +set media rules for smaller screens + smaller card size + +tech super balls - super ball can damage you + +add to todo: make it so each phase of the final boss works like a new level (call new level code on each new phase) + +bug reactor boss + harpoon foam production seems to make too much foam + +set mob health bar colors based on status effects? + make mob damage immunity a mob status effect? + +physics notes: add link to double slit content + https://www.youtube.com/watch?v=v_uBaBuarEM + +seekers after taking damage if seekers are below 1/2 life they teleport to a random point on the player history and sneak attack again + make sure they don't teleport on top of the player + +card images + process: discord midjourney prompts -> "pixelmator pro" -> adjust color, repair, scale to 384x256, export PNG -> webP? -> place in /img folder + make n-gon a progressive web app to manage image downloads, cache + wave function collapse opens the pause menu after it triggers alternate reality + this is actually good, maybe reuse this code to get pause menu to open at any time + if pause is pressed while selecting power ups, display pause menu on top of selection menu + ***styles*** + try --- Pastel drawing, Psychedelic art, Arabesque (cool patterns), knolling (everything spread out and placed on a flat mat) + try taking screen shots of fields graphics and feeding them into midJourney V4 + technology stuff --- Dan Matutina (cute complex technology), + Katsuhiro Otomo (intricate space technology), Tsutomu Nihei (black and white detailed future tech) + infographics of all know multiverses. 1980s Japanese graphic design, dimensional astrolabe, + Japanese poster graphics, Ralph McQuarrie (looks like star wars), Simon Stålenhag (retro-futuristic), Yoshiyuki Tomino (detailed anime future technology) + isometric: low-poly, box cutout, made in blender, Materials: matte clay + subtractive sculpture + kinetic sculpture + quantum stuff -- Hypertorus, Glowing Opal Pearlescent, Physics, Hydro-Dipping Hydrodipped, Vija Celmins, Matt Molloy (photo of golden waves in the sky) + ***major themes missing*** + ***maybe redo*** + dynamical systems + harpoon gun + nail-bot + homeostasis + ***past style themes*** + field emitter - isometric, clean white robot spherical gun turret on bird legs, blender 3d, style of artstation and behance, Disney Pixar, cute + standing wave - concentric transparent blue geometric circles science + perfect diamagnetism - physics magnetic field chalk diagram + time dilation - graphic of a hyperbolic equation Luminogram + negative mass - Blacklight painting by Moebius + plasma torch - by Dan Mumford + metamaterial cloaking - Scientific photography by Miki Asai + molecular assembler - by Laurie Greasley 16-bit Isometric + wormhole - by Tim White + + nail gun - Screenprint + shotgun - blueprint by Dan McPharlin + grenades, missiles, explosions - by Victo Ngai + spores - by Ernst Haeckel + drones - tilt-shift photography + super balls - By Akari Toriyama + wave - sound wave oscilloscope by Paul Catherall, concentric circles by Paul Catherall + foam - black blobs Ink doodle + harpoon - by Eiichiro Oda + mine - by Dan McPharlin + laser - complex optical scientific equipment + + guns, ammo - isometric clean pixel art image cutaway of , style of tekkonkinkreet + defensive - Paper cutout + bots - hovering drone by Laurie Greasley 16-bit Isometric + generic energy tech - by Laurie Greasley + duplication, cancel - by Kazumasa Nagai + anti-shear topology, fracture analysis, shear stress - Chemigram + ON/OFF - ASCII art + block throwing - Bauhaus style + tech that adds JUNK - by Choi Jeong-hwa + ice IX - microscope images of ice crystals + tech that spawns health - glowing green balls by Enki Bilal + invulnerable - by Nick Veasey (photos that look like x-rays) + alternate reality - Fractal art + tech choice - mandala tile Mosaic + tech that spawns heal power ups - green Quilling + time, CPT, pause - by Lee Bontecou + boost, coupling power ups tech - cyan electron orbiting a black nucleus electric field as bas-relief //(by Kazumasa Nagai) + radioactive - volumetric atomic nucleus diagram by Paul Catherall + + + +tech: railgun area damage effect, but for all harpoon mode + +laser momentum pushed back on player? + might just be annoying + +JUNK - overwrite mob draw function so mobs only draw if they can connect a ray from player to mob + gonna cause lag? + +tech: p-zombie - sporangium infect mobs, making them fight for you + zombies should attack player if there are no mob targets + name: cordyceps, zombie, p-zombie? infected mobs get a status debuff. when they die they return as zombie mob type zombie mobs run code similar to drones they inherit color, sides, radius from host +mob status effect - vulnerability + mobs take 4x damage for __ time + afterwards mobs go back to normal damage taken + graphical effect while they take extra damage + needs to come from a "rare"ish effect + merge with the decloaking damage effect + decloaking gives all mobs (nearby??) a 3x damage taken status? + this can be merged with the stun crit damage tech + also the increased damage every hit tech? + bad idea because the graphical effect will be too annoying + tech: sporangium that grow little trees the trees have an area of effect damage for about 6-10 seconds maybe something similar to radioactive drones, but maybe a few smaller shapes +spores, worms, fleas - can target player + when to target player + probably have to not go after player for at least a few seconds + only go after player if there are no mobs + go after what ever is closest target + go after a random target + if distance to player < 60 damage player + new bot type that makes phonon waves name: phono-bot? each bot has to generate it themselves, can't run code in gun.do @@ -86,12 +191,8 @@ finalBoss mob status effect - emit - mobs fire lasers for a few seconds tech: phosphorescence - mobs emit after being hit with laser beams -run canvas direct pixel editing while game is paused - (I tried it an it really hits performance hard) - just update once every second? - if it uses too much processing have a setting to toggle it off - this might help get players to spend more time relaxing on the power up selection - increase the click delay? +Tech: "Solid rocket motor": Missiles would start at 300% speed and 200% missile damage upon explosion, but the speed and damage would decrease to 40% speed and damage as time goes on +tech: every time shotgun fires it's a different shotgun mode: nails, ice, needles, worms, fleas, rivets, ... but you get more ammo try again - line of sight https://ncase.me/sight-and-light/ @@ -1111,7 +1212,7 @@ possible names for tech Unitarity - https://en.wikipedia.org/wiki/Unitarity_(physics) - all probabilities add up to 1, calculations work the same forward and backwards in time this is violated by expansion of the universe https://en.wikipedia.org/wiki/Cosmic_censorship_hypothesis - black holes can't leak - + Alcubierre warp drive (FTL with negative mass)