Compare commits

...

10 Commits

Author SHA1 Message Date
landgreen
7142943b71 pilot wave tech
pilot wave tech: Bells theorem - field is always on for no energy cost
pilot wave tech: principle of locality - 0.9x damage taken while inside pilot wave field, -2 choices

hidden-variable theory 1.2->1.3 damage per field tech
WIMPS spawn 4->5 research per level

bug fixes
  fixed exploit with final tech power up on subway level
2025-02-09 17:47:36 -08:00
landgreen
b2426cd7be surfing
pilot wave rework
  it's easier to surf on blocks controlled by pilot wave
    pilot wave secret combo spawns blocks that are easier to surf on: long and thin
  pilot wave location resets to player when off
  pilot wave hitting map no longer shrinks, it just will not enter map
  field speed slows down with total block mass in field
  energy drain
    1x energy regen disabled when field is active
    2x passive regen drained when out of line of sight of player
    energy drain that scales with size and acceleration of blocks in field
  added graphical flicker when field is out of line of sight
  a few more bosses now interact with blocks and can take damage
  prevented field from disabling when mouse goes off screen
    I don't expect any bugs from this, but maybe...

ghoster mobs have 2x->1.5x extra density and health
exploder mobs no longer have a chance for a shield
  2.5x explode damage, 1.3x health
  added a red aura to show they explode on contact
spawnerBossCulture changed visual look to be a flashing transparent red outline
  2x explode damage
laser mobs no longer explode, 1.5x density/mass
2025-02-02 21:16:10 -08:00
landgreen
77e484c3d2 another combo
tech: collimator - add 1 laser beam and align your diverging beams to be parallel
  requires diffraction grating

added secret pilot wave combo to make blocks
rewrote combo test algorithm to be more forgiving with pattern matching
  also extended combos test to arrow keys, not just WASD

cache 17->15x ammo
metamaterial cloaking 0.3->0.4x damage reduction while cloaked
boson composite drains more energy when passing through mobs
  scales with difficulty
subway level has 6->4 (5 on hard difficulty) stations
subway gives 1/3->1/5 interest per station

bug fixes
  Higgs skin removal fixed
  diaphragm skin removal fixed
2025-01-26 09:09:15 -08:00
landgreen
c9a5ab91b8 combos
mantisBoss flashes for a second before it drops invulnerability
removed parasitism - it's too similar to invulnerability tech
invariant no longer drains energy while wormhole time is paused
  added 1 research cost
added secret combo to change molecular assembler mode

bug fixes
  issue with constraint: "mob death heals mobs"
    mob health was becoming NaN, this was infecting other values like player energy
  entering a seed in settings wasn't giving the same results as a randomly generated seeds
    also removed some random code that was using seeded shuffle, but didn't need to
      converted it to non seeded random shuffle with .sort(() => Math.random() - 0.5);
2025-01-18 17:00:10 -08:00
landgreen
1040d1ff7e demineralization
tech: demineralization - after mobs die gain 0.85x damage taken, effect stacks, but fades 10% every second
tech: remineralization - after mobs die gain 1.08x damage, effect stacks, but fades 10% every second
tech: equivalence principle - negative mass field doesn't cost energy
new JUNK tech: aerodynamics

interferometer
  slower elevator and lasers
  wider side ledges
  large laser blocking blocks
flocculation
  fewer mobs
  it's easier to get out of the slime
pavilion
  move vanish elements
  easier traversal
  secret tunnel
  removed debris, but added power ups and blocks
corridor
  limited to bosses that don't interact with the movers poorly
gravitron, substructure, corridor, interferometer
  added more heal and ammo power ups to match other levels
because some newer levels are zoomed out more
  laser max range is 3000->5000
  nails last 1/3 of a second longer
bosses spawn an extra ammo power up
  and 2 extra ammo on the hardest 2 difficulties
slasher mob's laserSwords will now damage a cloaked player
constraint announcement text looks more like computer code style to match game theme

foam recoil is back: 1->0.7x horizontal force and 2->4.3x vertical up force
  this makes it less annoying to horizontally and easier to kinda fly/float
negative mass field damage reduction 0.4->0.5x
holographic principle no longer slows player movement
  added 2 research cost
fermion gives 6->5 seconds of invulnerability after mobs die
stability 0.2->0.1x damage taken at max health
non-Newtonian armor 0.3->0.4x damage taken after collisions
Zeno's paradox 0.15->0.2x damage taken
annihilation energy cost 10->8 to destroy mobs after collisions
radiative equilibrium damage is 3->4x for 8->4 seconds
aerostat can be taken 1->3 times
dynamic equilibrium damage increased by 6->8x damage per last damage taken
aerostat no longer has 0.9x damage for being on the ground
launch system 1.2->1.3x ammo for missiles
research says that repeatedly entering alternate realities builds up some positive effects
  Hilbert space 4x->3x damage
  Ψ(t) collapse 6->4 research on boss death
transdimensional worms: 50% chance for a second worm per block in wormhole
wormhole 7->8 energy regen per second
hidden-variable theory 1.15->1.2 damage after choosing a field tech
ghoster mobs are less likely to get knocked far away from the player for long periods of time

bug fixes
  dynamic equilibrium was set to 100 times higher frequency then normal
  when constraints hide health bar's it's now hidden in the pause menu
  mobs aiming at cloaked player
    snakeBoss more intelligently chases player for a few seconds
    pulsarBoss aims at player's history 3 seconds in past
    pulsar will not stop firing
      but it will still not fire at cloaked player
2025-01-04 21:33:32 -08:00
landgreen
2daeae1ff4 corridor
new level corridor
  new level element fizzler - it removes blocks
interferometer has wider platforms, a few helpful blocks, and fewer mobs
level constraints are announced in console

foam gun no longer pushes the player back when firing
wave gun buffs
  1.2x base damage
  1.1x base ammo
  0.1->0.13x speed in map
  0.25->0.30x speed in blocks
  tech: phase velocity 1.4->1.5x damage
pigeonhole principle gives 1.3->1.4 damage per gun
  you can no longer switch guns, your gun cycles each level
quenching 0.4->0.5x overheal converts into max health
tungsten carbide no longer has reduced coyote cycles
control theory 1.5->2x damage at max health
stability 0.3->0.2 damage taken at max health
overcharge +88->100 max energy, 4->5% JUNK
zoospore vector 10->13% chance for spores on mob death
replication 15->10% JUNK
interest 6->5% of your power ups spawn each level

updated "about" details menu
  moved classic n-gon to here from settings
  added links to community content in "about"
    Are there more links I should add?
  added an n-gon SVG head image

bugs
  fixed outline on splash screen doesn't sync right on safari browser
  fixed possible lock out on training levels: "hold", "throw", "throwAt"
    from losing block behind a door
  shortcut sort buttons in experiment mode properly order tech without clicking sort
  fixed/increased the horizontal velocity contribution for some guns
    this makes bullets shot on moving platforms more realistic
    nail gun, super balls, foam, harpoon
2024-12-24 11:22:57 -08:00
landgreen
1966173f88 moving files to different computer
reworked focuser mobs to fire blue energy draining laser instead of charging player
2024-11-29 18:47:49 -08:00
landgreen
97c5509278 tiny bug fix 2024-11-25 21:39:35 -08:00
landgreen
f1a6713f68 switchWorlds
reworked m.switchWorlds() (used in many-worlds and similar effects)
  no longer has extra bot build up
  effects that carry over into next world:
    your total tech count
    effects of non-removeable tech, like determinism
mass production research ramps up by 5->4 each time
bot fabrications cost ramp is increased to (+1 per 4)-->(+1 per 3)
lowered minimum threshold for making small heals from over healing to 13->20 health
snakeBoss invulnerable phase is 5->4 seconds long

time dilation disables level based lasers
adjusted laser sensor paths on substructure level

move splash screen buttons to bottom right
added a start button
details menus in splash screen now have individual widths instead of sharing with each other

bugs
  non-renewables change color for ammo power ups on current level
2024-11-25 20:05:56 -08:00
landgreen
1fde74d65a substructure
new level substructure
  featured element - motion triggered lasers

futures exchange 5->6% duplication per cancel
plasma torch coupling 0.015->0.025x damage per coupling
Gibbs free energy  1.005->1.006x damage per missing energy
compound lens arc adds 25->30 degrees
instability 2->2.5x damage when damage taken is 1x
constraint: after 30->40 seconds spawn WIMPs
constraint: 0.1->0.3x damage after getting power ups
renamed holographic principle -> charmed baryons

updates to community map: downpour
updated lasers in labs and testChamber to the new more realistic laser

bugs
  returning to the old console.log system from last patch
    I rather read bugs in the browser console not the n-gon console
  bots properly follow player when level flips vertically
  community map: arena's sword is properly removed at end of level
  rewrote shaped charge to be better at protecting you from all explosions
  pause correctly lists both mobs types for the level
  for quasiparticles "boost" replaces ammo in more edge cases
  bug with removing surfactant setting b.activeGun false and crashing game with checking active gun
    not sure if this is fixed or not?
2024-11-12 20:16:17 -08:00
22 changed files with 5600 additions and 4005 deletions

BIN
img/Bells theorem.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
img/collimator.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
img/demineralization.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
img/remineralization.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -39,20 +39,22 @@
<div style="position: absolute; top:0;right:0;">
<div id="pause-grid-right" class="pause-grid"></div>
</div>
<svg class="SVG-button" id="experiment-button" width="170" height="45" style="border: 2px #333 solid;">
<g stroke='none' fill='#333' stroke-width="2" font-size="30px" font-family="Arial, sans-serif">
<text x="10" y="33">experiment</text>
</g>
<svg class="SVG-button SVG-button-splash" id="start-button" width="82" height="45" stroke='none' fill='#333' font-size="30px" font-family="Arial, sans-serif" onclick="simulation.startGame()">
<text x="10" y="32">start</text>
</svg>
<svg class="SVG-button" id="training-button" width="120" height="45" style="border: 2px #333 solid;" stroke='none' fill='#333' font-size="30px" font-family="Arial, sans-serif" onclick="simulation.startGame(false, true)">
<text x="10" y="33">training</text>
<svg class="SVG-button SVG-button-splash" id="training-button" width="120" height="45" stroke='none' fill='#333' font-size="30px" font-family="Arial, sans-serif" onclick="simulation.startGame(false, true)">
<text x="10" y="32">training</text>
</svg>
<svg class="SVG-button SVG-button-splash" id="experiment-button" width="170" height="45">
<text stroke='none' fill='#333' stroke-width="2" font-size="30px" font-family="Arial, sans-serif" x="10" y="32">experiment</text>
</svg>
<div id='info'>
<div id="settings" >
<details id = 'settings-details'>
<div>
<details id='settings-details'>
<summary>settings</summary>
<div style="line-height: 150%;" class="details-div">
<div class="details-div" style="max-width: 24rem; line-height: 150%;">
<input onclick="build.showImages('settings')" type="checkbox" id="hide-images" name="hide-images" style="width:17px; height:17px;">
<label for="hide-images" title="hide images for fields, guns, and tech">hide images</label>
<br>
@@ -75,25 +77,6 @@
<label for="banned" title="type banned levels with a space between them. Example: run temple biohazard">banned levels:</label>
<input id="banned" name="banned" placeholder="list levels by name" autocomplete="off" spellcheck="false" style="width: 182px;" />
<br>
<label for="classic-select" title="play older versions of n-gon">classic n-gon:</label>
<select name="classic-select" id="classic-select" onChange="window.location.href=this.value">
<option value="https://scratch.mit.edu/projects/14005697/fullscreen/">mech: 2014</option>
<option value="https://scratch.mit.edu/projects/22573757/fullscreen/">spacetime: 2015</option>
<option value="https://scratch.mit.edu/projects/41429974/fullscreen/">ballistics: 2015</option>
<option value="https://scratch.mit.edu/projects/43690666/fullscreen/">portal: 2016</option>
<option value="https://codepen.io/lilgreenland/full/ozXNWZ">side scroller: 2016</option>
<option value="https://codepen.io/lilgreenland/full/wzARJY">side scroller: 2016</option>
<option value="classic/7-1-2017/">LandGame: 2017</option>
<option value="classic/4-15-2018/">n-gon: 2018</option>
<option value="classic/7-11-2019/">n-gon: summer-2019</option>
<option value="classic/9-8-2019/">n-gon: fall-2019</option>
<option value="classic/7-15-2020/">n-gon: summer-2020</option>
<option value="classic/6-1-2021/">n-gon: spring-2021</option>
<option value="classic/11-1-2022/">n-gon: fall-2022</option>
<option value="classic/7-29-2024/">n-gon: summer-2024</option>
<option value="" selected>current version</option>
</select>
<br>
<label for="seed" title="the randoms seed determines level order, tech choices, and mob types">randomization seed:</label>
<input type="text" id="seed" name="seed" autocomplete="off" spellcheck="false" minlength="1" style="width: 120px;">
<br><span id="previous-seed" style="color:#bbb"></span>
@@ -103,7 +86,7 @@
<div>
<details id="control-details">
<summary>controls</summary>
<div class="details-div">
<div class="details-div" style="max-width: 24rem;">
To change controls click a box
<br>and press an unused key.
<br><br>
@@ -171,22 +154,76 @@
<div>
<details id="updates">
<summary>updates</summary>
<div id="updates-div" class="details-div" style="font-size: 70%;height: 400px;overflow: scroll;max-width: 800px;"></div>
<div id="updates-div" class="details-div" style="font-size: 70%;height: 400px;overflow: scroll;max-width: 50rem;"></div>
</details>
</div>
<div>
<details>
<summary>about</summary>
<div class="details-div" style="max-width: 450px;">
n-gon is a solo project written in JavaScript, CSS, and HTML using the matter.js 2-D physics library. It's free and open source on <a href="https://github.com/landgreen/n-gon">Github</a>.
<div class="details-div" style="max-width: 24rem;padding:0.6em;font-size: 1.3rem;">
<a id="github" href="https://github.com/landgreen/n-gon" aria-label="github">
<svg viewBox="0 0 100 16" xmlns="http://www.w3.org/2000/svg" fill="#1B1F23">
<!-- <svg viewBox="0 0 100 16" xmlns="http://www.w3.org/2000/svg" fill="#1B1F23">
<path d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z" />
<g stroke='none' font-size="8px" font-family="Arial Black, sans-serif">
<text x="19" y="11">Github</text>
</g>
</svg> -->
<svg viewBox="-19 -8 40 16" xmlns="http://www.w3.org/2000/svg" stroke="#333" stroke-width="0.4" >
<defs>
<linearGradient id="horizontalGradient" x1="-8" y1="0" x2="8" y2="0" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="#e0e3e6" />
<stop offset="100%" stop-color="#fff" />
</linearGradient>
</defs>
<circle cx="0" cy="0" r="7" fill="url(#horizontalGradient)" />
<circle cx="4" cy="0" r="1.1" fill="none" />
<path d="M5.3 0 h1.7" stroke="#1B1F23" />
</svg>
</a>
</a>
<p>
I wrote n-gon in JavaScript, CSS, and HTML using the matter.js 2-D physics library.
The code is free and open source on <a id="github" href="https://github.com/landgreen/n-gon" aria-label="github">Github</a>.
This is just my hobby project, but I try to fix bugs when <a id="github" href="https://github.com/landgreen/n-gon/issues" aria-label="github">reported</a>.
</p>
<span style="max-width: 25rem; line-height: 180%;">
<label for="classic-select" title="play older versions of n-gon">classic n-gon:</label>
<select name="classic-select" id="classic-select" onChange="window.location.href=this.value">
<option value="https://scratch.mit.edu/projects/14005697/fullscreen/">mech: 2014</option>
<option value="https://scratch.mit.edu/projects/22573757/fullscreen/">spacetime: 2015</option>
<option value="https://scratch.mit.edu/projects/41429974/fullscreen/">ballistics: 2015</option>
<option value="https://scratch.mit.edu/projects/43690666/fullscreen/">portal: 2016</option>
<option value="https://codepen.io/lilgreenland/full/ozXNWZ">side scroller: 2016</option>
<option value="https://codepen.io/lilgreenland/full/wzARJY">side scroller: 2016</option>
<option value="classic/7-1-2017/">LandGame: 2017</option>
<option value="classic/4-15-2018/">n-gon: 2018</option>
<option value="classic/7-11-2019/">n-gon: summer-2019</option>
<option value="classic/9-8-2019/">n-gon: fall-2019</option>
<option value="classic/7-15-2020/">n-gon: summer-2020</option>
<option value="classic/6-1-2021/">n-gon: spring-2021</option>
<option value="classic/11-1-2022/">n-gon: fall-2022</option>
<option value="classic/7-29-2024/">n-gon: summer-2024</option>
<option value="" selected>old versions</option>
</select>
<br><label for="classic-select" title="community links">community links:</label>
<select name="classic-select" id="classic-select" onChange="window.location.href=this.value">
<option value="https://www.cornbread2100.com/n-gon-loader">n-commit loader</option>
<option value="https://3xiondev.github.io/n-gon-upgraded">n-gon upgraded</option>
<option value="https://n-gon-enhanced.vercel.app">n-gon enhanced</option>
<option value="https://coaldeficit.github.io/c-gon">c-gon</option>
<option value="https://kgurchiek.github.io/n-gon-portal-gun">n-gon portal gun</option>
<option value="https://github.com/Whyisthisnotavalable/n-scythe">n-scythe</option>
<option value="https://github.com/kgurchiek/n-gon-mobile">n-mobile</option>
<option value="https://github.com/kgurchiek/n-gon-controller">n-controller</option>
<option value="https://github.com/kgurchiek/n-gon-stopwatch">n-stopwatch</option>
<option value="https://github.com/Ant-Throw-Pology/n-qol">n-qol</option>
<option value="https://github.com/c-rxxp-y/n-gon-treasury">n-treasury</option>
<option value="https://github.com/3xionDev/n-docs">n-docs</option>
<option value="https://ngon.fandom.com/wiki/N-gon">n-wiki fandom</option>
<option value="https://n-gon.wiki/">n-wiki n-gon</option>
<option value="" selected>mods, forks, info</option>
</select>
</span>
</div>
</details>
</div>
@@ -228,8 +265,9 @@
<path d="M70 70 h60 v60 h-60 v-60" class="draw-lines-box-2" />
<path d="M140 70 h60 v60 h-60 v-60" class="draw-lines-box-3" />
</g>
<g fill='none' stroke='#333' stroke-width="3.5" stroke-linejoin="round" stroke-linecap="round">
<g fill='none' stroke='#333' stroke-width="3" stroke-linejoin="round" stroke-linecap="round">
<path d="M0 60 h60 v-60 h-60 v60" class="draw-lines-box-1" />
<!-- <rect x="0" y="0" width="60" height="60" rx="10" ry="10" class="draw-lines-box-1" /> -->
<path d="M70 60 h60 v-60 h-60 v60" class="draw-lines-box-2" />
<path d="M140 60 h60 v-60 h-60 v60" class="draw-lines-box-3" />
<path d="M0 70 h60 v60 h-60 v-60" class="draw-lines-box-1" />

View File

@@ -23,7 +23,7 @@ const b = {
},
fire() { },
fireNormal() {
if (b.inventory.length && b.activeGun !== null) {
if (b.inventory.length && (b.activeGun !== null && b.activeGun !== undefined)) {
if (input.fire && m.fireCDcycle < m.cycle && (!input.field || m.fieldFire)) {
if (b.guns[b.activeGun].ammo > 0) {
b.fireWithAmmo()
@@ -36,7 +36,7 @@ const b = {
}
},
fireNotMove() { //added && player.speed < 0.5 && m.onGround
if (b.inventory.length && b.activeGun !== null) {
if (b.inventory.length && (b.activeGun !== null && b.activeGun !== undefined)) {
if (input.fire && m.fireCDcycle < m.cycle && (!input.field || m.fieldFire) && player.speed < 2.5 && m.onGround && Math.abs(m.yOff - m.yOffGoal) < 1) {
if (b.guns[b.activeGun].ammo > 0) {
b.fireWithAmmo()
@@ -49,7 +49,7 @@ const b = {
}
},
fireAlwaysFire() { //added && player.speed < 0.5 && m.onGround //removed input.fire && (!input.field || m.fieldFire)
if (b.inventory.length && b.activeGun !== null) {
if (b.inventory.length && (b.activeGun !== null && b.activeGun !== undefined)) {
if (m.fireCDcycle < m.cycle && player.speed < 0.5 && m.onGround && Math.abs(m.yOff - m.yOffGoal) < 1) {
if (b.guns[b.activeGun].ammo > 0) {
b.fireWithAmmo()
@@ -60,7 +60,7 @@ const b = {
}
},
fireFloat() { //added && player.speed < 0.5 && m.onGround
if (b.inventory.length && b.activeGun !== null) {
if (b.inventory.length && (b.activeGun !== null && b.activeGun !== undefined)) {
if (input.fire && (!input.field || m.fieldFire)) {
if (m.fireCDcycle < m.cycle) {
if (b.guns[b.activeGun].ammo > 0) {
@@ -116,7 +116,7 @@ const b = {
}
},
refundAmmo() { //triggers after firing when you removed ammo for a gun, but didn't need to
if (tech.crouchAmmoCount && m.crouch && b.activeGun !== null) {
if (tech.crouchAmmoCount && m.crouch && (b.activeGun !== null && b.activeGun !== undefined)) {
tech.crouchAmmoCount--
if ((tech.crouchAmmoCount) % 2) {
b.guns[b.activeGun].ammo++;
@@ -280,14 +280,14 @@ const b = {
fireProps(cd, speed, dir, me) {
m.fireCDcycle = m.cycle + Math.floor(cd * b.fireCDscale); // cool down
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + speed * Math.cos(dir),
y: m.Vy / 2 + speed * Math.sin(dir)
x: 0.5 * player.velocity.x + speed * Math.cos(dir),
y: 0.5 * player.velocity.y + speed * Math.sin(dir)
});
Composite.add(engine.world, bullet[me]); //add bullet to world
},
fireCDscale: 1,
setFireCD() {
b.fireCDscale = tech.fireRate * tech.slowFire * tech.researchHaste * tech.aimDamage
b.fireCDscale = tech.fireRate * tech.slowFire * tech.researchHaste * tech.slowFireDamage
if (m.fieldMode === 6) b.fireCDscale *= 0.8
if (tech.isFastTime) b.fireCDscale *= 0.666
if (tech.isFireRateForGuns) b.fireCDscale *= Math.pow(0.76923, Math.max(0, b.inventory.length - 1))
@@ -377,7 +377,7 @@ const b = {
explosion(where, radius, color = "rgba(255,25,0,0.6)", reducedKnock = 1) { // typically explode is used for some bullets with .onEnd
radius *= tech.explosiveRadius
let dist, sub, knock;
let knock;
let dmg = radius * 0.019
if (tech.isExplosionHarm) radius *= 1.7 // 1/sqrt(2) radius -> area
if (tech.isSmallExplosion) {
@@ -385,10 +385,13 @@ const b = {
radius *= 0.7
dmg *= 1.7
}
let sub = Vector.sub(where, player.position);
let dist = Vector.magnitude(sub);
if (tech.isSmartRadius && radius > dist - 50) radius = Math.max(dist - 50, 1)
if (tech.isExplodeRadio) { //radiation explosion
radius *= 1.25; //alert range
if (tech.isSmartRadius) radius = Math.max(Math.min(radius, Vector.magnitude(Vector.sub(where, player.position)) - 25), 1)
// if (tech.isSmartRadius) radius = Math.max(Math.min(radius, Vector.magnitude(Vector.sub(where, player.position)) - 25), 1)
color = "rgba(25,139,170,0.25)"
simulation.drawList.push({ //add dmg to draw queue
x: where.x,
@@ -425,7 +428,7 @@ const b = {
}
}
} else { //normal explosions
if (tech.isSmartRadius) radius = Math.max(Math.min(radius, Vector.magnitude(Vector.sub(where, player.position)) - 25), 1)
// if (tech.isSmartRadius) radius = Math.max(Math.min(radius, Vector.magnitude(Vector.sub(where, player.position)) - 25), 1)
simulation.drawList.push({ //add dmg to draw queue
x: where.x,
y: where.y,
@@ -444,9 +447,6 @@ const b = {
//player damage and knock back
if (m.immuneCycle < m.cycle) {
sub = Vector.sub(where, player.position);
dist = Vector.magnitude(sub);
if (dist < radius) {
if (simulation.dmgScale) {
const harm = tech.isExplosionHarm ? 0.067 : 0.05
@@ -624,7 +624,7 @@ const b = {
clusterExplode(where, size) { //can occur after grenades detonate
const cycle = () => {
if (m.alive) {
if (simulation.paused || m.isBodiesAsleep) {
if (simulation.paused || m.isTimeDilated) {
requestAnimationFrame(cycle)
} else {
count++
@@ -643,7 +643,7 @@ const b = {
const color = `hsla(${360 * Math.random()},100%,66%,0.6)`
const cycle = () => {
if (m.alive) {
if (simulation.paused || m.isBodiesAsleep) {
if (simulation.paused || m.isTimeDilated) {
requestAnimationFrame(cycle)
} else {
count++
@@ -668,7 +668,7 @@ const b = {
const range = size * Math.sqrt(b.explosionRange())
const cycle = () => {
if (m.alive) {
if (simulation.paused || m.isBodiesAsleep) {
if (simulation.paused || m.isTimeDilated) {
requestAnimationFrame(cycle)
} else {
if (count < 30 && m.alive) requestAnimationFrame(cycle);
@@ -734,8 +734,8 @@ const b = {
};
speed = m.crouch ? 43 : 32
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + speed * Math.cos(angle),
y: m.Vy / 2 + speed * Math.sin(angle)
x: 0.5 * player.velocity.x + speed * Math.cos(angle),
y: 0.5 * player.velocity.y + speed * Math.sin(angle)
});
bullet[me].endCycle = simulation.cycle + Math.floor(m.crouch ? 120 : 80) * tech.bulletsLastLonger;
bullet[me].restitution = 0.4;
@@ -759,8 +759,8 @@ const b = {
};
speed = m.crouch ? 46 : 32
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + speed * Math.cos(angle),
y: m.Vy / 2 + speed * Math.sin(angle)
x: 0.8 * player.velocity.x + speed * Math.cos(angle),
y: 0.5 * player.velocity.y + speed * Math.sin(angle)
});
Composite.add(engine.world, bullet[me]); //add bullet to world
@@ -794,8 +794,8 @@ const b = {
};
speed = m.crouch ? 46 : 32
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + speed * Math.cos(angle),
y: m.Vy / 2 + speed * Math.sin(angle)
x: 0.8 * player.velocity.x + speed * Math.cos(angle),
y: 0.5 * player.velocity.y + speed * Math.sin(angle)
});
Composite.add(engine.world, bullet[me]); //add bullet to world
bullet[me].endCycle = simulation.cycle + 70 * tech.bulletsLastLonger;
@@ -924,8 +924,8 @@ const b = {
bullet[me].endCycle += 20;
}
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + speed * Math.cos(angle),
y: m.Vy / 2 + speed * Math.sin(angle)
x: 0.5 * player.velocity.x + speed * Math.cos(angle),
y: 0.5 * player.velocity.y + speed * Math.sin(angle)
});
Composite.add(engine.world, bullet[me]); //add bullet to world
}
@@ -951,7 +951,7 @@ const b = {
Matter.Body.scale(bullet[me], SCALE, SCALE);
speed = m.crouch ? 25 : 15
// speed = m.crouch ? 43 : 32
Matter.Body.setVelocity(bullet[me], { x: m.Vx / 2 + speed * Math.cos(angle), y: m.Vy / 2 + speed * Math.sin(angle) });
Matter.Body.setVelocity(bullet[me], { x: 0.5 * player.velocity.x + speed * Math.cos(angle), y: 0.5 * player.velocity.y + speed * Math.sin(angle) });
const MAG = 0.005
bullet[me].thrust = { x: bullet[me].mass * MAG * Math.cos(angle), y: bullet[me].mass * MAG * Math.sin(angle) }
}
@@ -1140,148 +1140,6 @@ const b = {
}
}
},
// dart(where, angle = m.angle, size = 0.8) {
// //find a target
// const closest = {
// score: 10000,
// position: null
// }
// for (let i = 0, len = mob.length; i < len; ++i) {
// if (mob[i].alive && !mob[i].isBadTarget && Matter.Query.ray(map, where, mob[i].position).length === 0) {
// const dot = Vector.dot({ x: Math.cos(angle), y: Math.sin(angle) }, Vector.normalise(Vector.sub(mob[i].position, where))) //the dot product of diff and dir will return how much over lap between the vectors
// const dist = Vector.magnitude(Vector.sub(where, mob[i].position))
// // if (dist < closest.score && ((dist > 500 && dot > 0) || (dot > 0.9))) { //target closest mob that player is looking at and isn't too close to target
// if (dist < closest.score && dot > 0.9 - 0.0004 * dist) { //target closest mob that player is looking at and isn't too close to target
// closest.score = dist
// closest.position = mob[i].position
// }
// }
// }
// if (!closest.position) {
// // const unit = Vector.mult(sub(simulation.mouseInGame, where), 10000)
// closest.position = Vector.mult(Vector.sub(simulation.mouseInGame, where), 10000)
// }
// const me = bullet.length;
// bullet[me] = Bodies.fromVertices(where.x, where.y, [{ x: -20 * size, y: 2 * size, index: 0, isInternal: false }, { x: -20 * size, y: -2 * size, index: 1, isInternal: false }, { x: 5 * size, y: -2 * size, index: 4, isInternal: false }, { x: 20 * size, y: 0, index: 3, isInternal: false }, { x: 5 * size, y: 2 * size, index: 4, isInternal: false }], {
// cycle: 0,
// angle: angle,
// friction: 1,
// frictionAir: 0.15,
// thrustMag: 0.03,
// turnRate: 0.15, //0.015
// drawStringControlMagnitude: 3000 + 5000 * Math.random(),
// drawStringFlip: (Math.round(Math.random()) ? 1 : -1),
// dmg: 7, //damage done in addition to the damage from momentum
// classType: "bullet",
// endCycle: simulation.cycle + 120,
// collisionFilter: {
// category: cat.bullet,
// mask: tech.isShieldPierce ? cat.body | cat.mob | cat.mobBullet : cat.body | cat.mob | cat.mobBullet | cat.mobShield,
// },
// minDmgSpeed: 0,
// lookFrequency: Math.floor(7 + Math.random() * 3),
// density: 0.001, //0.001 is normal for blocks, 0.008 is normal for harpoon, 0.008*6 when buffed
// beforeDmg(who) {
// if (tech.isShieldPierce && who.isShielded) { //disable shields
// who.isShielded = false
// requestAnimationFrame(() => { who.isShielded = true });
// }
// if (tech.fragments) {
// b.targetedNail(this.vertices[2], tech.fragments * Math.floor(2 + 1.5 * Math.random()))
// this.endCycle = 0;
// }
// if (!who.isBadTarget) {
// this.frictionAir = 0.01
// this.do = this.doNoTargeting
// }
// },
// onEnd() {},
// doNoTargeting: function() {
// // this.force.y += this.mass * 0.001;
// if (Matter.Query.collides(this, map).length) { //stick in walls
// this.collisionFilter.mask = 0;
// Matter.Body.setAngularVelocity(this, 0)
// Matter.Body.setVelocity(this, {
// x: 0,
// y: 0
// });
// this.do = () => {
// // if (!Matter.Query.collides(this, map).length) this.force.y += this.mass * 0.001;
// }
// }
// },
// do() {
// this.cycle++
// // if (this.cycle > 40) {
// // this.frictionAir = 0.003
// // this.do = this.doNoTargeting
// // }
// // if (closest.target) { //rotate towards the target
// const face = { x: Math.cos(this.angle), y: Math.sin(this.angle) };
// const vectorGoal = Vector.normalise(Vector.sub(this.position, closest.position));
// const cross = Vector.cross(vectorGoal, face)
// if (cross > 0.01) {
// Matter.Body.rotate(this, this.turnRate * Math.sqrt(cross));
// } else if (cross < 0.01) {
// Matter.Body.rotate(this, -this.turnRate * Math.sqrt(Math.abs(cross)));
// }
// this.force.x += this.thrustMag * this.mass * Math.cos(this.angle);
// this.force.y += this.thrustMag * this.mass * Math.sin(this.angle);
// // }
// if (Matter.Query.collides(this, map).length) { //stick in walls
// this.collisionFilter.mask = 0;
// Matter.Body.setAngularVelocity(this, 0)
// Matter.Body.setVelocity(this, {
// x: 0,
// y: 0
// });
// this.do = this.doNoTargeting
// }
// // else if (!(this.cycle % 2)) { //look for a target if you don't have one
// // simulation.drawList.push({ //add dmg to draw queue
// // x: this.position.x,
// // y: this.position.y,
// // radius: 10,
// // color: simulation.mobDmgColor,
// // time: simulation.drawTime
// // });
// // let closest = {
// // distance: 2000,
// // target: null
// // }
// // const dir = Vector.normalise(this.velocity) //make a vector for direction of length 1
// // for (let i = 0, len = mob.length; i < len; ++i) {
// // if (
// // mob[i].alive && !mob[i].isBadTarget &&
// // Matter.Query.ray(map, this.position, mob[i].position).length === 0 && //check for map in Line of sight
// // Vector.dot(dir, Vector.normalise(Vector.sub(mob[i].position, this.position))) > 0.55 //the dot product of diff and dir will return how much over lap between the vectors
// // ) {
// // const dist = Vector.magnitude(Vector.sub(this.position, mob[i].position))
// // if (dist < closest.distance) {
// // closest.distance = dist
// // closest.target = mob[i]
// // }
// // }
// // }
// // if (closest.target) {
// // target = closest.target
// // this.turnRate = 0.05
// // this.frictionAir = 0.8
// // }
// // }
// },
// });
// Matter.Body.setVelocity(bullet[me], {
// x: m.Vx / 2 + 40 * Math.cos(bullet[me].angle),
// y: m.Vy / 2 + 40 * Math.sin(bullet[me].angle)
// });
// // if (!closest.target) {
// // bullet[me].frictionAir = 0.002
// // bullet[me].do = bullet[me].doNoTargeting
// // }
// Composite.add(engine.world, bullet[me]); //add bullet to world
// },
grapple(where, angle = m.angle) {
const me = bullet.length;
const returnRadius = 100
@@ -1962,8 +1820,8 @@ const b = {
});
if (!isReturn && !target) {
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + 600 * thrust * Math.cos(bullet[me].angle),
y: m.Vy / 2 + 600 * thrust * Math.sin(bullet[me].angle)
x: 0.7 * player.velocity.x + 600 * thrust * Math.cos(bullet[me].angle),
y: 0.5 * player.velocity.x + 600 * thrust * Math.sin(bullet[me].angle)
});
bullet[me].frictionAir = 0.002
bullet[me].do = function () {
@@ -2084,8 +1942,8 @@ const b = {
});
const thrust = 0.0066 * bullet[me].mass * (tech.isMissileBig ? (tech.isMissileBiggest ? 0.3 : 0.7) : 1);
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + speed * Math.cos(angle),
y: m.Vy / 2 + speed * Math.sin(angle)
x: 0.5 * player.velocity.x + speed * Math.cos(angle),
y: 0.5 * player.velocity.y + speed * Math.sin(angle)
});
Composite.add(engine.world, bullet[me]); //add bullet to world
},
@@ -2322,7 +2180,7 @@ const b = {
const d = Vector.sub(path[path.length - 1], path[path.length - 2]);
const nn = Vector.mult(n, 2 * Vector.dot(d, n));
const r = Vector.normalise(Vector.sub(d, nn));
path[path.length] = Vector.add(Vector.mult(r, 3000), path[path.length - 1]);
path[path.length] = Vector.add(Vector.mult(r, 5000), path[path.length - 1]);
};
checkForCollisions();
@@ -2761,14 +2619,14 @@ const b = {
}
}
},
spore(where, isFreeze = tech.isSporeFreeze) { //used with the tech upgrade in mob.death()
spore(where, velocity = null) { //used with the tech upgrade in mob.death()
const bIndex = bullet.length;
const size = 4
if (bIndex < 500) { //can't make over 500 spores
bullet[bIndex] = Bodies.polygon(where.x, where.y, size, size, {
// density: 0.0015, //frictionAir: 0.01,
inertia: Infinity,
isFreeze: isFreeze,
isFreeze: tech.isSporeFreeze,
restitution: 0.5,
angle: Math.random() * 2 * Math.PI,
friction: 0,
@@ -2835,57 +2693,19 @@ const b = {
}
}
// if (!this.lockedOn && !(simulation.cycle % this.lookFrequency)) { //find mob targets
// this.closestTarget = null;
// this.lockedOn = null;
// let closeDist = Infinity;
// for (let i = 0, len = mob.length; i < len; ++i) {
// if (mob[i].isDropPowerUp && Matter.Query.ray(map, this.position, mob[i].position).length === 0) {
// // Matter.Query.ray(body, this.position, mob[i].position).length === 0
// const targetVector = Vector.sub(this.position, mob[i].position)
// const dist = Vector.magnitude(targetVector);
// if (dist < closeDist) {
// this.closestTarget = mob[i].position;
// closeDist = dist;
// this.lockedOn = mob[i] //Vector.normalise(targetVector);
// if (0.3 > Math.random()) break //doesn't always target the closest mob
// }
// }
// }
// }
// if (this.lockedOn && this.lockedOn.alive) { //accelerate towards mobs
// this.force = Vector.mult(Vector.normalise(Vector.sub(this.lockedOn.position, this.position)), this.mass * this.thrust)
// } else if (tech.isSporeFollow && this.lockedOn !== undefined) { //move towards player
// //checking for undefined means that the spores don't go after the player until it has looked and not found a target
// const dx = this.position.x - m.pos.x;
// const dy = this.position.y - m.pos.y;
// if (dx * dx + dy * dy > 10000) {
// this.force = Vector.mult(Vector.normalise(Vector.sub(m.pos, Vector.add(this.playerOffPosition, this.position))), this.mass * this.thrust)
// }
// // this.force = Vector.mult(Vector.normalise(Vector.sub(m.pos, this.position)), this.mass * this.thrust)
// } else {
// this.force.y += this.mass * 0.0001; //gravity
// }
// if (this.nextPortCycle < simulation.cycle) { //teleport around if you have tech.isBulletTeleport
// this.nextPortCycle = simulation.cycle + this.portFrequency
// const range = 50 * Math.random()
// Matter.Body.setPosition(this, Vector.add(this.position, Vector.rotate({ x: range, y: 0 }, 2 * Math.PI * Math.random())))
// }
},
});
// if (tech.isBulletTeleport) {
// bullet[bIndex].portFrequency = 10 + Math.floor(5 * Math.random())
// bullet[bIndex].nextPortCycle = simulation.cycle + bullet[bIndex].portFrequency
// }
if (velocity) {
Matter.Body.setVelocity(bullet[bIndex], velocity);
} else {
const SPEED = 4 + 8 * Math.random();
const ANGLE = 2 * Math.PI * Math.random()
Matter.Body.setVelocity(bullet[bIndex], {
x: SPEED * Math.cos(ANGLE),
y: SPEED * Math.sin(ANGLE)
});
}
const SPEED = 4 + 8 * Math.random();
const ANGLE = 2 * Math.PI * Math.random()
Matter.Body.setVelocity(bullet[bIndex], {
x: SPEED * Math.cos(ANGLE),
y: SPEED * Math.sin(ANGLE)
});
Composite.add(engine.world, bullet[bIndex]); //add bullet to world
if (tech.isMutualism && m.health > 0.01) {
@@ -2972,11 +2792,6 @@ const b = {
y: speed * Math.sin(dir)
});
Matter.Body.setAngularVelocity(bullet[me], 3000 * bullet[me].spin);
// Matter.Body.setVelocity(bullet[me], {
// x: m.Vx / 2 + speed * Math.cos(dir),
// y: m.Vy / 2 + speed * Math.sin(dir)
// });
},
flea(where, velocity, radius = 6 + 3 * Math.random() + 10 * tech.wormSize * Math.random()) {
const me = bullet.length;
@@ -3307,7 +3122,7 @@ const b = {
if (
Vector.magnitudeSquared(Vector.sub(this.position, powerUp[i].position)) < 20000 &&
!(
(m.health > 0.93 * m.maxHealth && !tech.isDroneGrab && powerUp[i].name === "heal") ||
(m.health > 0.94 * m.maxHealth && !tech.isOverHeal && !tech.isDroneGrab && powerUp[i].name === "heal") ||
(tech.isSuperDeterminism && powerUp[i].name === "field") ||
((tech.isEnergyNoAmmo || b.inventory.length === 0) && powerUp[i].name === "ammo")
)
@@ -3339,7 +3154,7 @@ const b = {
let closeDist = Infinity;
for (let i = 0, len = powerUp.length; i < len; ++i) {
if (!(
(m.health > 0.93 * m.maxHealth && !tech.isDroneGrab && powerUp[i].name === "heal") ||
(m.health > 0.94 * m.maxHealth && !tech.isOverHeal && !tech.isDroneGrab && powerUp[i].name === "heal") ||
(tech.isSuperDeterminism && powerUp[i].name === "field") ||
((tech.isEnergyNoAmmo || b.inventory.length === 0) && powerUp[i].name === "ammo")
)) {
@@ -3810,165 +3625,6 @@ const b = {
}
return shotsFired
},
// plasmaBall(position, velocity, radius) {
// // radius *= Math.sqrt(tech.bulletSize)
// const me = bullet.length;
// bullet[me] = Bodies.polygon(position.x, position.y, 20, radius, {
// density: 0.000001, // 0.001 is normal density
// inertia: Infinity,
// frictionAir: 0.003,
// dmg: 0, //damage on impact
// damage: 0, //damage done over time
// scale: 1 - 0.006 / tech.bulletsLastLonger,
// classType: "bullet",
// collisionFilter: {
// category: cat.bullet,
// mask: 0 //cat.mob | cat.mobBullet // cat.map | cat.body | cat.mob | cat.mobShield
// },
// minDmgSpeed: 0,
// endCycle: Infinity,
// count: 0,
// radius: radius,
// portFrequency: 5 + Math.floor(5 * Math.random()),
// nextPortCycle: Infinity, //disabled unless you have the teleport tech
// beforeDmg(who) {
// 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
// } 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
// } else {
// this.targetRelativePosition = Vector.rotate(Vector.sub(this.position, who.position), -who.angle) //find relative position vector for zero mob rotation
// }
// this.collisionFilter.category = cat.body;
// this.collisionFilter.mask = null;
// let bestVertexDistance = Infinity
// let bestVertex = null
// for (let i = 0; i < this.target.vertices.length; i++) {
// const dist = Vector.magnitude(Vector.sub(this.position, this.target.vertices[i]));
// if (dist < bestVertexDistance) {
// bestVertex = i
// bestVertexDistance = dist
// }
// }
// this.targetVertex = bestVertex
// }
// },
// onEnd() {},
// do() {
// if (this.count < 20) {
// this.count++
// //grow
// const SCALE = 1.06
// Matter.Body.scale(this, SCALE, SCALE);
// this.radius *= SCALE;
// } else {
// //shrink
// Matter.Body.scale(this, this.scale, this.scale);
// this.radius *= this.scale;
// if (this.radius < 8) this.endCycle = 0;
// }
// if (this.target && this.target.alive) { //if stuck to a target
// const rotate = Vector.rotate(this.targetRelativePosition, this.target.angle) //add in the mob's new angle to the relative position vector
// if (this.target.isVerticesChange) {
// Matter.Body.setPosition(this, this.target.vertices[this.targetVertex])
// } else {
// Matter.Body.setPosition(this, Vector.add(Vector.add(rotate, this.target.velocity), this.target.position))
// }
// if (this.target.isBoss) {
// if (this.target.speed > 8) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.98))
// } else {
// if (this.target.speed > 4) Matter.Body.setVelocity(this.target, Vector.mult(this.target.velocity, 0.95))
// }
// Matter.Body.setAngularVelocity(this.target, this.target.angularVelocity * 0.9);
// // Matter.Body.setAngularVelocity(this.target, this.target.angularVelocity * 0.9)
// if (this.target.isShielded) {
// this.target.damage(m.dmgScale * this.damage, true); //shield damage bypass
// const SCALE = 1 - 0.004 / tech.bulletsLastLonger //shrink if mob is shielded
// Matter.Body.scale(this, SCALE, SCALE);
// this.radius *= SCALE;
// } else {
// this.target.damage(m.dmgScale * this.damage);
// }
// } else if (this.target !== null) { //look for a new target
// this.collisionFilter.category = cat.bullet;
// this.collisionFilter.mask = cat.mob //| cat.mobShield //cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield
// if (tech.isSpawnBulletsOnDeath && bullet.length < 180 && !this.target.isMobBullet) {
// let targets = []
// for (let i = 0, len = mob.length; i < len; i++) {
// const dist = Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position));
// if (dist < 1000000) targets.push(mob[i])
// }
// const radius = Math.min(this.radius * 0.5, 9)
// const len = bullet.length < 80 ? 2 : 1
// for (let i = 0; i < len; i++) {
// if (targets.length - i > 0) {
// const index = Math.floor(Math.random() * targets.length)
// const speed = 6 + 6 * Math.random()
// const velocity = Vector.mult(Vector.normalise(Vector.sub(targets[index].position, this.position)), speed)
// b.foam(this.position, Vector.rotate(velocity, 0.5 * (Math.random() - 0.5)), radius)
// } else {
// b.foam(this.position, Vector.rotate({
// x: 15 + 10 * Math.random(),
// y: 0
// }, 2 * Math.PI * Math.random()), radius)
// }
// }
// }
// this.target = null
// } else if (Matter.Query.point(map, this.position).length > 0) { //slow when touching map or blocks
// const slow = 0.85
// Matter.Body.setVelocity(this, {
// x: this.velocity.x * slow,
// y: this.velocity.y * slow
// });
// const SCALE = 0.96
// Matter.Body.scale(this, SCALE, SCALE);
// this.radius *= SCALE;
// // } else if (Matter.Query.collides(this, body).length > 0) {
// } else if (Matter.Query.point(body, this.position).length > 0) {
// const slow = 0.9
// Matter.Body.setVelocity(this, {
// x: this.velocity.x * slow,
// y: this.velocity.y * slow
// });
// const SCALE = 0.96
// Matter.Body.scale(this, SCALE, SCALE);
// this.radius *= SCALE;
// } else {
// this.force.y += this.mass * tech.foamGravity; //gravity
// if (tech.isFoamAttract) {
// for (let i = 0, len = mob.length; i < len; i++) {
// if (!mob[i].isBadTarget && Vector.magnitude(Vector.sub(mob[i].position, this.position)) < 375 && mob[i].alive && Matter.Query.ray(map, this.position, mob[i].position).length === 0) {
// this.force = Vector.mult(Vector.normalise(Vector.sub(mob[i].position, this.position)), this.mass * 0.004)
// const slow = 0.9
// Matter.Body.setVelocity(this, {
// x: this.velocity.x * slow,
// y: this.velocity.y * slow
// });
// break
// }
// }
// }
// }
// if (this.nextPortCycle < simulation.cycle) { //teleport around if you have tech.isBulletTeleport
// this.nextPortCycle = simulation.cycle + this.portFrequency
// const range = 15 * 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())))
// }
// }
// });
// if (tech.isBulletTeleport) bullet[me].nextPortCycle = simulation.cycle + bullet[me].portFrequency
// Composite.add(engine.world, bullet[me]); //add bullet to world
// Matter.Body.setVelocity(bullet[me], velocity);
// },
foam(position, velocity, radius) {
if (tech.isFoamCavitation && Math.random() < 0.25) {
velocity = Vector.mult(velocity, 1.35)
@@ -4024,10 +3680,7 @@ const b = {
}
}
this.targetVertex = bestVertex
Matter.Body.setVelocity(this, {
x: 0,
y: 0
});
Matter.Body.setVelocity(this, { x: 0, y: 0 });
}
},
onEnd() { },
@@ -4070,10 +3723,7 @@ const b = {
} else if (this.target !== null) { //look for a new target
this.collisionFilter.category = cat.bullet;
this.collisionFilter.mask = cat.mob //| cat.mobShield //cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield
Matter.Body.setVelocity(this, {
x: this.target.velocity.x,
y: this.target.velocity.y
});
Matter.Body.setVelocity(this, { x: this.target.velocity.x, y: this.target.velocity.y });
if (tech.isSpawnBulletsOnDeath && bullet.length < 180 && !this.target.isMobBullet) {
let targets = []
for (let i = 0, len = mob.length; i < len; i++) {
@@ -4099,20 +3749,14 @@ const b = {
this.target = null
} else if (Matter.Query.point(map, this.position).length > 0) { //slow when touching map
const slow = 0.87
Matter.Body.setVelocity(this, {
x: this.velocity.x * slow,
y: this.velocity.y * slow
});
Matter.Body.setVelocity(this, { x: this.velocity.x * slow, y: this.velocity.y * slow });
const SCALE = 0.97
Matter.Body.scale(this, SCALE, SCALE);
this.radius *= SCALE;
// } else if (Matter.Query.collides(this, body).length > 0) {
} else if (Matter.Query.point(body, this.position).length > 0) { //slow when touching blocks
const slow = 0.94
Matter.Body.setVelocity(this, {
x: this.velocity.x * slow,
y: this.velocity.y * slow
});
Matter.Body.setVelocity(this, { x: this.velocity.x * slow, y: this.velocity.y * slow });
const SCALE = 0.99
Matter.Body.scale(this, SCALE, SCALE);
this.radius *= SCALE;
@@ -4247,7 +3891,7 @@ const b = {
bullet[me] = Bodies.rectangle(pos.x, pos.y, 25 * tech.bulletSize, 2 * tech.bulletSize, b.fireAttributes(Math.atan2(velocity.y, velocity.x)));
Matter.Body.setVelocity(bullet[me], velocity);
Composite.add(engine.world, bullet[me]); //add bullet to world
bullet[me].endCycle = simulation.cycle + 60 + 18 * Math.random();
bullet[me].endCycle = simulation.cycle + 80 + 18 * Math.random();
bullet[me].dmg = tech.isNailRadiation ? 0 : dmg
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
@@ -4417,8 +4061,8 @@ const b = {
}
const SPEED = 90
Matter.Body.setVelocity(bullet[me], {
x: m.Vx / 2 + SPEED * Math.cos(angle),
y: m.Vy / 2 + SPEED * Math.sin(angle)
x: 0.5 * player.velocity.x + SPEED * Math.cos(angle),
y: 0.5 * player.velocity.y + SPEED * Math.sin(angle)
});
// Matter.Body.setDensity(bullet[me], 0.00001);
Composite.add(engine.world, bullet[me]); //add bullet to world
@@ -4505,14 +4149,15 @@ const b = {
}
},
zeroBotCount() { //remove all bots
tech.dynamoBotCount = 0
tech.laserBotCount = 0
tech.nailBotCount = 0
tech.foamBotCount = 0
tech.soundBotCount = 0
tech.boomBotCount = 0
tech.orbitBotCount = 0
tech.missileBotCount = 0
tech.dynamoBotCount = 0;
tech.nailBotCount = 0;
tech.laserBotCount = 0;
tech.orbitBotCount = 0;
tech.foamBotCount = 0;
tech.soundBotCount = 0;
tech.boomBotCount = 0;
tech.plasmaBotCount = 0;
tech.missileBotCount = 0;
},
respawnBots() {
for (let i = 0; i < tech.dynamoBotCount; i++) b.dynamoBot({
@@ -5032,7 +4677,7 @@ const b = {
} else { //fire mode: quickly fire at targets and doesn't follow player
this.fire()
}
if (!m.isBodiesAsleep) { //update current waves
if (!m.isTimeDilated) { //update current waves
ctx.strokeStyle = "rgba(0,0,0,0.6)" //"000";
ctx.lineWidth = 2 * tech.wavePacketDamage
ctx.beginPath();
@@ -5713,7 +5358,7 @@ const b = {
b.needle()
function cycle() {
if (simulation.paused || m.isBodiesAsleep) {
if (simulation.paused || m.isTimeDilated) {
requestAnimationFrame(cycle)
} else {
count++
@@ -5728,7 +5373,7 @@ const b = {
b.needle()
function cycle() {
if (simulation.paused || m.isBodiesAsleep) {
if (simulation.paused || m.isTimeDilated) {
requestAnimationFrame(cycle)
} else {
count++
@@ -5927,8 +5572,8 @@ const b = {
x: m.pos.x + 30 * Math.cos(m.angle),
y: m.pos.y + 30 * Math.sin(m.angle)
}, {
x: m.Vx / 2 + speed * Math.cos(angle),
y: m.Vy / 2 + speed * Math.sin(angle)
x: 0.8 * player.velocity.x + speed * Math.cos(angle),
y: 0.5 * player.velocity.y + speed * Math.sin(angle)
}) //position, velocity, damage
if (tech.isIceCrystals) {
bullet[bullet.length - 1].beforeDmg = function (who) {
@@ -6200,8 +5845,8 @@ const b = {
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)
x: 0.6 * player.velocity.x + SPEED * Math.cos(angle),
y: 0.5 * player.velocity.y + SPEED * Math.sin(angle)
}, 8 + 7 * Math.random())
}
} else if (tech.isNeedles) {
@@ -6332,8 +5977,8 @@ const b = {
return `emit <strong>wave packets</strong> that propagate through <strong>solids</strong><br>waves <strong class='color-s'>slow</strong> mobs<br><strong>${this.ammoPack.toFixed(0)}</strong> wave packets per ${powerUps.orb.ammo()}`
},
ammo: 0,
ammoPack: 52,
defaultAmmoPack: 52,
ammoPack: 60,
defaultAmmoPack: 60,
have: false,
wavePacketCycle: 0,
delay: 40,
@@ -6356,7 +6001,7 @@ const b = {
},
do() { },
do360Longitudinal() {
if (!m.isBodiesAsleep) {
if (!m.isTimeDilated) {
ctx.strokeStyle = "rgba(0,0,0,0.6)" //"000";
ctx.lineWidth = 2 * tech.wavePacketDamage
ctx.beginPath();
@@ -6453,7 +6098,7 @@ const b = {
})
},
doLongitudinal() {
if (!m.isBodiesAsleep) {
if (!m.isTimeDilated) {
ctx.strokeStyle = "rgba(0,0,0,0.6)" //"000";
ctx.lineWidth = 2 * tech.wavePacketDamage
ctx.beginPath();
@@ -6654,12 +6299,12 @@ const b = {
}
}
}
let waveSpeedMap = 0.1
let waveSpeedBody = 0.25
let waveSpeedMap = 0.13
let waveSpeedBody = 0.3
if (tech.isPhaseVelocity) {
waveSpeedMap = 3.5
waveSpeedBody = 2
bullet[me].dmg *= 1.4
bullet[me].dmg *= 1.5
}
if (tech.waveReflections) {
bullet[me].reflectCycle = totalCycles / tech.waveReflections //tech.waveLengthRange
@@ -7061,8 +6706,12 @@ const b = {
isDischarge: false,
knockBack: 0.0005, //set in tech: cavitation
applyKnock(velocity) {
player.force.x -= this.knockBack * velocity.x
player.force.y -= 2 * this.knockBack * velocity.y
player.force.x -= 0.7 * this.knockBack * velocity.x
if (velocity.y > 0) {
player.force.y -= 4.3 * this.knockBack * velocity.y
} else {
player.force.y -= this.knockBack * velocity.y
}
},
chooseFireMethod() {
if (tech.isFoamPressure) {
@@ -7082,7 +6731,10 @@ const b = {
const radius = 5 + 8 * Math.random() + (tech.isAmmoFoamSize && this.ammo < 300) * 12
const SPEED = (m.crouch ? 1.2 : 1) * Math.max(2, 14 - radius * 0.25)
const dir = m.angle + 0.15 * (Math.random() - 0.5)
const velocity = { x: SPEED * Math.cos(dir), y: SPEED * Math.sin(dir) }
const velocity = {
x: 0.7 * player.velocity.x + SPEED * Math.cos(dir),
y: 0.5 * player.velocity.y + SPEED * Math.sin(dir)
}
const position = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
b.foam(position, Vector.rotate(velocity, spread), radius)
this.applyKnock(velocity)
@@ -7104,8 +6756,8 @@ const b = {
const SPEED = (m.crouch ? 1.2 : 1) * 10 - radius * 0.4 + Math.min(5, Math.sqrt(this.charge));
const dir = m.angle + 0.15 * (Math.random() - 0.5)
const velocity = {
x: SPEED * Math.cos(dir),
y: SPEED * Math.sin(dir)
x: 0.7 * player.velocity.x + SPEED * Math.cos(dir),
y: 0.5 * player.velocity.y + SPEED * Math.sin(dir)
}
const position = {
x: m.pos.x + 30 * Math.cos(m.angle),
@@ -7134,29 +6786,11 @@ const b = {
const SPEED = (m.crouch ? 1.2 : 1) * Math.max(2, 14 - radius * 0.25)
const dir = m.angle + 0.15 * (Math.random() - 0.5)
const velocity = {
x: SPEED * Math.cos(dir),
y: SPEED * Math.sin(dir)
x: 0.7 * player.velocity.x + SPEED * Math.cos(dir),
y: 0.5 * player.velocity.y + SPEED * Math.sin(dir)
}
const position = {
x: m.pos.x + 30 * Math.cos(m.angle),
y: m.pos.y + 30 * Math.sin(m.angle)
}
// if (tech.foamFutureFire) {
// simulation.drawList.push({ //add dmg to draw queue
// x: position.x,
// y: position.y,
// radius: 5,
// color: "rgba(0,50,50,0.3)",
// time: 15 * tech.foamFutureFire
// });
// setTimeout(() => {
// if (!simulation.paused) {
// b.foam(position, Vector.rotate(velocity, spread), radius)
// bullet[bullet.length - 1].damage *= (1 + 0.7 * tech.foamFutureFire)
// }
// }, 210 * tech.foamFutureFire);
// } else {
// }
const position = { x: m.pos.x + 30 * Math.cos(m.angle), y: m.pos.y + 30 * Math.sin(m.angle) }
b.foam(position, Vector.rotate(velocity, spread), radius)
this.applyKnock(velocity)
m.fireCDcycle = m.cycle + Math.floor(1.5 * b.fireCDscale);
@@ -7698,6 +7332,8 @@ const b = {
};
}
} else if (tech.beamCollimator) {
this.fire = this.fireSplitCollimator
} else if (tech.beamSplitter) {
this.fire = this.fireSplit
} else if (tech.historyLaser) {
@@ -7716,16 +7352,14 @@ const b = {
} else {
m.fireCDcycle = m.cycle
m.energy -= drain
const where = {
x: m.pos.x + 20 * Math.cos(m.angle),
y: m.pos.y + 20 * Math.sin(m.angle)
}
const where = { x: m.pos.x + 20 * Math.cos(m.angle), y: m.pos.y + 20 * Math.sin(m.angle) }
b.laser(where, {
x: where.x + 3000 * Math.cos(m.angle),
y: where.y + 3000 * Math.sin(m.angle)
x: where.x + 5000 * Math.cos(m.angle),
y: where.y + 5000 * Math.sin(m.angle)
}, tech.laserDamage / b.fireCDscale * this.lensDamage);
}
},
firePulse() { },
fireSplit() {
const drain = tech.laserDrain / b.fireCDscale
@@ -7749,6 +7383,29 @@ const b = {
}
}
},
fireSplitCollimator() {
const drain = tech.laserDrain / b.fireCDscale
if (m.energy < drain) {
m.fireCDcycle = m.cycle + 100; // cool down if out of energy
} else {
m.fireCDcycle = m.cycle
m.energy -= drain
const freq = 0.037
const len = tech.beamSplitter + 1
const phase = 2 * Math.PI / len
for (let i = 0; i < len; i++) {
if (Math.sin(m.cycle * freq + phase * (i) + Math.PI / 2) > 0 || !(m.cycle % 3)) ctx.globalAlpha = 0.35
const whereSweep = m.angle + (m.crouch ? 0.4 : 1) * (Math.sin(m.cycle * freq + phase * (i)))
const where = { x: m.pos.x + 30 * Math.cos(whereSweep), y: m.pos.y + 30 * Math.sin(whereSweep) }
b.laser(where, {
x: where.x + 5000 * Math.cos(m.angle),
y: where.y + 5000 * Math.sin(m.angle)
}, tech.laserDamage / b.fireCDscale * this.lensDamage);
ctx.globalAlpha = 1
}
}
},
fireWideBeam() {
const drain = tech.laserDrain / b.fireCDscale
if (m.energy < drain) {

View File

@@ -116,7 +116,7 @@ function collisionChecks(event) {
m.damage(dmg); //normal damage
if (tech.isCollisionRealitySwitch && m.alive) {
m.switchWorlds()
m.switchWorlds("Hilbert space")
simulation.trails(90)
simulation.inGameConsole(`simulation.amplitude <span class='color-symbol'>=</span> ${Math.random()}`);
}
@@ -177,8 +177,8 @@ function collisionChecks(event) {
let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x);
Matter.Body.setVelocity(player, { x: player.velocity.x + 8 * Math.cos(angle), y: player.velocity.y + 8 * Math.sin(angle) });
Matter.Body.setVelocity(mob[k], { x: mob[k].velocity.x - 8 * Math.cos(angle), y: mob[k].velocity.y - 8 * Math.sin(angle) });
if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.1 && mob[k].damageReduction > 0) {
m.energy -= 0.1 //* Math.max(m.maxEnergy, m.energy) //0.33 * m.energy
if (tech.isAnnihilation && !mob[k].shield && !mob[k].isShielded && !mob[k].isBoss && mob[k].isDropPowerUp && m.energy > 0.08 && mob[k].damageReduction > 0) {
m.energy -= 0.08 //* Math.max(m.maxEnergy, m.energy) //0.33 * m.energy
if (m.immuneCycle === m.cycle + m.collisionImmuneCycles) m.immuneCycle = 0; //player doesn't go immune to collision damage
mob[k].death();
simulation.drawList.push({ //add dmg to draw queue

View File

@@ -1,5 +1,14 @@
"use strict";
//list of the recent github hashes, shortened to the first 7 digits of the full hash.
//the last element of the array is the most recent commit
// const commitHashes = ['6472d6d', 'c8bf77d', 'eb8f4b0', 'f556371', '74f569b', 'c9f355b', '6814c10', '9402cf2', 'f8b4b6f', '82c0ea8', 'f9849d4', 'd00a94a', '3654198', '9bcf4d3', 'eecf763', 'be109bb', 'e2bf9aa', '3ea8bfd', 'c614451', '1752453', '34e05c7', '07af7a7', '2e76b5c', '1b23dec', '0b728fb', 'e6e5058', '4f87444', 'e418b93', 'b3fa1bf', '09c9e93', 'd8e978f', 'da559f4', '1d4b0c4', '4415942', '6cd2502', '8a211e8', '3d423a5', '4933ef5', '77cafe3', 'bffaeed', '99bd1c8', '8a3ac11', 'bf5f866', 'b14f2c1', 'ff613dc', '1129b9d', '3844d00', 'e9d2262', 'ce74f42', 'ad33cf6', '2d12f1d', 'c47d860', '4e6acdd', '778a2c9', '68f9269', '17f65cf', 'b5e4b0d', '38d9931', '64f2a9f', '64c81cd', '254ec00', '38ef45a', '1728b53', 'fde3a58', '6c3d97a', '951806d', '2b99e59', '3ce6bec', '773ee5c', '4c6b480', 'a1164ed', '507b060', '63bfaba', 'eabd146', '438c166', '1903b9e', '5e12cea', 'f43a5e3', '022e2fa', '20f9b79', 'fc70dfe', '5eae070', '8dacb02', '52046ca', '220a6b4', 'ebd2274', 'cea1c64', 'a47ef97', 'a8c6c0e', '9c2c9be', '8bb8222', '1fde74d', 'f1a6713', '97c5509', '1966173', '2daeae1', '1040d1f', 'c9a5ab9', '77e484c', 'b2426cd']
// const lastShortHash = 'b2426cd'
//Landgreen needs to update the commitHashes array with the most recent commit hash on each new upload, but the array will always be missing the current hash since it is generated with each new commit
//write code to check the 2nd most recent hash and see if it match an element in the commitHashes array. Use that to calculate how many commits have been made since the last update
//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);
@@ -13,7 +22,9 @@ Math.hash = s => {
// document.getElementById("seed").placeholder = Math.initialSeed = Math.floor(Date.now() % 100000) //random every time: just the time in milliseconds UTC
window.addEventListener('error', error => {
simulation.inGameConsole(`<strong style='color:red;'>ERROR:</strong> ${error.message} <u>${error.filename}:${error.lineno}</u>`)
// simulation.inGameConsole(`<strong style='color:red;'>ERROR:</strong> ${error.message} <u>${error.filename}:${error.lineno}</u>`)
simulation.inGameConsole(`<strong style='color:red;'>ERROR:</strong> ${(error.stack && error.stack.replace(/\n/g, "<br>")) || (error.message + ` <u>${error.filename}:${error.lineno}</u>`)}`);
});
document.getElementById("seed").placeholder = Math.initialSeed = String(Math.floor(Date.now() % 100000))
@@ -26,11 +37,11 @@ Math.seededRandom = function (min = 0, max = 1) { // in order to work 'Math.seed
// console.log(Math.seed)
function shuffle(array) {
function seededShuffle(array) {
var currentIndex = array.length,
temporaryValue,
randomIndex;
// While there remain elements to shuffle...
// While there remain elements
while (0 !== currentIndex) {
// Pick a remaining element...
// randomIndex = Math.floor(Math.random() * currentIndex);
@@ -495,7 +506,7 @@ const build = {
<span style="float: right;"><strong class='color-d'>level</strong> ${((m.dmgScale)).toPrecision(4)}x</span>
<br><strong class='color-defense'>damage taken</strong> ${(m.defense()).toPrecision(4)}x
<span style="float: right;"><strong class='color-defense'>level</strong> ${(simulation.dmgScale).toPrecision(4)}x</span>
<br><strong class='color-h'>health</strong> (${(m.health * 100).toFixed(0)} / ${(m.maxHealth * 100).toFixed(0)})
<br><strong class='color-h'>health</strong> (${level.isHideHealth ? "null" : (m.health * 100).toFixed(0)} / ${(m.maxHealth * 100).toFixed(0)})
<span style="float: right;">${powerUps.research.count} ${powerUps.orb.research()}</span>
<br><strong class='color-f'>energy</strong> (${(m.energy * 100).toFixed(0)} / ${(m.maxEnergy * 100).toFixed(0)}) + (${(m.fieldRegen * 6000 * level.isReducedRegen).toFixed(0)}/s)
<span style="float: right;">${tech.totalCount} ${powerUps.orb.tech()}</span>
@@ -512,7 +523,7 @@ ${botText}
<span style="float: right;">mouse (${simulation.mouseInGame.x.toFixed(0)}, ${simulation.mouseInGame.y.toFixed(0)})</span>
<br>cycles ${m.cycle}
<span style="float: right;">velocity (${player.velocity.x.toFixed(2)}, ${player.velocity.y.toFixed(2)})</span>
<br>mobs ${mob.length} (${spawn.pickList[0]}, ${spawn.pickList[0]})
<br>mobs ${mob.length} (${spawn.pickList[0]}, ${spawn.pickList[1]})
<span style="float: right;">blocks ${body.length}</span>
<br>bullets ${bullet.length}
<span style="float: right;">power ups ${powerUp.length}</span>
@@ -540,7 +551,7 @@ ${simulation.difficultyMode > 4 ? `<details id="constraints-details" style="padd
<details id = "console-log-details" style="padding: 0 8px;">
<summary>console log</summary>
<div class="pause-details">
<div class="pause-grid-module" style="background-color: rgba(255,255,255,0.3);font-size: 0.8em;">${document.getElementById("text-log").innerHTML}</div>
<div class="pause-grid-module" style=" background-color: #e2e9ec;font-size: 0.8em;">${document.getElementById("text-log").innerHTML}</div>
</div>
</details>
</div>`
@@ -641,7 +652,7 @@ ${simulation.difficultyMode > 4 ? `<details id="constraints-details" style="padd
}
}
document.getElementById("sort-input").addEventListener('keydown', pressEnterSort);
requestAnimationFrame(() => { document.getElementById("sort-input").focus(); });
// requestAnimationFrame(() => { document.getElementById("sort-input").focus(); });
},
sortTech(find, isExperiment = false) {
const sortKeyword = (a, b) => {
@@ -728,6 +739,8 @@ ${simulation.difficultyMode > 4 ? `<details id="constraints-details" style="padd
});
} else if (find === 'damage') {
tech.tech.sort(sortKeyword);
} else if (find === 'damage taken') {
tech.tech.sort(sortKeyword);
} else if (find === 'defense') {
tech.tech.sort(sortKeyword);
} else if (find === 'energy') {
@@ -952,8 +965,8 @@ ${simulation.difficultyMode > 4 ? `<details id="constraints-details" style="padd
<button onclick="build.sortTech('fieldtech', true)" class='sort-button'>${powerUps.orb.fieldTech()}</button>
<button onclick="build.sortTech('damage', true)" class='sort-button'><strong class='color-d'>damage</strong></button>
<button onclick="build.sortTech('damage taken', true)" class='sort-button'><strong style="letter-spacing: 1px;font-weight: 100;">dmg taken</strong></button>
<button onclick="build.sortTech('heal')" class='sort-button'><strong class='color-h'>heal</strong></button>
<button onclick="build.sortTech('energy')" class='sort-button'><strong class='color-f'>energy</strong></button>
<button onclick="build.sortTech('heal', true)" class='sort-button'><strong class='color-h'>heal</strong></button>
<button onclick="build.sortTech('energy', true)" class='sort-button'><strong class='color-f'>energy</strong></button>
<input type="search" id="sort-input" style="width: 7.5em;font-size: 0.6em;color:#000;" placeholder="sort by" />
<button onclick="build.sortTech('input', true)" class='sort-button' style="border-radius: 0em;border: 1.5px #000 solid;font-size: 0.6em;" value="damage">sort</button>
</div>
@@ -1064,8 +1077,7 @@ ${simulation.difficultyMode > 4 ? `<details id="constraints-details" style="padd
b.activeGun = null;
b.inventoryGun = 0;
simulation.makeGunHUD();
tech.setupAllTech();
m.resetSkin();
tech.resetAllTech();
build.populateGrid();
document.getElementById("field-0").classList.add("build-field-selected");
document.getElementById("experiment-grid").style.display = "grid"
@@ -1166,12 +1178,14 @@ ${simulation.difficultyMode > 4 ? `<details id="constraints-details" style="padd
function openExperimentMenu() {
document.getElementById("experiment-button").style.display = "none";
document.getElementById("training-button").style.display = "none";
document.getElementById("start-button").style.display = "none";
const el = document.getElementById("experiment-grid")
el.style.display = "grid"
document.body.style.overflowY = "scroll";
document.body.style.overflowX = "hidden";
document.getElementById("info").style.display = 'none'
build.reset();
}
//record settings so they can be reproduced in the experimental menu
@@ -1201,6 +1215,8 @@ const input = {
left: false,
right: false,
isPauseKeyReady: true,
// isMouseInside: true,
// lastDown: null,
key: {
fire: "KeyF",
field: "Space",
@@ -1375,6 +1391,7 @@ window.addEventListener("keyup", function (event) {
});
window.addEventListener("keydown", function (event) {
// input.lastDown = event.code
// console.log(event.code)
switch (event.code) {
case input.key.right:
@@ -1414,11 +1431,13 @@ window.addEventListener("keydown", function (event) {
build.pauseGrid()
} else if (simulation.paused) {
build.unPauseGrid()
simulation.paused = false;
// level.levelAnnounce();
document.body.style.cursor = "none";
requestAnimationFrame(cycle);
if (document.activeElement !== document.getElementById('sort-input')) {
build.unPauseGrid()
simulation.paused = false;
// level.levelAnnounce();
document.body.style.cursor = "none";
requestAnimationFrame(cycle);
}
} else { //if (!tech.isNoDraftPause)
simulation.paused = true;
build.pauseGrid()
@@ -1540,7 +1559,7 @@ window.addEventListener("keydown", function (event) {
}
break
}
if (b.inventory.length > 1 && !simulation.testing && !tech.isGunCycle) {
if (b.inventory.length > 1 && !simulation.testing && !(tech.isGunChoice || tech.isGunCycle)) {
switch (event.code) {
case "Digit1":
simulation.switchToGunInInventory(0);
@@ -1727,11 +1746,12 @@ document.body.addEventListener("mouseenter", (e) => { //prevents mouse getting s
input.fire = false;
}
if (e.button === 3) {
input.field = true;
} else {
input.field = false;
}
// if (e.button === 3) {
// input.field = true;
// } else {
// input.field = false;
// }
// input.isMouseInside = true
});
document.body.addEventListener("mouseleave", (e) => { //prevents mouse getting stuck when leaving the window
if (e.button === 1) {
@@ -1740,11 +1760,12 @@ document.body.addEventListener("mouseleave", (e) => { //prevents mouse getting s
input.fire = false;
}
if (e.button === 3) {
input.field = true;
} else {
input.field = false;
}
// if (e.button === 3) {
// input.field = true;
// } else {
// input.field = false;
// }
// input.isMouseInside = false
});
document.body.addEventListener("wheel", (e) => {
@@ -1941,13 +1962,41 @@ document.getElementById("updates").addEventListener("toggle", function () {
xhr.open("GET", path, true);
xhr.send();
}
// fetch(`https://api.github.com/repos/landgreen/n-gon/commits?per_page=100`)
// .then(response => {
// if (!response.ok) {
// throw new Error(`GitHub API responded with status ${response.status}`);
// }
// return response.json();
// })
// .then(commits => {
// // console.log(commits.sha)
// const array = []
// commits.forEach(commitData => {
// const shortHash = commitData.sha.substr(0, 7);
// array.push(shortHash)
// });
// console.log(array)
// })
// .catch(error => {
// console.error('Error fetching commits:', error);
// });
let text = `<pre><strong>n-gon</strong>: <a href="https://github.com/landgreen/n-gon/blob/master/todo.txt">todo list</a> and complete <a href="https://github.com/landgreen/n-gon/commits/master">change-log</a><hr>`
document.getElementById("updates-div").innerHTML = text
/// https://api.github.com/repos/landgreen/n-gon/stats/commit_activity
loadJSON('https://api.github.com/repos/landgreen/n-gon/commits',
function (data) {
// console.log(data[0].sha) //unique code for most recent commit
// console.log(data[0].sha, lastShortHash)
// if (data[0].sha.substr(0, 7) === lastShortHash) {
// text += "<br><em>https://github.com/landgreen/n-gon/</em>: hash matches latest version<hr>"
// } else {
// text += "<br><em>https://github.com/landgreen/n-gon/</em>: hash does <strong>not</strong> match latest version<br><hr>"
// }
for (let i = 0, len = 20; i < len; i++) {
text += "<strong>" + data[i].commit.author.date.substr(0, 10) + "</strong> - "; //+ "<br>"
text += data[i].commit.message

File diff suppressed because it is too large Load Diff

View File

@@ -1088,7 +1088,7 @@ const lore = {
() => {
setTimeout(() => {
lore.anand.text("How ever it thinks it can learn, and I think we showed it that nonviolence is an option,")
lore.anand.text("How ever it thinks, it can learn, and I think we showed it that violence isn't the only option,")
}, 1000);
},
() => {

View File

@@ -41,23 +41,15 @@ const mobs = {
ctx.fillRect(x, y, w, h);
ctx.fillStyle = "rgba(255,0,0,0.7)";
ctx.fillRect(x, y, w * mob[i].health, h);
// if (mob[i].isInvulnerable) {
// ctx.strokeStyle = "rgba(255,255,255,1)";
// ctx.lineWidth = 5
// ctx.strokeRect(x, y, w, h);
// }
}
}
},
healthBar() {
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].seePlayer.recall && mob[i].showHealthBar) {
const h = mob[i].radius * 0.3;
const w = mob[i].radius * 2;
const x = mob[i].position.x - w / 2;
const y = mob[i].position.y - w * 0.7;
ctx.fillStyle = "rgba(100, 100, 100, 0.3)";
ctx.fillRect(x, y, w, h);
ctx.fillStyle = "rgba(255,0,0,0.7)";
ctx.fillRect(x, y, w * mob[i].health, h);
}
}
},
healthBar() { },
statusSlow(who, cycles = 60) {
applySlow(who)
//look for mobs near the target
@@ -989,7 +981,7 @@ const mobs = {
},
explode(mass = this.mass) {
if (m.immuneCycle < m.cycle) {
m.damage(Math.min(Math.max(0.02 * Math.sqrt(mass), 0.01), 0.35) * simulation.dmgScale);
m.damage(Math.min(Math.max(0.03 * Math.sqrt(mass), 0.01), 0.4) * simulation.dmgScale);
this.isDropPowerUp = false;
this.death(); //death with no power up or body
}
@@ -1077,7 +1069,11 @@ const mobs = {
if (tech.isFarAwayDmg) dmg *= 1 + Math.sqrt(Math.max(500, Math.min(3000, this.distanceToPlayer())) - 500) * 0.0067 //up to 33% dmg at max range of 3000
dmg *= this.damageReduction
//energy and heal drain should be calculated after damage boosts
if (tech.energySiphon && dmg !== Infinity && this.isDropPowerUp && m.immuneCycle < m.cycle) m.energy += Math.min(this.health, dmg) * tech.energySiphon * level.isReducedRegen
if (tech.energySiphon && this.isDropPowerUp && m.immuneCycle < m.cycle) {
//dmg !== Infinity &&
const regen = Math.min(this.health, dmg) * tech.energySiphon * level.isReducedRegen
if (!isNaN(regen) && regen !== Infinity) m.energy += regen
}
dmg /= Math.sqrt(this.mass)
}
@@ -1137,7 +1133,7 @@ const mobs = {
for (let i = 0; i < mob.length; i++) {
if (Vector.magnitudeSquared(Vector.sub(this.position, mob[i].position)) < 500000 && mob[i].alive) { //700
if (mob[i].health < 1) {
mob[i].health += 0.33 + this.isBoss
mob[i].health += 0.33
if (mob[i].health > 1) mob[i].health = 1
simulation.drawList.push({
x: mob[i].position.x,
@@ -1232,7 +1228,7 @@ const mobs = {
});
}
if (tech.isVerlet && !m.isBodiesAsleep) {
if (tech.isVerlet && !m.isTimeDilated) {
requestAnimationFrame(() => {
simulation.timePlayerSkip(this.isBoss ? 60 : 30)
simulation.loop(); //ending with a wipe and normal loop fixes some very minor graphical issues where things are draw in the wrong locations
@@ -1242,6 +1238,30 @@ const mobs = {
m.energy -= 0.05;
if (m.energy < 0) m.energy = 0
}
if (tech.isRemineralize) {
//reduce mineral percent based on time since last check
const seconds = (simulation.cycle - tech.mineralLastCheck) / 60
tech.mineralLastCheck = simulation.cycle
tech.mineralDamageReduction = 1 - (1 - tech.mineralDamageReduction) * Math.pow(0.9, seconds);
tech.mineralDamage = 1 + (tech.mineralDamage - 1) * Math.pow(0.9, seconds);
//apply mineral damage reduction
tech.mineralDamageReduction *= 0.85
}
if (tech.isDemineralize) {
//reduce mineral percent based on time since last check
const seconds = (simulation.cycle - tech.mineralLastCheck) / 60
tech.mineralLastCheck = simulation.cycle
tech.mineralDamageReduction = 1 - (1 - tech.mineralDamageReduction) * Math.pow(0.9, seconds);
tech.mineralDamage = 1 + (tech.mineralDamage - 1) * Math.pow(0.9, seconds);
//apply mineral damage
tech.mineralDamage *= 1.08
}
powerUps.spawnRandomPowerUp(this.position.x, this.position.y);
m.lastKillCycle = m.cycle; //tracks the last time a kill was made, mostly used in simulation.checks()
mobs.mobDeaths++
@@ -1261,9 +1281,11 @@ const mobs = {
} else {
for (let i = 0; i < amount; i++) b.spore(this.position)
}
} else if (tech.isExplodeMob) {
}
if (tech.isExplodeMob) {
b.explosion(this.position, Math.min(700, Math.sqrt(this.mass + 6) * (30 + 60 * Math.random())))
} else if (tech.nailsDeathMob) {
}
if (tech.nailsDeathMob) {
b.targetedNail(this.position, tech.nailsDeathMob, 39 + 6 * Math.random())
}
if (tech.isBotSpawnerReset) {
@@ -1277,7 +1299,7 @@ const mobs = {
this.leaveBody = false; // no body since it turned into the bot
}
if (tech.isMobDeathImmunity) {
const immuneTime = 360
const immuneTime = 300
if (m.immuneCycle < m.cycle + immuneTime) m.immuneCycle = m.cycle + immuneTime; //player is immune to damage
}
if (tech.isAddRemoveMaxHealth) {
@@ -1384,7 +1406,7 @@ const mobs = {
//replace dead mob with a regular body
replace(i) {
//if there are too many bodies don't turn into blocks to help performance
if (this.leaveBody && body.length < mobs.maxMobBody && this.mass < 200 && this.radius > 18) {
if (this.leaveBody && body.length < mobs.maxMobBody && this.mass < 200 && this.mass > 2 && this.radius > 18) {
let v = Matter.Vertices.hull(Matter.Vertices.clockwiseSort(this.vertices)) //might help with vertex collision issue, not sure
if (v.length > 5 && body.length < 35 && Math.random() < 0.25) {
const cutPoint = 3 + Math.floor((v.length - 6) * Math.random()) //Math.floor(v.length / 2)
@@ -1397,6 +1419,8 @@ const mobs = {
body[len].collisionFilter.category = cat.body;
body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet;
body[len].classType = "body";
body[len].frictionAir = 0.001
body[len].friction = 0.05
Composite.add(engine.world, body[len]); //add to world
const len2 = body.length;
@@ -1406,6 +1430,8 @@ const mobs = {
body[len2].collisionFilter.category = cat.body;
body[len2].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet;
body[len2].classType = "body";
body[len2].frictionAir = 0.001
body[len2].friction = 0.05
Composite.add(engine.world, body[len2]); //add to world
//large mobs shrink so they don't block paths
@@ -1429,8 +1455,9 @@ const mobs = {
body[len].collisionFilter.category = cat.body;
body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet;
body[len].classType = "body";
body[len].frictionAir = 0.001
body[len].friction = 0.05
Composite.add(engine.world, body[len]); //add to world
//large mobs shrink so they don't block paths
if (body[len].mass > 9) {
const massLimit = 7 + 4 * Math.random()

File diff suppressed because it is too large Load Diff

View File

@@ -212,7 +212,7 @@ const powerUps = {
dupExplode() {
for (let i = 0, len = powerUp.length; i < len; ++i) {
if (powerUp[i].isDuplicated) {
if (Math.random() < 0.003 && !m.isBodiesAsleep) { // (1-0.003)^240 = chance to be removed after 4 seconds, 240 = 4 seconds * 60 cycles per second
if (Math.random() < 0.003 && !m.isTimeDilated) { // (1-0.003)^240 = chance to be removed after 4 seconds, 240 = 4 seconds * 60 cycles per second
b.explosion(powerUp[i].position, 175 + (11 + 3 * Math.random()) * powerUp[i].size);
if (powerUp[i]) {
Matter.Composite.remove(engine.world, powerUp[i]);
@@ -256,6 +256,8 @@ const powerUps = {
powerUps.endDraft(type);
},
showDraft() {
simulation.isChoosing = true; //stops p from un pausing on key down
//disable clicking for 1/2 a second to prevent mistake clicks
document.getElementById("choose-grid").style.pointerEvents = "none";
document.body.style.cursor = "none";
@@ -264,7 +266,6 @@ const powerUps = {
document.getElementById("choose-grid").style.pointerEvents = "auto";
document.getElementById("choose-grid").style.transitionDuration = "0s";
}, 400);
simulation.isChoosing = true; //stops p from un pausing on key down
if (!simulation.paused) {
if (tech.isNoDraftPause || level.isNoPause) {
@@ -285,7 +286,7 @@ const powerUps = {
endDraft(type, isCanceled = false) { //type should be a gun, tech, or field
if (isCanceled) {
if (tech.isCancelDuplication) {
const value = 0.05
const value = 0.06
tech.duplication += value
simulation.inGameConsole(`tech.duplicationChance() <span class='color-symbol'>+=</span> ${value}`)
simulation.circleFlare(value);
@@ -708,7 +709,7 @@ const powerUps = {
if (amount !== 0) powerUps.research.count += amount
if (tech.isRerollBots && !this.isMakingBots) {
let cycle = () => {
const cost = 2 + Math.floor(0.25 * b.totalBots())
const cost = 2 + Math.floor(b.totalBots() / 3)
if (m.alive && powerUps.research.count >= cost) {
requestAnimationFrame(cycle);
this.isMakingBots = true
@@ -762,7 +763,7 @@ const powerUps = {
}
powerUps.research.currentRerollCount++
if (tech.isResearchReality) {
m.switchWorlds()
m.switchWorlds("Ψ(t) collapse")
simulation.trails()
simulation.inGameConsole(`simulation.amplitude <span class='color-symbol'>=</span> ${Math.random()}`);
}
@@ -785,7 +786,7 @@ const powerUps = {
m.addHealth(heal);
if (healOutput > 0) simulation.inGameConsole(`<div class="circle-grid heal"></div> &nbsp; <span class='color-var'>m</span>.health <span class='color-symbol'>+=</span> ${(healOutput).toFixed(3)}`) // <br>${m.health.toFixed(3)}
if (tech.isOverHeal && overHeal > 0) { //tech quenching
tech.extraMaxHealth += 0.4 * overHeal //increase max health
tech.extraMaxHealth += 0.5 * overHeal //increase max health
m.setMaxHealth();
simulation.inGameConsole(`<div class="circle-grid heal"></div> &nbsp; <span class='color-var'>m</span>.maxHealth <span class='color-symbol'>+=</span> ${(0.3 * overHeal).toFixed(3)}`)
simulation.drawList.push({ //add dmg to draw queue
@@ -812,7 +813,7 @@ const powerUps = {
// color: simulation.mobDmgColor,
// time: simulation.drawTime
// });
} else if (overHeal > 0.13) { //if leftover heals spawn a new spammer heal power up
} else if (overHeal > 0.2) { //if leftover heals spawn a new spammer heal power up
requestAnimationFrame(() => {
powerUps.directSpawn(this.position.x, this.position.y, "heal", true, Math.min(1, overHeal) * 40 * (simulation.healScale ** 0.25))// directSpawn(x, y, name, moving = true, mode = null, size = powerUps[name].size()) {
});
@@ -883,7 +884,7 @@ const powerUps = {
const couplingExtraAmmo = (m.fieldMode === 10 || m.fieldMode === 0) ? 1 + 0.04 * m.coupling : 1
if (b.inventory.length > 0) {
powerUps.animatePowerUpGrab('rgba(68, 102, 119,0.25)')
if (tech.isAmmoForGun && b.activeGun !== null) { //give extra ammo to one gun only with tech logistics
if (tech.isAmmoForGun && (b.activeGun !== null && b.activeGun !== undefined)) { //give extra ammo to one gun only with tech logistics
const name = b.guns[b.activeGun]
if (name.ammo !== Infinity) {
if (tech.ammoCap) {
@@ -909,7 +910,7 @@ const powerUps = {
}
},
cancelText(type) {
if (tech.isSuperDeterminism) {
if (tech.isSuperDeterminism || type === "constraint") {
return `<div></div>`
} else if (tech.isCancelTech && tech.cancelTechCount === 0) {
return `<div class='cancel-card sticky' onclick='powerUps.endDraft("${type}",true)' style="width: 115px;"><span class="color-randomize">randomize</span></div>`
@@ -940,7 +941,9 @@ const powerUps = {
},
researchAndCancelText(type) {
let text = `<div class='research-cancel'>`
if (type === "entanglement") {
if (type === "constraint") {
return
} else if (type === "entanglement") {
text += `<span class='research-card entanglement flipX' style="width: 275px;" onclick='powerUps.endDraft("${type}",true)'><span style="letter-spacing: 6px;">entanglement</span></span>`
} else if (tech.isJunkResearch && powerUps.research.currentRerollCount < 2) {
text += `<span onclick="powerUps.research.use('${type}')" class='research-card' style="width: 275px;float: left;">` // style = "margin-left: 192px; margin-right: -192px;"
@@ -1008,6 +1011,12 @@ const powerUps = {
return text
},
hideStyle: `style="height:auto; border: none; background-color: transparent;"`,
constraintText(choose, click) {
return `<div class="choose-grid-module card-background" onclick="${click}" onauxclick="${click}"${powerUps.hideStyle}>
<div class="card-text">
<div class="grid-title"><div class="circle-grid field"></div> &nbsp; ${m.fieldUpgrades[choose].name}</div>
${m.fieldUpgrades[choose].description}</div></div>`
},
gunText(choose, click) {
const style = localSettings.isHideImages ? powerUps.hideStyle : `style="background-image: url('img/gun/${b.guns[choose].name}.webp');"`
return `<div class="choose-grid-module card-background" onclick="${click}" onauxclick="${click}" ${style}>
@@ -1129,7 +1138,7 @@ const powerUps = {
}
// console.log(options.length)
if (options.length > 0 || !tech.isSuperDeterminism) {
let totalChoices = 2 + tech.extraChoices + 3 * (m.fieldMode === 8) - level.fewerChoices
let totalChoices = 2 + tech.extraChoices + (tech.isInPilot ? 1 : 3) * (m.fieldMode === 8) - level.fewerChoices
if (tech.isCancelTech && tech.cancelTechCount === 1) {
totalChoices *= 3
tech.cancelTechCount++
@@ -1196,7 +1205,7 @@ const powerUps = {
for (let i = 1; i < m.fieldUpgrades.length; i++) { //skip field emitter
if (i !== m.fieldMode) options.push(i);
}
let totalChoices = 2 + tech.extraChoices + 3 * (m.fieldMode === 8) - level.fewerChoices
let totalChoices = 2 + tech.extraChoices + (tech.isInPilot ? 1 : 3) * (m.fieldMode === 8) - level.fewerChoices
if (tech.isCancelTech && tech.cancelTechCount === 1) {
totalChoices *= 3
tech.cancelTechCount++
@@ -1276,7 +1285,7 @@ const powerUps = {
}
}
//set total choices
let totalChoices = 3 + tech.extraChoices + 3 * (m.fieldMode === 8) - level.fewerChoices
let totalChoices = 3 + tech.extraChoices + (tech.isInPilot ? 1 : 3) * (m.fieldMode === 8) - level.fewerChoices
if (tech.isCancelTech && tech.cancelTechCount === 1) {
totalChoices *= 3
tech.cancelTechCount++
@@ -1607,6 +1616,8 @@ const powerUps = {
}
}
}
powerUps.spawn(x + 25, y - 25, "ammo", false);
if (simulation.difficultyMode > 5) powerUps.spawn(x - 25, y - 50, "ammo", false);
if (tech.isAddRemoveMaxHealth) {
powerUps.spawn(x + 20, y, "tech", false)
powerUps.spawn(x - 20, y, "research", false)
@@ -1618,7 +1629,7 @@ const powerUps = {
powerUps.spawn(x, y - 40, "heal", false)
}
if (tech.isResearchReality) powerUps.spawnDelay("research", 6)
if (tech.isBanish) powerUps.spawnDelay("research", 2)
if (tech.isBanish) powerUps.spawnDelay("research", 3)
if (tech.isCouplingNoHit) powerUps.spawnDelay("coupling", 9)
// if (tech.isRerollDamage) powerUps.spawnDelay("research", 1)
}
@@ -1642,6 +1653,7 @@ const powerUps = {
if (b.inventory.length === 0) {
powerUps.spawn(x, y, "gun", false); //first gun
} else if (tech.totalCount === 0) { //first tech
powerUps.spawn(x - 22, y - 50, "ammo", false); //some ammo
powerUps.spawn(x, y, "tech", false);
} else if (b.inventory.length === 1) { //second gun or extra ammo
if (Math.random() < 0.4) {
@@ -1735,9 +1747,10 @@ const powerUps = {
}
//count big power ups and small power ups
let options = ["heal", "research", "ammo"]
let options = ["heal", "research", tech.isBoostReplaceAmmo ? "boost" : "ammo"]
if (m.coupling) options.push("coupling")
if (tech.isBoostPowerUps) options.push("boost")
let bigIndexes = []
let smallIndexes = []
for (let i = 0; i < powerUp.length; i++) {

View File

@@ -2,152 +2,152 @@
//*********************************************************************
const simulation = {
loop() { }, //main game loop, gets set to normal or testing loop
normalLoop() {
try {
simulation.gravity();
Engine.update(engine, simulation.delta);
simulation.wipe();
simulation.textLog();
if (m.onGround) {
m.groundControl()
} else {
m.airControl()
}
m.move();
m.look();
simulation.camera();
level.custom();
powerUps.do();
mobs.draw();
simulation.draw.cons();
simulation.draw.body();
if (!m.isBodiesAsleep) mobs.loop();
mobs.healthBar();
m.draw();
m.hold();
level.customTopLayer();
simulation.draw.drawMapPath();
b.fire();
b.bulletRemove();
b.bulletDraw();
if (!m.isBodiesAsleep) b.bulletDo();
simulation.drawCircle();
simulation.runEphemera();
ctx.restore();
} catch (error) {
simulation.inGameConsole(`<strong style='color:red;'>ERROR:</strong> ${(error.stack && error.stack.replace(/\n/g, "<br>")) || (error.message + ` <u>${error.filename}:${error.lineno}</u>`)}`);
} finally {
simulation.drawCursor();
}
},
testingLoop() {
try {
simulation.gravity();
Engine.update(engine, simulation.delta);
simulation.wipe();
simulation.textLog();
if (m.onGround) {
m.groundControl()
} else {
m.airControl()
}
m.move();
m.look();
simulation.camera();
level.custom();
m.draw();
m.hold();
level.customTopLayer();
simulation.draw.wireFrame();
if (input.fire && m.fireCDcycle < m.cycle) {
m.fireCDcycle = m.cycle + 15; //fire cooldown
for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitudeSquared(Vector.sub(mob[i].position, simulation.mouseInGame)) < mob[i].radius * mob[i].radius) {
console.log(mob[i])
}
}
}
simulation.draw.cons();
simulation.draw.testing();
simulation.drawCircle();
simulation.runEphemera();
simulation.constructCycle()
} catch (error) {
simulation.inGameConsole(`<strong style='color:red;'>ERROR:</strong> ${(error.stack && error.stack.replace(/\n/g, "<br>")) || (error.message + ` <u>${error.filename}:${error.lineno}</u>`)}`);
} finally {
ctx.restore();
simulation.testingOutput();
simulation.drawCursor();
}
},
// normalLoop() {
// simulation.gravity();
// Engine.update(engine, simulation.delta);
// simulation.wipe();
// simulation.textLog();
// if (m.onGround) {
// m.groundControl()
// } else {
// m.airControl()
// try {
// simulation.gravity();
// Engine.update(engine, simulation.delta);
// simulation.wipe();
// simulation.textLog();
// if (m.onGround) {
// m.groundControl()
// } else {
// m.airControl()
// }
// m.move();
// m.look();
// simulation.camera();
// level.custom();
// powerUps.do();
// mobs.draw();
// simulation.draw.cons();
// simulation.draw.body();
// if (!m.isTimeDilated) mobs.loop();
// mobs.healthBar();
// m.draw();
// m.hold();
// level.customTopLayer();
// simulation.draw.drawMapPath();
// b.fire();
// b.bulletRemove();
// b.bulletDraw();
// if (!m.isTimeDilated) b.bulletDo();
// simulation.drawCircle();
// simulation.runEphemera();
// ctx.restore();
// } catch (error) {
// simulation.inGameConsole(`<strong style='color:red;'>ERROR:</strong> ${(error.stack && error.stack.replace(/\n/g, "<br>")) || (error.message + ` <u>${error.filename}:${error.lineno}</u>`)}`);
// } finally {
// simulation.drawCursor();
// }
// m.move();
// m.look();
// simulation.camera();
// level.custom();
// powerUps.do();
// mobs.draw();
// simulation.draw.cons();
// simulation.draw.body();
// if (!m.isBodiesAsleep) mobs.loop();
// mobs.healthBar();
// m.draw();
// m.hold();
// level.customTopLayer();
// simulation.draw.drawMapPath();
// b.fire();
// b.bulletRemove();
// b.bulletDraw();
// if (!m.isBodiesAsleep) b.bulletDo();
// simulation.drawCircle();
// simulation.runEphemera();
// ctx.restore();
// simulation.drawCursor();
// },
// testingLoop() {
// simulation.gravity();
// Engine.update(engine, simulation.delta);
// simulation.wipe();
// simulation.textLog();
// if (m.onGround) {
// m.groundControl()
// } else {
// m.airControl()
// }
// m.move();
// m.look();
// simulation.camera();
// level.custom();
// m.draw();
// m.hold();
// level.customTopLayer();
// simulation.draw.wireFrame();
// if (input.fire && m.fireCDcycle < m.cycle) {
// m.fireCDcycle = m.cycle + 15; //fire cooldown
// for (let i = 0, len = mob.length; i < len; i++) {
// if (Vector.magnitudeSquared(Vector.sub(mob[i].position, simulation.mouseInGame)) < mob[i].radius * mob[i].radius) {
// console.log(mob[i])
// try {
// simulation.gravity();
// Engine.update(engine, simulation.delta);
// simulation.wipe();
// simulation.textLog();
// if (m.onGround) {
// m.groundControl()
// } else {
// m.airControl()
// }
// m.move();
// m.look();
// simulation.camera();
// level.custom();
// m.draw();
// m.hold();
// level.customTopLayer();
// simulation.draw.wireFrame();
// if (input.fire && m.fireCDcycle < m.cycle) {
// m.fireCDcycle = m.cycle + 15; //fire cooldown
// for (let i = 0, len = mob.length; i < len; i++) {
// if (Vector.magnitudeSquared(Vector.sub(mob[i].position, simulation.mouseInGame)) < mob[i].radius * mob[i].radius) {
// console.log(mob[i])
// }
// }
// }
// simulation.draw.cons();
// simulation.draw.testing();
// simulation.drawCircle();
// simulation.runEphemera();
// simulation.constructCycle()
// } catch (error) {
// simulation.inGameConsole(`<strong style='color:red;'>ERROR:</strong> ${(error.stack && error.stack.replace(/\n/g, "<br>")) || (error.message + ` <u>${error.filename}:${error.lineno}</u>`)}`);
// } finally {
// ctx.restore();
// simulation.testingOutput();
// simulation.drawCursor();
// }
// simulation.draw.cons();
// simulation.draw.testing();
// simulation.drawCircle();
// simulation.runEphemera();
// simulation.constructCycle()
// ctx.restore();
// simulation.testingOutput();
// simulation.drawCursor();
// },
normalLoop() {
simulation.gravity();
Engine.update(engine, simulation.delta);
simulation.wipe();
simulation.textLog();
if (m.onGround) {
m.groundControl()
} else {
m.airControl()
}
m.move();
m.look();
simulation.camera();
level.custom();
powerUps.do();
mobs.draw();
simulation.draw.cons();
simulation.draw.body();
if (!m.isTimeDilated) mobs.loop();
mobs.healthBar();
m.draw();
m.hold();
level.customTopLayer();
simulation.draw.drawMapPath();
b.fire();
b.bulletRemove();
b.bulletDraw();
if (!m.isTimeDilated) b.bulletDo();
simulation.drawCircle();
simulation.runEphemera();
ctx.restore();
simulation.drawCursor();
},
testingLoop() {
simulation.gravity();
Engine.update(engine, simulation.delta);
simulation.wipe();
simulation.textLog();
if (m.onGround) {
m.groundControl()
} else {
m.airControl()
}
m.move();
m.look();
simulation.camera();
level.custom();
m.draw();
m.hold();
level.customTopLayer();
simulation.draw.wireFrame();
if (input.fire && m.fireCDcycle < m.cycle) {
m.fireCDcycle = m.cycle + 15; //fire cooldown
for (let i = 0, len = mob.length; i < len; i++) {
if (Vector.magnitudeSquared(Vector.sub(mob[i].position, simulation.mouseInGame)) < mob[i].radius * mob[i].radius) {
console.log(mob[i])
}
}
}
simulation.draw.cons();
simulation.draw.testing();
simulation.drawCircle();
simulation.runEphemera();
simulation.constructCycle()
ctx.restore();
simulation.testingOutput();
simulation.drawCursor();
},
isTimeSkipping: false,
timeSkip(cycles = 60) {
simulation.isTimeSkipping = true;
@@ -183,10 +183,10 @@ const simulation = {
Engine.update(engine, simulation.delta);
// level.custom();
// level.customTopLayer();
if (!m.isBodiesAsleep) mobs.loop();
if (!m.isTimeDilated) mobs.loop();
if (m.fieldMode !== 7) m.hold();
b.bulletRemove();
if (!m.isBodiesAsleep) b.bulletDo();
if (!m.isTimeDilated) b.bulletDo();
simulation.runEphemera();
}
simulation.isTimeSkipping = false;
@@ -223,7 +223,7 @@ const simulation = {
// mobs.draw();
// simulation.draw.cons();
// simulation.draw.body();
// if (!m.isBodiesAsleep) {
// if (!m.isTimeDilated) {
// // mobs.loop();
// }
// mobs.healthBar();
@@ -235,7 +235,7 @@ const simulation = {
// b.fire();
// b.bulletRemove();
// b.bulletDraw();
// if (!m.isBodiesAsleep) b.bulletDo();
// if (!m.isTimeDilated) b.bulletDo();
// simulation.drawCircle();
// // simulation.clip();
// ctx.restore();
@@ -425,7 +425,7 @@ const simulation = {
if (simulation.drawList[i].time) {
simulation.drawList[i].time--;
} else {
if (!m.isBodiesAsleep) simulation.drawList.splice(i, 1); //remove when timer runs out
if (!m.isTimeDilated) simulation.drawList.splice(i, 1); //remove when timer runs out
}
}
},
@@ -496,6 +496,32 @@ const simulation = {
}
simulation.boldActiveGunHUD();
},
// updateTechHUD() {
// let text = ""
// for (let i = 0, len = tech.tech.length; i < len; i++) { //add tech
// if (tech.tech[i].isLost) {
// if (text) text += "<br>" //add a new line, but not on the first line
// text += `<span style="text-decoration: line-through;">${tech.tech[i].name}</span>`
// } else if (tech.tech[i].count > 0 && !tech.tech[i].isInstant) {
// if (text) text += "<br>" //add a new line, but not on the first line
// text += `<span id = "${tech.tech[i].name}">${tech.tech[i].name}${tech.tech[i].count > 1 ? ` (${tech.tech[i].count}x)` : ""}</span>`
// // document.getElementById(tech.tech[i].name).style.fontWeight = 'bold';
// // simulation.ephemera.push({
// // name: "bold",
// // count: 180,
// // do() {
// // this.count--
// // if (this.count < 0) {
// // simulation.removeEphemera(this.name)
// // if (document.getElementById(tech.tech[i].name)) document.getElementById(tech.tech[i].name).style.fontWeight = 'normal';
// // }
// // }
// // })
// }
// }
// document.getElementById("right-HUD").innerHTML = text
// },
updateTechHUD() {
let text = ""
for (let i = 0, len = tech.tech.length; i < len; i++) { //add tech
@@ -532,14 +558,14 @@ const simulation = {
}
},
nextGun() {
if (b.inventory.length > 1 && !tech.isGunCycle) {
if (b.inventory.length > 1 && !(tech.isGunCycle || tech.isGunChoice)) {
b.inventoryGun++;
if (b.inventoryGun > b.inventory.length - 1) b.inventoryGun = 0;
simulation.switchGun();
}
},
previousGun() {
if (b.inventory.length > 1 && !tech.isGunCycle) {
if (b.inventory.length > 1 && !(tech.isGunCycle || tech.isGunChoice)) {
b.inventoryGun--;
if (b.inventoryGun < 0) b.inventoryGun = b.inventory.length - 1;
simulation.switchGun();
@@ -712,7 +738,7 @@ const simulation = {
mouseMove = mouseMoveDefault
}
},
translatePlayerAndCamera(where) {
translatePlayerAndCamera(where, isTranslateBots = true) {
//infinite falling. teleport to sky after falling
const before = { x: player.position.x, y: player.position.y, }
Matter.Body.setPosition(player, { x: where.x, y: where.y });
@@ -728,20 +754,21 @@ const simulation = {
//is there a reason to update m.pos here?
// m.pos.x = player.position.x;
// m.pos.y = playerBody.position.y - m.yOff;
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
if (Vector.magnitudeSquared(Vector.sub(bullet[i].position, player.position)) > 1000000) { //far away bots teleport to player
Matter.Body.setPosition(bullet[i], Vector.add(player.position, { x: 250 * (Math.random() - 0.5), y: 250 * (Math.random() - 0.5) }));
Matter.Body.setVelocity(bullet[i], { x: 0, y: 0 });
} else { //close bots maintain relative distance to player on teleport
Matter.Body.setPosition(bullet[i], Vector.sub(bullet[i].position, change));
if (isTranslateBots) {
for (let i = 0; i < bullet.length; i++) {
if (bullet[i].botType) {
if (Vector.magnitudeSquared(Vector.sub(bullet[i].position, player.position)) > 1000000) { //far away bots teleport to player
Matter.Body.setPosition(bullet[i], Vector.add(player.position, { x: 250 * (Math.random() - 0.5), y: 250 * (Math.random() - 0.5) }));
Matter.Body.setVelocity(bullet[i], { x: 0, y: 0 });
} else { //close bots maintain relative distance to player on teleport
Matter.Body.setPosition(bullet[i], Vector.sub(bullet[i].position, change));
}
}
}
}
},
setupCamera() { //makes the camera not scroll after changing locations
// //only works if velocity is zero
// only works if velocity is zero
m.pos.x = player.position.x;
m.pos.y = playerBody.position.y - m.yOff;
const scale = 0.8;
@@ -767,6 +794,20 @@ const simulation = {
simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX;
simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY;
},
//for moving camera away from player
setCameraPosition(x, y, zoom = 1) {
ctx.restore();
ctx.save();
ctx.translate(canvas.width2, canvas.height2); //center
ctx.scale(zoom, zoom); //zoom in once centered
ctx.translate(- x, - y); //center
// ctx.scale(simulation.zoom / simulation.edgeZoomOutSmooth, simulation.zoom / simulation.edgeZoomOutSmooth); //zoom in once centered
// ctx.translate(-canvas.width2, -canvas.height2); //translate
//calculate in game mouse position by undoing the zoom and translations
simulation.mouseInGame.x = (simulation.mouse.x - canvas.width2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.width2 - m.transX;
simulation.mouseInGame.y = (simulation.mouse.y - canvas.height2) / simulation.zoom * simulation.edgeZoomOutSmooth + canvas.height2 - m.transY;
},
cameraNoLook() {
ctx.save();
ctx.translate(canvas.width2, canvas.height2); //center
@@ -836,7 +877,7 @@ const simulation = {
bodies[i].force.y += bodies[i].mass * magnitude;
}
}
if (!m.isBodiesAsleep) {
if (!m.isTimeDilated) {
addGravity(powerUp, simulation.g);
addGravity(body, simulation.g);
}
@@ -864,6 +905,8 @@ const simulation = {
document.getElementById("experiment-button").style.opacity = "0";
document.getElementById("training-button").style.display = "inline"
document.getElementById("training-button").style.opacity = "0";
document.getElementById("start-button").style.display = "inline"
document.getElementById("start-button").style.opacity = "0";
document.getElementById("experiment-grid").style.display = "none"
document.getElementById("pause-grid-left").style.display = "none"
document.getElementById("pause-grid-right").style.display = "none"
@@ -877,6 +920,7 @@ const simulation = {
setTimeout(() => {
document.getElementById("experiment-button").style.opacity = "1";
document.getElementById("training-button").style.opacity = "1";
document.getElementById("start-button").style.opacity = "1";
document.getElementById("info").style.opacity = "1";
document.getElementById("splash").style.opacity = "1";
}, 200);
@@ -903,6 +947,7 @@ const simulation = {
document.getElementById("info").style.display = "none";
document.getElementById("experiment-button").style.display = "none";
document.getElementById("training-button").style.display = "none";
document.getElementById("start-button").style.display = "none";
// document.getElementById("experiment-button").style.opacity = "0";
document.getElementById("splash").onclick = null; //removes the onclick effect so the function only runs once
document.getElementById("splash").style.display = "none"; //hides the element that spawned the function
@@ -942,14 +987,13 @@ const simulation = {
} else {
Composite.add(engine.world, [player])
}
shuffle(level.constraint)
seededShuffle(level.constraint)
level.populateLevels()
input.endKeySensing();
simulation.ephemera = []
powerUps.powerUpStorage = []
tech.setupAllTech(); //sets tech to default values
tech.resetAllTech(); //sets tech to default values
b.resetAllGuns();
tech.duplication = 0;
for (i = 0, len = b.guns.length; i < len; i++) { //find which gun
if (b.guns[i].name === "laser") b.guns[i].chooseFireMethod()
if (b.guns[i].name === "nail gun") b.guns[i].chooseFireMethod()
@@ -957,15 +1001,7 @@ const simulation = {
if (b.guns[i].name === "harpoon") b.guns[i].chooseFireMethod()
if (b.guns[i].name === "foam") b.guns[i].chooseFireMethod()
}
tech.dynamoBotCount = 0;
tech.nailBotCount = 0;
tech.laserBotCount = 0;
tech.orbitBotCount = 0;
tech.foamBotCount = 0;
tech.soundBotCount = 0;
tech.boomBotCount = 0;
tech.plasmaBotCount = 0;
tech.missileBotCount = 0;
b.zeroBotCount()
m.isSwitchingWorlds = false
simulation.isChoosing = false;
@@ -996,7 +1032,7 @@ const simulation = {
simulation.makeGunHUD();
simulation.lastLogTime = 0;
mobs.mobDeaths = 0
level.isFlipped = false
level.onLevel = 0;
level.levelsCleared = 0;
level.updateDifficulty()
@@ -1043,12 +1079,12 @@ const simulation = {
simulation.ephemera.push({
name: "dmgDefBars", count: 0, do() {
if (!(m.cycle % 15)) { //4 times a second
const defense = m.defense() //update defense bar
const defense = m.defense() //* simulation.dmgScale //update defense bar
if (m.lastCalculatedDefense !== defense) {
document.getElementById("defense-bar").style.width = Math.floor(300 * m.maxHealth * (1 - defense)) + "px";
m.lastCalculatedDefense = defense
}
const damage = tech.damageFromTech() //update damage bar
const damage = tech.damageFromTech() //* m.dmgScale //update damage bar
if (m.lastCalculatedDamage !== damage) {
document.getElementById("damage-bar").style.height = Math.floor((Math.atan(0.25 * damage - 0.25) + 0.25) * 0.53 * canvas.height) + "px";
m.lastCalculatedDamage = damage

View File

@@ -1,6 +1,6 @@
//main object for spawning things in a level
const spawn = {
nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture"],
nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "growBossCulture", "snakeBoss"],
// other bosses: suckerBoss, laserBoss, tetherBoss, bounceBoss, sprayBoss, mineBoss, hopMotherBoss //these need a particular level to work so they are not included in the random pool
randomBossList: [
"orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss",
@@ -42,6 +42,7 @@ const spawn = {
spawn.pickList.splice(0, 1);
const push = spawn.mobTypeSpawnOrder[spawn.mobTypeSpawnIndex++ % spawn.mobTypeSpawnOrder.length]
spawn.pickList.push(push);
// if (spawn.mobTypeSpawnIndex > spawn.mobTypeSpawnOrder.length) spawn.mobTypeSpawnIndex = 0
//each level has 2 mobs: one new mob and one from the last level
// spawn.pickList.splice(0, 1);
@@ -113,11 +114,11 @@ const spawn = {
}
}
},
secondaryBossChance(x, y) {
secondaryBossChance(x, y, options = []) {
if (simulation.difficultyMode > 2 && level.levelsCleared > 1) {
spawn.randomLevelBoss(x, y);
powerUps.directSpawn(x - 30, y, "ammo");
powerUps.directSpawn(x + 30, y, "ammo");
spawn.randomLevelBoss(x, y, options);
powerUps.spawn(x - 30, y, "ammo");
powerUps.spawn(x + 30, y, "ammo");
} else {
return false
}
@@ -194,7 +195,7 @@ const spawn = {
ctx.strokeStyle = "#000"
ctx.lineWidth = 1;
ctx.stroke();
if (tech.isDarkStar && !m.isCloak) { //&& !m.isBodiesAsleep
if (tech.isDarkStar && !m.isCloak) { //&& !m.isTimeDilated
ctx.fillStyle = "rgba(10,0,40,0.4)"
ctx.fill()
//damage mobs
@@ -744,7 +745,7 @@ const spawn = {
// exit() { },
// },
]
shuffle(me.mode); //THIS SHOULD NOT BE COMMENTED OUT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
me.mode.sort(() => Math.random() - 0.5);
me.do = function () {
this.fill = `hsl(${360 * Math.sin(this.cycle * 0.011)},${80 + 20 * Math.sin(this.cycle * 0.004)}%,${60 + 20 * Math.sin(this.cycle * 0.009)}%)`
if (this.health < 1) {
@@ -1014,7 +1015,7 @@ const spawn = {
return
}
}
if (simulation.testing || simulation.difficultyMode > 5) {
if (simulation.testing || simulation.difficultyMode > 6) {
unlockExit()
setTimeout(function () {
simulation.inGameConsole(`level.levels.length <span class='color-symbol'>=</span> <strong>Infinite</strong>`);
@@ -1497,7 +1498,7 @@ const spawn = {
for (let i = 0; i < num; i++) spawn.spawnerBoss(x, y, radius, spawnID)
},
spawnerBoss(x, y, radius, spawnID) {
mobs.spawn(x + Math.random(), y + Math.random(), 4, radius, "rgba(255,60,0,0.3)") //);
mobs.spawn(x + Math.random(), y + Math.random(), 4, radius, "rgba(255,0,70,1)") //);
let me = mob[mob.length - 1];
me.isBoss = true;
@@ -1517,10 +1518,24 @@ const spawn = {
// spawn.shield(me, x, y, 1);
me.onHit = function () { //run this function on hitting player
this.explode();
this.explode(2 * this.mass);
};
me.damageReduction = 0.14
me.doAwake = function () {
//draw aura
ctx.beginPath();
const vertices = this.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.strokeStyle = `rgba(255,0,70,${0.2 + 0.4 * Math.random()})`
ctx.lineWidth = Math.floor(5 + 30 * this.health)
ctx.stroke();
// ctx.strokeStyle = "rgba(255,60,0,0.1)"
// ctx.lineWidth = 70
// ctx.stroke();
// this.fill = `rgba(255,0,70,${0.1 + 0.1 * Math.random()})`
this.alwaysSeePlayer();
this.checkStatus();
this.attraction();
@@ -1545,6 +1560,7 @@ const spawn = {
this.checkStatus();
if (this.seePlayer.recall) {
this.do = this.doAwake
this.fill = `transparent`
//awaken other spawnBosses
for (let i = 0, len = mob.length; i < len; i++) {
if (mob[i].isSpawnBoss && mob[i].spawnID === this.spawnID) mob[i].seePlayer.recall = 1
@@ -1600,7 +1616,7 @@ const spawn = {
me.seePlayerFreq = Math.floor(11 + 7 * Math.random())
me.seeAtDistance2 = 200000 //1400000;
me.stroke = "transparent"
me.collisionFilter.mask = cat.player | cat.bullet //| cat.body //| cat.map //"rgba(255,60,0,0.3)"
me.collisionFilter.mask = cat.player | cat.bullet | cat.body //| cat.map //"rgba(255,60,0,0.3)"
me.buffCount = 0
me.accelMag = 0.00005 //* simulation.accelScale;
@@ -1770,6 +1786,7 @@ const spawn = {
powerUps.spawn(me.position.x, me.position.y, "heal");
powerUps.spawn(me.position.x, me.position.y, "ammo");
powerUps.spawn(me.position.x, me.position.y, "ammo");
powerUps.spawn(me.position.x, me.position.y, "ammo");
} else if (!m.isCloak) {
me.foundPlayer();
}
@@ -2028,7 +2045,7 @@ const spawn = {
// Matter.Body.setStatic(me, true); //make static (disables taking damage)
me.frictionAir = 1
me.damageReduction = 2
me.collisionFilter.mask = cat.bullet //| cat.body
me.collisionFilter.mask = cat.bullet | cat.body
// me.collisionFilter.category = cat.mobBullet;
// me.collisionFilter.mask = cat.bullet | cat.body // | cat.player
me.isMine = true
@@ -2682,32 +2699,37 @@ const spawn = {
this.seePlayerByHistory()
this.invulnerabilityCountDown--
if (this.isInvulnerable) {
ctx.beginPath();
let vertices = this.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
for (let i = 0; i < this.babyList.length; i++) {
if (this.babyList[i].alive) {
let vertices = this.babyList[i].vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
if (this.invulnerabilityCountDown > 90 || this.invulnerabilityCountDown % 20 > 10) {
ctx.beginPath();
let vertices = this.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
for (let i = 0; i < this.babyList.length; i++) {
if (this.babyList[i].alive) {
let vertices = this.babyList[i].vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1; j < vertices.length; j++) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
}
}
ctx.lineWidth = 3 + 0.2 * Math.min(this.invulnerabilityCountDown, 90) + 5 * Math.random()
ctx.strokeStyle = `rgba(255,255,255,${0.4 + 0.4 * Math.random()})`;
ctx.stroke();
}
ctx.lineWidth = 13 + 5 * Math.random();
ctx.strokeStyle = `rgba(255,255,255,${0.5 + 0.2 * Math.random()})`;
ctx.stroke();
if (this.invulnerabilityCountDown < 0) {
this.invulnerabilityCountDown = 110
this.isInvulnerable = false
this.damageReduction = this.startingDamageReduction
for (let i = 0; i < this.babyList.length; i++) {
if (this.babyList[i].alive) this.babyList[i].damageReduction = this.startingDamageReduction
if (this.babyList[i].alive) {
this.babyList[i].isInvulnerable = false
this.babyList[i].damageReduction = this.startingDamageReduction
}
}
}
} else if (this.invulnerabilityCountDown < 0) {
this.invulnerabilityCountDown = 120 + 9 * simulation.difficulty
this.invulnerabilityCountDown = 240 + 5 * simulation.difficulty
this.isInvulnerable = true
if (this.damageReduction) this.startingDamageReduction = this.damageReduction
this.damageReduction = 0
@@ -3088,28 +3110,32 @@ const spawn = {
if (this.seePlayer.yes && dist2 < 4000000) {
const rangeWidth = 2000; //this is sqrt of 4000000 from above if()
//targeting laser will slowly move from the mob to the player's position
this.laserPos = Vector.add(this.laserPos, Vector.mult(Vector.sub(player.position, this.laserPos), 0.1));
this.laserPos = Vector.add(this.laserPos, Vector.mult(Vector.sub(player.position, this.laserPos), 0.03));
let targetDist = Vector.magnitude(Vector.sub(this.laserPos, m.pos));
const r = 12;
ctx.beginPath();
ctx.moveTo(this.position.x, this.position.y);
if (targetDist < r + 16) {
targetDist = r + 10;
//charge at player
const forceMag = this.accelMag * 40 * this.mass;
const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
this.force.x += forceMag * Math.cos(angle);
this.force.y += forceMag * Math.sin(angle);
}
// else {
//high friction if can't lock onto player
// Matter.Body.setVelocity(this, {
// x: this.velocity.x * 0.98,
// y: this.velocity.y * 0.98
// });
// }
if (dist2 > 80000) {
const laserWidth = 0.002;
if (m.immuneCycle < m.cycle) {
m.damage(0.0003 * simulation.dmgScale);
if (m.energy > 0.1) m.energy -= 0.003
}
ctx.beginPath();
ctx.moveTo(this.position.x, this.position.y);
ctx.lineTo(m.pos.x, m.pos.y);
ctx.lineTo(m.pos.x + (Math.random() - 0.5) * 3000, m.pos.y + (Math.random() - 0.5) * 3000);
ctx.lineWidth = 2;
ctx.strokeStyle = "rgb(0,0,255)";
ctx.setLineDash([125 * Math.random(), 125 * Math.random()]);
ctx.stroke();
ctx.setLineDash([]);
ctx.beginPath();
ctx.arc(m.pos.x, m.pos.y, 40, 0, 2 * Math.PI);
ctx.fillStyle = "rgba(0,0,255,0.1)";
ctx.fill();
} else {
const laserWidth = 0.0005;
let laserOffR = Vector.rotateAbout(this.laserPos, (targetDist - r) * laserWidth, this.position);
let sub = Vector.normalise(Vector.sub(laserOffR, this.position));
laserOffR = Vector.add(laserOffR, Vector.mult(sub, rangeWidth));
@@ -3119,7 +3145,7 @@ const spawn = {
sub = Vector.normalise(Vector.sub(laserOffL, this.position));
laserOffL = Vector.add(laserOffL, Vector.mult(sub, rangeWidth));
ctx.lineTo(laserOffL.x, laserOffL.y);
ctx.fillStyle = `rgba(0,0,255,${Math.max(0, 0.3 * r / targetDist)})`
ctx.fillStyle = `rgba(0,0,255,${Math.max(0, 0.6 * r / targetDist)})`
ctx.fill();
}
} else {
@@ -3127,6 +3153,69 @@ const spawn = {
}
}
},
// focuser(x, y, radius = 30 + Math.ceil(Math.random() * 10)) {
// radius = Math.ceil(radius * 0.7);
// mobs.spawn(x, y, 4, radius, "rgb(0,0,255)");
// let me = mob[mob.length - 1];
// Matter.Body.setDensity(me, 0.003); //extra dense //normal is 0.001
// me.restitution = 0;
// me.laserPos = me.position; //required for laserTracking
// me.repulsionRange = 1200000; //squared
// me.accelMag = 0.00009 * simulation.accelScale;
// me.frictionStatic = 0;
// me.friction = 0;
// me.onDamage = function () {
// this.laserPos = this.position;
// };
// spawn.shield(me, x, y);
// me.do = function () {
// this.seePlayerByLookingAt();
// this.checkStatus();
// this.attraction();
// const dist2 = this.distanceToPlayer2();
// //laser Tracking
// if (this.seePlayer.yes && dist2 < 4000000) {
// const rangeWidth = 2000; //this is sqrt of 4000000 from above if()
// //targeting laser will slowly move from the mob to the player's position
// this.laserPos = Vector.add(this.laserPos, Vector.mult(Vector.sub(player.position, this.laserPos), 0.1));
// let targetDist = Vector.magnitude(Vector.sub(this.laserPos, m.pos));
// const r = 12;
// ctx.beginPath();
// ctx.moveTo(this.position.x, this.position.y);
// if (targetDist < r + 16) {
// targetDist = r + 10;
// //charge at player
// const forceMag = this.accelMag * 40 * this.mass;
// const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x);
// this.force.x += forceMag * Math.cos(angle);
// this.force.y += forceMag * Math.sin(angle);
// }
// // else {
// //high friction if can't lock onto player
// // Matter.Body.setVelocity(this, {
// // x: this.velocity.x * 0.98,
// // y: this.velocity.y * 0.98
// // });
// // }
// if (dist2 > 80000) {
// const laserWidth = 0.002;
// let laserOffR = Vector.rotateAbout(this.laserPos, (targetDist - r) * laserWidth, this.position);
// let sub = Vector.normalise(Vector.sub(laserOffR, this.position));
// laserOffR = Vector.add(laserOffR, Vector.mult(sub, rangeWidth));
// ctx.lineTo(laserOffR.x, laserOffR.y);
// let laserOffL = Vector.rotateAbout(this.laserPos, (targetDist - r) * -laserWidth, this.position);
// sub = Vector.normalise(Vector.sub(laserOffL, this.position));
// laserOffL = Vector.add(laserOffL, Vector.mult(sub, rangeWidth));
// ctx.lineTo(laserOffL.x, laserOffL.y);
// ctx.fillStyle = `rgba(0,0,255,${Math.max(0, 0.3 * r / targetDist)})`
// ctx.fill();
// }
// } else {
// this.laserPos = this.position;
// }
// }
// },
flutter(x, y, radius = 20 + 6 * Math.random()) {
mobs.spawn(x, y, 7, radius, '#16576b');
let me = mob[mob.length - 1];
@@ -3850,13 +3939,13 @@ const spawn = {
}
me.frictionStatic = 0;
me.friction = 0;
me.memory = 240
me.seePlayerFreq = 55
me.memory = 900;
me.seePlayerFreq = 41
me.delay = 5 + 2 * simulation.CDScale;//8 + 3 * simulation.CDScale;
me.nextBlinkCycle = me.delay;
me.JumpDistance = 0//set in redMode()
// spawn.shield(me, x, y, 1);
me.collisionFilter.mask = cat.bullet | cat.map //| cat.body //cat.player |
me.collisionFilter.mask = cat.bullet | cat.map | cat.body //cat.player |
me.powerUpNames = []
me.redMode = function () {
this.color = `rgba(255,0,200,`
@@ -3895,7 +3984,7 @@ const spawn = {
if (this.health < this.nextHealthThreshold) {
this.health = this.nextHealthThreshold - 0.01
this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
this.invulnerableCount = 300
this.invulnerableCount = 240
this.isInvulnerable = true
this.damageReduction = 0
if (this.history.length < 200) for (let i = 0; i < 11; i++) this.history.unshift(this.history[0])
@@ -4011,21 +4100,18 @@ const spawn = {
move()
} else if (this.seePlayer.recall) { //chase player's history
this.lostPlayer();
if (!m.isCloak) {
for (let i = 0; i < 50; i++) { //if lost player lock onto a player location in history
if (m.isCloak) {
move(this.seePlayer.position) //go after where you last saw the player
} else {
for (let i = 0; i < 55; i++) { //if lost player lock onto a player location in history
let history = m.history[(m.cycle - 10 * i) % 600]
if (Matter.Query.ray(map, this.position, history.position).length === 0) {
this.seePlayer.recall = this.memory + Math.round(this.memory * Math.random()); //cycles before mob falls a sleep
this.seePlayer.position.x = history.position.x;
this.seePlayer.position.y = history.position.y;
this.seePlayer.yes = true;
move()
move(history.position) //go after where you last saw the player
break
}
}
}
}
}
this.checkStatus();
if (this.isInvulnerable) {
@@ -4099,7 +4185,7 @@ const spawn = {
me.fire = function () {
// this.armor();
this.checkStatus();
if (!m.isCloak && !this.isStunned) {
if (!this.isStunned) {
if (this.isFiring) {
if (this.fireCycle > this.fireDelay) { //fire
this.isFiring = false
@@ -4150,7 +4236,9 @@ const spawn = {
}
} else { //aim at player
this.fireCycle++
this.fireDir = Vector.normalise(Vector.sub(m.pos, this.position)); //set direction to turn to fire
//if cloaked, aim at player's history from 3 seconds ago
const whereIsPlayer = m.isCloak ? m.history[(m.cycle - 180) % 600].position : m.pos
this.fireDir = Vector.normalise(Vector.sub(whereIsPlayer, this.position)); //set direction to turn to fire
//rotate towards fireAngle
const angle = this.angle + Math.PI / 2;
const c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y;
@@ -4162,7 +4250,7 @@ const spawn = {
} else if (this.fireCycle > 45) { //fire
unit = Vector.mult(Vector.normalise(Vector.sub(this.vertices[1], this.position)), this.distanceToPlayer() - 100)
this.fireTarget = Vector.add(this.vertices[1], unit)
if (Vector.magnitude(Vector.sub(m.pos, this.fireTarget)) < 1000) { //if's possible for this to be facing 180 degrees away from the player, this makes sure that doesn't occur
if (Vector.magnitude(Vector.sub(whereIsPlayer, this.fireTarget)) < 1000) { //if's possible for this to be facing 180 degrees away from the player, this makes sure that doesn't occur
Matter.Body.setAngularVelocity(this, 0)
this.fireLockCount = 0
this.isFiring = true
@@ -4206,7 +4294,7 @@ const spawn = {
}, Vector.normalise(Vector.sub(this.fireTarget, this.position)));
//distance between the target and the player's location
if (
m.isCloak ||
// m.isCloak ||
dot > 0.03 || // not looking at target
Matter.Query.ray(map, this.fireTarget, this.position).length || Matter.Query.ray(body, this.fireTarget, this.position).length || //something blocking line of sight
Vector.magnitude(Vector.sub(m.pos, this.fireTarget)) > 1000 // distance from player to target is very far, (this is because dot product can't tell if facing 180 degrees away)
@@ -4638,10 +4726,11 @@ const spawn = {
Matter.Body.rotate(me, Math.random() * Math.PI * 2);
me.accelMag = 0.0001 * simulation.accelScale;
me.laserInterval = 100
Matter.Body.setDensity(me, 0.0015); //extra dense //normal is 0.001 //makes effective life much larger
spawn.shield(me, x, y);
me.onHit = function () {
//run this function on hitting player
this.explode();
// this.explode();
};
me.do = function () {
this.torque = this.lookTorque * this.inertia * 0.5;
@@ -4985,7 +5074,7 @@ const spawn = {
me.laserSword = function (where, angle, length) {
best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
const look = { x: where.x + length * Math.cos(angle), y: where.y + length * Math.sin(angle) };
best = vertexCollision(where, look, m.isCloak ? [map] : [map, [playerBody, playerHead]]);
best = vertexCollision(where, look, [map, [playerBody, playerHead]]);
if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + m.collisionImmuneCycles; //player is immune to damage for an extra second
m.damage(this.swordDamage);
@@ -5592,7 +5681,7 @@ const spawn = {
best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]);
best = vertexCollision(where, look, [map, body, [playerBody, playerHead]]);
if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
@@ -5691,7 +5780,7 @@ const spawn = {
me.laserSword = function (where, angle) {
best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]);
best = vertexCollision(where, look, [map, body, [playerBody, playerHead]]);
if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
m.damage(this.swordDamage);
@@ -5783,7 +5872,7 @@ const spawn = {
me.laserSword = function (where, angle) {
best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]);
best = vertexCollision(where, look, [map, body, [playerBody, playerHead]]);
if (best.who && (best.who === playerBody || best.who === playerHead) && m.immuneCycle < m.cycle) {
m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60; //player is immune to damage for an extra second
m.damage(this.swordDamage);
@@ -5893,7 +5982,7 @@ const spawn = {
me.laserSpear = function (where, angle) {
best = { x: null, y: null, dist2: Infinity, who: null, v1: null, v2: null };
const look = { x: where.x + this.swordRadius * Math.cos(angle), y: where.y + this.swordRadius * Math.sin(angle) };
best = vertexCollision(where, look, m.isCloak ? [map, body] : [map, body, [playerBody, playerHead]]);
best = vertexCollision(where, look, [map, body, [playerBody, playerHead]]);
if (best.who && (best.who === playerBody || best.who === playerHead)) {
this.swordRadiusGrowRate = 1 / this.swordRadiusGrowRateInitial //!!!! this retracts the sword if it hits the player
@@ -5954,7 +6043,7 @@ const spawn = {
simulation.drawList.push({
x: this.position.x,
y: this.position.y,
radius: 3000,
radius: 5000,
color: `rgba(0, 0, 0,${1 - 0.1 * i})`,
time: (i + 2) * 4
});
@@ -6109,9 +6198,9 @@ const spawn = {
mobs.spawn(x, y, 7, radius, "transparent");
let me = mob[mob.length - 1];
me.seeAtDistance2 = 500000;
me.accelMag = 0.00007 + 0.0001 * simulation.accelScale;
me.accelMag = 0.0002 + 0.0001 * simulation.accelScale;
if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search
Matter.Body.setDensity(me, 0.0002); //normal is 0.001
Matter.Body.setDensity(me, 0.00015); //normal is 0.001
me.damageReduction = 0.1
me.stroke = "transparent"; //used for drawGhost
me.alpha = 1; //used in drawGhost
@@ -6151,7 +6240,7 @@ const spawn = {
if (this.health < 0.8) me.seeAtDistance2 = 2000000;
}
me.do = function () {
if (this.speed > 7) Matter.Body.setVelocity(this, { x: this.velocity.x * 0.8, y: this.velocity.y * 0.8 }); //cap max speed to avoid getting launched by deflection, explosion
if (this.speed > 6) Matter.Body.setVelocity(this, { x: this.velocity.x * 0.8, y: this.velocity.y * 0.8 }); //cap max speed to avoid getting launched by deflection, explosion
this.seePlayerCheckByDistance();
this.checkStatus();
this.attraction();
@@ -6251,7 +6340,7 @@ const spawn = {
me.friction = 0;
me.frictionAir = 0.01;
me.memory = Infinity;
me.collisionFilter.mask = cat.player | cat.bullet //| cat.body
me.collisionFilter.mask = cat.player | cat.bullet | cat.body
spawn.shield(me, x, y, 1);
const len = Math.floor(Math.min(15, 3 + Math.sqrt(simulation.difficulty)))
@@ -7144,6 +7233,7 @@ const spawn = {
me.do = function () {
this.seePlayerByHistory(60);
this.attraction();
if (this.distanceToPlayer2() > 9000000) this.attraction(); //extra attraction if far away
this.checkStatus();
this.eventHorizon = 950 + 250 * Math.sin(simulation.cycle * 0.005)
if (!simulation.isTimeSkipping) {
@@ -7355,13 +7445,27 @@ const spawn = {
exploder(x, y, radius = 40 + Math.ceil(Math.random() * 50)) {
mobs.spawn(x, y, 4, radius, "rgb(255,0,0)");
let me = mob[mob.length - 1];
Matter.Body.setDensity(me, 0.0013); //normal is 0.001
me.onHit = function () {
//run this function on hitting player
this.explode();
this.explode(2.5 * this.mass);
};
me.g = 0.0004; //required if using this.gravity
spawn.shield(me, x, y);
// spawn.shield(me, x, y);
me.do = function () {
//draw aura
ctx.beginPath();
const vertices = this.vertices;
ctx.moveTo(vertices[0].x, vertices[0].y);
for (let j = 1, len = vertices.length; j < len; ++j) ctx.lineTo(vertices[j].x, vertices[j].y);
ctx.lineTo(vertices[0].x, vertices[0].y);
ctx.strokeStyle = `rgba(255,0,50,${0.13 + 0.45 * Math.random()})`
ctx.lineWidth = 30
ctx.stroke();
ctx.strokeStyle = "rgba(255,0,50,0.1)"
ctx.lineWidth = 70
ctx.stroke();
this.gravity();
this.seePlayerCheck();
this.checkStatus();

File diff suppressed because it is too large Load Diff

101
style.css
View File

@@ -9,6 +9,7 @@ body {
margin: 0;
overflow: hidden;
cursor: auto;
background-color: #f00;
/* filter: grayscale(1); */
/* transition: background-color 0.2s ease-in-out; */
}
@@ -124,21 +125,45 @@ summary {
background-color: #eee;
}
.SVG-button-splash {
border: 2px #333 solid;
border-radius: 8px;
background-color: #fff;
transition: opacity 5s ease-in;
}
.SVG-button-splash:hover {
background-color: #eee;
}
#start-button {
position: absolute;
bottom: 108px;
right: 4px;
z-index: 12;
/* top-left | top-right | bottom-right | bottom-left */
/* border-radius: 8px 8px 0 0; */
}
#training-button {
position: absolute;
bottom: 56px;
right: 4px;
z-index: 12;
/* border-radius: 8px 0px 0 0; */
}
#experiment-button {
position: absolute;
bottom: 4px;
right: 4px;
z-index: 12;
transition: opacity 5s ease-in;
/* border-radius: 8px 0 8px 8px; */
}
#training-button {
position: absolute;
top: 4px;
right: 4px;
z-index: 12;
transition: opacity 5s ease-in;
}
#construct {
display: none;
@@ -567,9 +592,10 @@ summary {
position: absolute;
bottom: 3px;
left: 3px;
z-index: 12;
z-index: 10;
font-size: 1.5em;
transition: opacity 5s ease-in;
width: 100%;
/* border: 1.5px #333 solid; */
/* border-radius: 8px; */
@@ -721,6 +747,18 @@ summary {
background-color: rgba(255, 255, 255, 0.4);
}
.constraint-module {
line-height: 160%;
padding: 20px;
border-radius: 5px;
font-size: 1.2em;
font-family: monospace;
font-weight: 800;
text-align: center;
color: #624;
background-color: rgba(255, 240, 250, 1);
}
#right-HUD-constraint {
position: absolute;
top: 12px;
@@ -743,6 +781,39 @@ summary {
transition: all 0.5s linear;
}
.constraint {
color: rgb(141, 23, 88);
}
.metallic-sparkle {
background: linear-gradient(90deg,
#c38aa6,
#e6c0d9,
#dca4c6,
#c38aa6,
#e6c0d9,
#dca4c6,
#c38aa6);
background-size: 200% 100%;
background-clip: text;
color: transparent;
animation: shimmer 4s infinite linear;
}
@keyframes shimmer {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
#text-log {
z-index: 2;
position: absolute;
@@ -758,12 +829,6 @@ summary {
user-select: none;
}
.constraint {
color: rgb(141, 23, 88);
/* font-weight: 100; */
/* text-decoration: underline; */
}
.color-text {
color: #000;
}
@@ -1543,9 +1608,9 @@ summary {
}
.draw-lines4 {
stroke-dasharray: 300;
stroke-dashoffset: 300;
animation: dash 2.5s ease-in forwards;
stroke-dasharray: 500;
stroke-dashoffset: 500;
animation: dash 3.5s ease-in forwards;
}

278
todo.txt
View File

@@ -1,85 +1,116 @@
******************************************************** NEXT PATCH **************************************************
tech: Halbach array - throwing a block will also throw other nearby blocks
pilot wave tech: Bells theorem - field is always on for no energy cost
pilot wave tech: principle of locality - 0.9x damage taken while inside pilot wave field, -2 choices
tech non-renewables now spawns ammo, but ammo can't be picked up
grenade tech that cause multiple explosions have less knock back for mobs
constraint: 0->0.5x healing
wormhole 7->8% duplication
many worlds takes a few frames between each tech given
hidden-variable theory 1.2->1.3 damage per field tech
WIMPS spawn 4->5 research per level
bug fixes
harpoon ammo gain on autonomous defense fixed
constraints are properly randomized again
fixed exploit with final tech power up on subway level
******************************************************** BUGS ********************************************************
couple reports of crashes from many-worlds
around level 5-7
for me crash on factory level 7
might be linked to having all the guns?
the crash was in matter.js something about collisions and undefined
maybe too many things were spawned in the same spot?
also occurs when you just gain many random tech in testing mode
figure out why seeded random isn't making runs the same:
shuffle is being used for a wide variety of things that don't need a seeded random
make two shuffle functions?
check which of these is working
level order
is flipped
constraint order
mob type order
boss order
gun, field, tech options
make field options offered precalculated so it doesn't depend on player choices?
generate all constraints at the start of the game
doesn't seem to be determined by the seed...
display future constraints in pause menu?
at start of level game go stuck in pause state
no crash or bug report
occur level 8
after 2 levels of sending power ups to next level
auto drones grabbed a power up and game froze while in power up mode
running code to exit pause kinda worked
ants marching outline on splash screen doesn't sync right on safari
player can become crouched while not touching the ground if they exit the ground while crouched
graphical bug - player can become crouched while not touching the ground if they exit the ground while crouched
*********************************************************** TODO *****************************************************
make a text orb for JUNK text to make JUNK more clear
tech - benefit if you haven't killed any mobs on this level
have to clean up mobs that die on level spawn from falling blocks
tech - benefit in the first 20 seconds of the level
extended vertical flip to edge cases:
!!stored circular graphics simulation.drawList.push
plasma globe - it should not explode on map contact, but instead shrink?
only explode on mouse release
use pilot wave code?
new level based laser element
!!update new version into other levels
rework JUNK
example: +5 JUNK adds a frequency of (1? 6?) to a random JUNK tech
if you see that JUNK tech again it's frequency drops down to 0 again
have to rework constraints and a few other tech...
mob - moves around, but then stops and makes porcupine spikes for 2 seconds, then moves again.
maybe use hopper movement?
soft body boss?
search softBody(x, y, angle = 0, isAttached = true, len = 15, radius = 20, stiffness = 1, damping = 1) {
use ←↑→↓↖↗↘↙ combos to allow fields to have special actions
how to limit spam?
on cooldown
timer or once per level
energy cost
research cost
toggle modes
combos are listed in white text in field description, and console message when getting field
shows up on highlight, and mouse over in experiment mode
field ideas:
standing wave
push mobs away are any distance
pull mobs towards you
perfect diamagnetism
negative mass
molecular assembler - done
plasma torch
move around like you have recoil, move kinda fast so it's hard to control
like form recoil but fast
time dilation
metamaterial cloaking
pilot wave - done
wormhole
toggle bullets entering with wormholes
and player??
shoot out all the blocks that were sucked in this level (maybe cap at like 10?, cap with energy spent to fire)
are block sizes stored properly? because they shrink before they get eaten...
store vertices on the body object if one does already exists
after eating store the saved vertices
where to fire blocks from and in what direction?
target mobs?
fire from player (and draw a wormhole looking graphic)
grappling hook
new level idea: large map sized blocks that can't be destroyed that the player walks on as a part of the level
eventually the blocks fall
after fall level progresses to a phase 2 to clean up the blocks or leave them
should bosses be killed by falling blocks??
how to avoid the large block vibrating/dancing on tiny block issue
new level idea: escort mission
player has to stay near something that moves slowly through the level
maybe only a zone around the escort is safe
safe from?
lasers
slime
radiation
use line of site vision?
is it going to feel too slow?
where to put in level order?
random option instead of reactor?
normal level?
4th hard level?
already too many hard options
you could put in 2 hard levels in the level list
make the style look like substructure, that level looks great
use the motion sense lasers
tech: - remove the research costs of all tech
there's about 15 tech with a research cost
!!conformal - similar rules for small and big scales linked to holographic principle
!!holonomy - parallel transport of a vector leads to movement (applies to curved space)
when far away from your wormhole regenerate 1% of your max energy per second
when far away from your wormhole reduce damage taken
heal last hit damage after enter wormhole
!!quasar - plasma torch from both ends of wormhole
only after wormhole eats a block fire?
or just increase plasma length after eating block?
procedural animation
https://www.youtube.com/watch?v=qlfh_rv6khY
not implemented random constraint ideas________________________
mob death spawns something
mob bullets
bosses heals nearby mobs
ammo power ups give 0.7x ammo
2x research costs
mobs slowly regen health
exit door takes 10x time to open,
and while door is opening (ghosters, suckers) attack?
can't have more then 15 bullets
how to code?
remove 2 random tech and return them next level
tech: ice-VII - 1.5x duration for ice-IX
tech: - freezing grenades/explosions
tech: - when you get a bot, get a second bot
tech: - after killing a Boss
heal to full
gain 3x damage for the rest of the level
@@ -117,12 +148,6 @@ tech: atomic pile - lose 1 health if you are above the maximum energy
do damage?
plasma torch tech?
figure out how to put instructions for controls in background on initial level
mouse smooth makes the text position jitter when it moves sub pixels
hide the jitter with artificial jitter to make it seem intentional
make it look like the instructions are on a fuzzy TV screen
when player presses move buttons highlight the box/letter for those buttons
make player mass an adjustable var in the skin
does this mess with jump height or air control?
increase mass and movement speed at the same time
@@ -132,10 +157,6 @@ increase mass and movement speed at the same time
possible player.mass bad interactions
grapple
rework energy and health HUD
make both diegetic?
how? not sure there is a good way to do this...
tech - after a power up is duplicated
update text to random effect after choosing tech, or after each trigger, or on first display of tech
pick 1 effect at random
@@ -143,7 +164,7 @@ tech - after a power up is duplicated
summon JUNK bots for 10 seconds
2x current energy
gain 1.01x damage permanently
cool name:
cool name:
after picking up heals gain ____
0.1x damage taken for 12s
@@ -159,43 +180,9 @@ tech - getting caught in an explosion gives you _____
damage for 10 seconds?
heals
tech - limit total number of tech to like 10?
tech - destroying blocks gives _____
removeJunkTechFromPool doesn't seem to remove the correct amount
wormholes that end inside wall check to see if the space before the wall is safe and end there instead
can use laser code
tech: - (1 + 0.01)x for each tech, gun, field you've picked up
scales with born rule, duplication, remove tech
explosions have a chance to spawn spores
infinite feedback loop with spores that explode?
make sure healing isn't effected by simulation.healScale
instead heal orb size should be scaled
but the ratio between size and heal shouldn't be effected
boss - tracks the position, velocity, angle of power ups, blocks, and bullets it fires
reactor only?
will rewind time
after damage threshold?
does it track player bullets?
button/switch input ideas from Cocoon game
pick up blocks that have a rubber band attached to a sliding switch
as player moves the vector direction of the rubber band will move the slider left or right
use this to open doors, move larger blocks, ...
switches that toggle left, right when player presses input.field while standing nearby
replace laser off on switch?
platform that rises up when player presses input.field while standing
How to instruct player to use field on these?
color with field #0ff
draw field effect
make it still functional without the field button
tech - getting a new gun also gives you 2 random tech for that gun
or a field?
can these guntech tech be converted into a player choice?
@@ -219,6 +206,31 @@ improve new player experience
When foam is in an explosion it also explodes with size proportional to the size of the foam bubble
Requires foam, explosion source, not aerogel
new level similar to ash tray maze
!!not sure how this works with theme (most levels are locations that have industrial stuff)
this might work as another line of sight level?
could be fine without line of sight if rooms don't exist until they open up?
where to put in game sequence?
watch a run through https://www.youtube.com/watch?v=nudSXUMBEV4
close off doors as player gets close
open up doors as player gets close
holes in the floor
slide large walls back to open up levels below
show a zone, then close it off, but eventually reveal it later
rise up pillars during combat
small maze rooms, 1-2 really huge rooms, long corridors, medium combat rooms
triggers for changes
clearing mobs in a zone
or time based if player is too slow
player gets close to a zone
make map elements shift around as player moves through the game
start with map elements filling everywhere and slow open up new zones
need a cool way to animate adding and removing map elements
maybe for the entire level redraw the map every 15 cycles?
simulation.draw.setPaths() //update map graphics
slide map around
small map squares that each add in sequentially
Cosmological natural selection: do something with black holes
spawn black hole mobs
after bosses die?
@@ -341,16 +353,6 @@ make a lemming that walks until it hits a wall and then turns around robotically
body or mob?
can't be killed?
use ephemera to replace some bad code
JUNK?
request animation stuff
simulation checks
damage and defense bars
disable and enable ephemera with settings
perfect diamagnatism - invulnerable while field is active?
also drain energy while field is active?
mobs attack mines
mines periodically set all mobs to have player location to be the mine
is this going to work with all mob vision types?
@@ -364,23 +366,8 @@ Tech: relativity
wormhole tech - teleport away mobs with mass below 3 when they get too near the player
short CD, small energy cost, only mobs below a mass
extend brainstorming animation timers to fps cap?
will it be smoother or choppier?
anything else needs to hit limited fps on a high fps monitor?
perfect diamagnatism could bounce on mobs, or even map elements?
could work like a rocket jump?
tech: Bose Einstein condensate - freezes enemies in pilot wave, and drains some energy?
make super balls with Zectron deflectable with field
but is there a simple way to do this?
set mob health bar colors based on status effects?
make mob damage immunity a mob status effect?
tech: rail gun area damage effect, but for all harpoon mode
mob status effect - vulnerability
mobs take 4x damage for __ time
afterwards mobs go back to normal damage taken
@@ -839,9 +826,6 @@ mob/boss that fires a laser at player, but give player time to avoid
they target where player was 1 second ago
they turn to face player?
tech rocket jump - jumping produces an explosion at your feet that lets you jump extra high, but does some damage
require electric reactive armor?
Plasma Burner: upgrade for plasma torch, basically just a jet engine. does high damage, but short range, mostly for player movement.
maybe reduce gravity to really low then apply a vector away from mouse direction
@@ -851,17 +835,6 @@ auto-gon - auto battler with n-gon mob AI and tech
similar research and tech system to n-gon
some mobs can fire player weapons
tech: relativistic jets:
small particles that shot out from front and back poles and end up in a wide variety of spirals
slow trickle when charging and several more when firing
Tech: Make player smol
adapt the cloaking graphics to make a flashlight cone visual effect
put code in level.do?
be nice if block throwing had a projected path
Pilot wave tech
Energy use is increased, but you can now shape blocks using pressure
Grouping blocks will merge them into a massive ball
@@ -1234,11 +1207,8 @@ look up sci-fi science ideas here https://projectrho.com/public_html/rocket/
possible names for tech
sidereal - with respect to the stars (an extra rotation for time keeping)
holonomy - parallel transport of a vector leads to movement (applies to curved space)
holographic - 2-D surface can predict the 3-D space behind it? I think
entropic gravity - gravity is emergent in a holographic way
(maybe a field tech for negative mass)
conformal - similar rules for small and big scales linked to holographic principle
hypergolic - A hypergolic propellant combination used in a rocket engine is one whose components spontaneously ignite when they come into contact with each other.
swarm intelligence - for a drone tech
metaheuristic - is a higher-level procedure or heuristic designed to find, generate, or select a heuristic (partial search algorithm) that may provide a sufficiently good solution to an optimization problem, especially with incomplete or imperfect information or limited computation capacity
@@ -1292,7 +1262,6 @@ possible names for tech
amalgam, amalgamation - the action, process, or result of combining or uniting.
thermoplastic - the stuff in 3-D printers, use for molecular assembler tech
ergosphere - region of a spinning black hole that might allow FTL or alternate realities.
equivalence principle - gravity and acceleration are the same
Casimir effect - attractive force between two close conductive plates
difference engine - early calculator/computer
cyanoacrylate - superglue use for a slowing effect?
@@ -1307,8 +1276,13 @@ possible names for tech
cork - used as a heat shield for rockets
P = NP - something with speeding up calculation times
transistivity - something where a>b and b>c -> a>c
lenticular - looks different from different angles (lasers?)
lenticular - looks different from different angles (lasers?, cloaking?)
every few seconds pick a random skin tech?
De Sitter space - simple model of universe related to general relativity (mass-energy?)
active optics - something with lasers? maybe something with diffuse beam getting smaller
Quintessence - related to dark energy
biofilm - something defensive? related to spores?
Thermogalvanic - makes things cold, for no energy
******************************************************* DESIGN ******************************************************
@@ -1332,4 +1306,4 @@ list of powerful synergies
interest + coupling, research + (peer review? or Bayesian statistics)
electronegativity and high energy?
electronegativity + anyon + duplication + Maxwells demon + interest + pair production
chain reaction + invulnerable + Abelian group + parasitism = clear all mobs on level
chain reaction + invulnerable + Abelian group + parasitism = clear all mobs on level