diff --git a/.DS_Store b/.DS_Store index 3482c29..e089e3a 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/js/level.js b/js/level.js index 419fbf2..7c38ccc 100644 --- a/js/level.js +++ b/js/level.js @@ -12,9 +12,9 @@ const level = { start() { if (level.levelsCleared === 0) { //this code only runs on the first level // simulation.enableConstructMode() //used to build maps in testing mode - // level.difficultyIncrease(30) + // level.difficultyIncrease(60) //30 is near max on hard //60 is near max on why // simulation.isHorizontalFlipped = true - // m.setField("perfect diamagnetism") + // m.setField("wormhole") // b.giveGuns("spores") // tech.giveTech("CPT reversal") // tech.giveTech("causality bombs") @@ -640,10 +640,10 @@ const level = { this.isUp = true; } else { if (this.isUp === true) { - const list = Matter.Query.region(body, this) + const list = Matter.Query.region(body, this) //are any blocks colliding with this if (list.length > 0) { - if (list[0].bounds.max.x - list[0].bounds.min.x < 150 && list[0].bounds.max.y - list[0].bounds.min.y < 150) { - Matter.Body.setPosition(list[0], { + if (list[0].bounds.max.x - list[0].bounds.min.x < 150 && list[0].bounds.max.y - list[0].bounds.min.y < 150) { //not too big of a block + Matter.Body.setPosition(list[0], { //teleport block to the center of the button x: this.min.x + width / 2, y: list[0].position.y }) @@ -2195,7 +2195,9 @@ const level = { spawn.mapRect(475, -25, 25, 50); //edge shelf }, testing() { - // const button = level.button(200, -700) + const button = level.button(1000, 0) + spawn.bodyRect(1000, -50, 50, 50); + // const toggle = level.toggle(200, -700) level.custom = () => { // button.draw(); @@ -2206,7 +2208,8 @@ const level = { level.enter.draw(); }; level.customTopLayer = () => { - // toggle.query(); + button.query(); + button.draw(); }; level.setPosToSpawn(0, -450); //normal spawn @@ -2253,8 +2256,8 @@ const level = { spawn.mapRect(6700, -1800, 800, 2600); //right wall spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump - spawn.starter(1900, -500, 200) //big boy - spawn.starter(1900, -500) + // spawn.starter(1900, -500, 200) //big boy + spawn.buffBossCulture(1900, -500) // spawn.pulsarBoss(1900, -500) // spawn.shieldingBoss(1900, -500) @@ -2268,7 +2271,7 @@ const level = { // spawn.bomberBoss(1400, -500) // spawn.hopBoss(1800, -120) // spawn.streamBoss(1600, -500) - // spawn.orbitalBoss(1600, -500) + // spawn.powerUpBoss(1600, -500) // spawn.cellBossCulture(1600, -500) // spawn.shieldingBoss(1600, -500) // spawn.grenadier(1200, -500) @@ -7056,7 +7059,7 @@ const level = { spawn.randomGroup(2000, -5700, 0.6); powerUps.addResearchToLevel() //needs to run after mobs are spawned - let bosses = ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "laserBoss"]; + let bosses = ["shooterBoss", "launcherBoss", "laserTargetingBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "laserBoss", "buffBossCulture"]; let abc = Math.random(); if (simulation.difficulty > 3) { if (abc < 0.6) { diff --git a/js/lore.js b/js/lore.js index ad04aef..aaea374 100644 --- a/js/lore.js +++ b/js/lore.js @@ -351,7 +351,12 @@ const lore = { lore.miriam.text("The exact coordinates are blocked.") } else { console.log('Locating…') - navigator.geolocation.getCurrentPosition(success, error); + const options = { + enableHighAccuracy: true, + maximumAge: 30000, + timeout: 27000 + }; + navigator.geolocation.getCurrentPosition(success, error, options); } }, () => { lore.anand.text("This location is sending and receiving data from the satellite.") }, @@ -401,7 +406,6 @@ const lore = { () => { lore.talkingColor = "#dff" }, ], // [ // they decided that a part of the project is out of control, but the part of it that doesn't needs to calm it down, and trust. - // /* // The part of the AI controlling the player is outsourcing the player control to real humans that think they are playing a video game. // this means the player can use console commands to change the way the game works diff --git a/js/player.js b/js/player.js index 39ec651..92e1c14 100644 --- a/js/player.js +++ b/js/player.js @@ -1135,7 +1135,7 @@ const m = { b.pulse(50 * Math.pow(m.holdingTarget.mass, 0.25), m.angle) } else { //normal throw //bullet-like collisions - m.holdingTarget.collisionFilter.category = tech.isBlockBullets ? cat.bullet : cat.body; + m.holdingTarget.collisionFilter.category = cat.bullet m.holdingTarget.collisionFilter.mask = cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet | cat.mobShield; //check every second to see if player is away from thrown body, and make solid const solid = function(that) { @@ -2322,7 +2322,7 @@ const m = { // }, { name: "pilot wave", - description: "use energy to push blocks with your mouse
field radius decreases out of line of sight
energy drain scales with mass", + description: "use energy to push blocks with your mouse
blocks can collide with intangible mobs
field radius decreases out of line of sight", effect: () => { m.fieldPhase = 0; m.fieldPosition = { @@ -2431,7 +2431,7 @@ const m = { for (let i = 0, len = body.length; i < len; ++i) { if (Vector.magnitude(Vector.sub(body[i].position, m.fieldPosition)) < m.fieldRadius && !body[i].isNotHoldable) { - const DRAIN = speed * body[i].mass * 0.000013 // * (1 + m.energy * m.energy) //drain more energy when you have more energy + const DRAIN = speed * body[i].mass * 0.000015 // * (1 + m.energy * m.energy) //drain more energy when you have more energy if (m.energy > DRAIN) { m.energy -= DRAIN; Matter.Body.setVelocity(body[i], velocity); //give block mouse velocity @@ -2442,7 +2442,7 @@ const m = { const unit = Vector.mult(Vector.normalise(sub), body[i].mass * tech.pilotForce * Vector.magnitude(sub)) body[i].force.x += unit.x body[i].force.y += unit.y - body[i].mass * simulation.g //remove gravity effects - if (tech.isBlockBullets && body[i].collisionFilter.category !== cat.bullet) body[i].collisionFilter.category = cat.bullet; + if (body[i].collisionFilter.category !== cat.bullet) body[i].collisionFilter.category = cat.bullet; } else { m.fieldCDcycle = m.cycle + 120; m.fieldOn = false diff --git a/js/spawn.js b/js/spawn.js index a0973dd..728669c 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -84,7 +84,8 @@ const spawn = { } } }, - randomLevelBoss(x, y, options = ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss"]) { + nonCollideBossList: ["cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss", "spawnerBossCulture", "buffBossCulture"], + randomLevelBoss(x, y, options = ["shieldingBoss", "orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss", "powerUpBoss", "snakeBoss", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "buffBossCulture"]) { // other bosses: suckerBoss, laserBoss, tetherBoss, //these need a particular level to work so they are not included in the random pool spawn[options[Math.floor(Math.random() * options.length)]](x, y) }, @@ -706,7 +707,6 @@ const spawn = { me.memory = 60; me.seeAtDistance2 = 1400000 //1200 vision range Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback - me.do = function() { this.seePlayerByLookingAt(); this.attraction(); @@ -812,7 +812,6 @@ const spawn = { me.frictionAir = 0.012 me.seePlayerFreq = Math.floor(11 + 7 * Math.random()) me.seeAtDistance2 = 200000 //1400000; - me.cellMassMax = 70 me.stroke = "transparent" me.collisionFilter.mask = cat.player | cat.bullet //| cat.body //| cat.map //"rgba(255,60,0,0.3)" // Matter.Body.setDensity(me, 0.0014) // normal density is 0.001 @@ -828,11 +827,6 @@ const spawn = { this.checkStatus(); this.attraction(); - // if (this.seePlayer.recall && this.mass < this.cellMassMax) { //grow cell radius - // const scale = 1 + 0.0002 * this.cellMassMax / this.mass; - // Matter.Body.scale(this, scale, scale); - // this.radius = Math.sqrt(this.mass * k / Math.PI) - // } if (!(simulation.cycle % this.seePlayerFreq)) { //move away from other mobs const repelRange = 40 const attractRange = 240 @@ -887,6 +881,88 @@ const spawn = { } }, + buffBossCulture(x, y, radius = 17, nodes = 12 + Math.min(10, simulation.difficulty * 0.27)) { + const buffID = Math.random() + const sideLength = 200 + 50 * Math.sqrt(nodes) // distance between each node mob + const targets = [] + for (let i = 0; i < nodes; ++i) { + const angle = 2 * Math.PI * Math.random() + spawn.buffBoss(x + sideLength * Math.cos(angle) * Math.random(), y + sideLength * Math.sin(angle) * Math.random(), radius, buffID); + // spawn.buffBoss(x + sideLength * nodes * (Math.random() - 0.5), y + sideLength * nodes * (Math.random() - 0.5), radius, buffID); + targets.push(mob[mob.length - 1].id) //track who is in the group, for shields + + } + const attachmentStiffness = 0.0001 + spawn.constrain2AdjacentMobs(nodes, attachmentStiffness, false); //loop mobs together + // if (simulation.difficulty > 15) this.groupShield(targets, x, y, sideLength + radius * 2); + }, + buffBoss(x, y, radius, buffID) { + mobs.spawn(x + Math.random(), y + Math.random(), 6, radius, "hsl(144, 15%, 50%)") //); + let me = mob[mob.length - 1]; + me.isBoss = true; + me.damageReduction = 0.25; + me.isBuffBoss = true; + me.buffID = buffID + me.memory = Infinity; + // me.showHealthBar = false; + me.isVerticesChange = true + me.frictionAir = 0.012 + 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.buffCount = 0 + me.accelMag = 0.0001 //* simulation.accelScale; + me.setBuffed = function() { + this.buffCount++ + this.accelMag += 0.00005 //* Math.sqrt(simulation.accelScale) + // Matter.Body.setDensity(this, 0.001 + 0.0003 * this.buffCount) // normal density is 0.001 //+ 0.0005 * Math.sqrt(simulation.difficulty) + this.fill = `hsl(144, ${5+10*this.buffCount}%, 50%)` + const scale = 1.14; + Matter.Body.scale(this, scale, scale); + this.radius *= scale; + // this.health += 0.03 + // if (this.health > 1) this.health = 1 + } + me.onDeath = function() { + this.isBuffBoss = false; + let count = 0 //count other cells by id + for (let i = 0, len = mob.length; i < len; i++) { + if (mob[i].isBuffBoss && mob[i].buffID === this.buffID) { + count++ + mob[i].setBuffed() + } + } + if (count < 1) { //only drop a power up if this is the last cell + powerUps.spawnBossPowerUp(this.position.x, this.position.y) + } else { + this.leaveBody = false; + // this.isDropPowerUp = false; //these guys can still drop power ups since they are hard to kill + } + } + me.do = function() { + this.alwaysSeePlayer(); + this.checkStatus(); + this.attraction(); + + // if (!(simulation.cycle % this.seePlayerFreq)) { //move away from other mobs + // const repelRange = 100 + 4 * this.radius + // const attractRange = 240 + // for (let i = 0, len = mob.length; i < len; i++) { + // if (mob[i].isBuffBoss && mob[i].id !== this.id) { + // const sub = Vector.sub(this.position, mob[i].position) + // const dist = Vector.magnitude(sub) + // if (dist < repelRange) { + // this.force = Vector.mult(Vector.normalise(sub), this.mass * 0.002) + // } else if (dist > attractRange) { + // this.force = Vector.mult(Vector.normalise(sub), -this.mass * 0.002) + // } + // } + // } + // } + } + }, powerUpBoss(x, y, vertices = 9, radius = 130) { mobs.spawn(x, y, vertices, radius, "transparent"); let me = mob[mob.length - 1]; @@ -1585,7 +1661,7 @@ const spawn = { }, historyBoss(x, y, radius = 30) { if (tech.dynamoBotCount > 0) { - spawn.randomLevelBoss(x, y, ["cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss", "spawnerBossCulture"]) + spawn.randomLevelBoss(x, y, spawn.nonCollideBossList) return } mobs.spawn(x, y, 0, radius, "transparent"); @@ -2929,7 +3005,7 @@ const spawn = { }; Matter.Body.setDensity(me, 0.00005); //normal is 0.001 me.timeLeft = 240; - me.g = 0.001; //required if using 'gravity' + me.g = 0.0005; //required if using 'gravity' me.frictionAir = 0; me.restitution = 0; me.leaveBody = false; @@ -2939,6 +3015,7 @@ const spawn = { me.collisionFilter.category = cat.mobBullet; me.collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet; me.do = function() { + this.gravity(); this.timeLimit(); if (Matter.Query.collides(this, map).length > 0 || Matter.Query.collides(this, body).length > 0 && this.speed < 3) { this.isDropPowerUp = false; diff --git a/js/tech.js b/js/tech.js index 68dd7af..f7a8397 100644 --- a/js/tech.js +++ b/js/tech.js @@ -188,15 +188,14 @@ if (tech.is100Duplicate && tech.duplicationChance() > 0.99) { tech.is100Duplicate = false const range = 700 - const bossOptions = ["historyBoss", "cellBossCulture", "bomberBoss", "powerUpBoss", "orbitalBoss", "spawnerBossCulture"] - spawn.randomLevelBoss(m.pos.x + range, m.pos.y, bossOptions); - spawn.randomLevelBoss(m.pos.x, m.pos.y + range, bossOptions); - spawn.randomLevelBoss(m.pos.x - range, m.pos.y, bossOptions); - spawn.randomLevelBoss(m.pos.x, m.pos.y - range, bossOptions); - spawn.randomLevelBoss(m.pos.x + range, m.pos.y + range, bossOptions); - spawn.randomLevelBoss(m.pos.x + range, m.pos.y - range, bossOptions); - spawn.randomLevelBoss(m.pos.x - range, m.pos.y + range, bossOptions); - spawn.randomLevelBoss(m.pos.x - range, m.pos.y - range, bossOptions); + spawn.randomLevelBoss(m.pos.x + range, m.pos.y, spawn.nonCollideBossList); + spawn.randomLevelBoss(m.pos.x, m.pos.y + range, spawn.nonCollideBossList); + spawn.randomLevelBoss(m.pos.x - range, m.pos.y, spawn.nonCollideBossList); + spawn.randomLevelBoss(m.pos.x, m.pos.y - range, spawn.nonCollideBossList); + spawn.randomLevelBoss(m.pos.x + range, m.pos.y + range, spawn.nonCollideBossList); + spawn.randomLevelBoss(m.pos.x + range, m.pos.y - range, spawn.nonCollideBossList); + spawn.randomLevelBoss(m.pos.x - range, m.pos.y + range, spawn.nonCollideBossList); + spawn.randomLevelBoss(m.pos.x - range, m.pos.y - range, spawn.nonCollideBossList); } }, tech: [{ @@ -1524,24 +1523,24 @@ tech.isMobBlockFling = false } }, - { - name: "fermions", - description: "blocks thrown by you or pilot wave will
collide with intangible mobs, but not you", - maxCount: 1, - count: 0, - frequency: 2, - frequencyDefault: 2, - allowed() { - return (tech.throwChargeRate > 1 || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && !tech.isBlockExplosion - }, - requires: "mass driver or pilot wave, not tokamak", - effect() { - tech.isBlockBullets = true - }, - remove() { - tech.isBlockBullets = false - } - }, + // { + // name: "fermions", + // description: "blocks thrown by you or pilot wave will
collide with intangible mobs, but not you", + // maxCount: 1, + // count: 0, + // frequency: 2, + // frequencyDefault: 2, + // allowed() { + // return (tech.throwChargeRate > 1 || m.fieldUpgrades[m.fieldMode].name === "pilot wave") && !tech.isBlockExplosion + // }, + // requires: "mass driver or pilot wave, not tokamak", + // effect() { + // tech.isBlockBullets = true + // }, + // remove() { + // tech.isBlockBullets = false + // } + // }, { name: "inflation", description: "throwing a block expands it by 300%
increase throw charge rate by 200%", @@ -1617,17 +1616,17 @@ }, { name: "complex spin-statistics", - description: `become immune to harm for 1 second
once every 7 seconds`, + description: `become immune to harm for 1.5 seconds
once every 7 seconds`, maxCount: 3, count: 0, - frequency: 2, - frequencyDefault: 2, + frequency: 1, + frequencyDefault: 1, allowed() { return true //tech.collisionImmuneCycles > 30 }, requires: "", effect() { - tech.cyclicImmunity += 60; + tech.cyclicImmunity += 90; }, remove() { tech.cyclicImmunity = 0; @@ -7500,7 +7499,6 @@ isCollisionRealitySwitch: null, iceIXOnDeath: null, wimpCount: null, - isBlockBullets: null, isAddBlockMass: null, isMACHO: null, isHarmMACHO: null, diff --git a/todo.txt b/todo.txt index d07333c..e4587d3 100644 --- a/todo.txt +++ b/todo.txt @@ -1,59 +1,23 @@ ******************************************************** NEXT PATCH ******************************************************** -2 more lore chapters (5 total now) -entering testing mode makes a sound now +buffBoss: group of mobs that buff their group after they die + this boss maybe unbalanced in some situations, let me know + (get them all low on health before you start killing them) -reduced the requirements and frequency for many tech so that they may show up in "less optimal" situations - I hope this will increase build variety and also give more value to making good tech choices -countless bug fixes and wording fixes +complex spin-statistics gives 1.5/7 harm immunity (was 1/7) + also tech frequency was halved -mobs have a new trait mob[i].damageReduction +tech fermions is now on by default: thrown blocks can collide with intangible mobs + pilot wave uses 5% more energy for balance ******************************************************** TODO ******************************************************** - +try out making the player's "eye" a bigger circle perfect diamagnetism field stays when you aren't holding field good for perfect because it doesn't use energy holding field moves it the player -level with mobs that follow a genetic algorithm - mobs have genes - the last mob that did damage saves it's genes to local storage - new mobs have the saved genes, but with some random mutations - mutations need to be balanced to prevent a gene from moving towards infinity - total genome must equal 1 (100%) - binary genes have a flat cost - example: phasing through walls might cost 0.2 - spectrum genes have a rate - example: acceleration cost 0.01 per 0.001 - possible genes - genes should only effect it's ability to touch the player - so not damage? - genome: spectrum - acceleration - top speed / air friction - damageReduction - duration? - health decreases naturally? - or they just go away like bullets? - spawn rate - look frequency / memory? - genome: binary - go through walls - blink/teleport (like striker) - grow when near target - split into two - shielded - occurs in a specialized level - named: gene lab, gene factory, genetic lab, genome facility - in the level sequence after lab and before gauntlet? - level ends after a period of time - exit is hidden until time is up and it appears - the level tests player durability/evasion - this is a nice contrast to the final level that tests damage output, and the gauntlet which tests AoE damage - - scrolling console history in pause menu? also make tech, guns scrolling? in testing mode console log the body you click on @@ -261,7 +225,41 @@ is there a way to check if the player is stuck inside the map or block ******************************************************** LEVELS ******************************************************** -try out making the player's "eye" a bigger circle +level with mobs that follow a genetic algorithm + mobs have genes + the last mob that did damage saves it's genes to local storage + new mobs have the saved genes, but with some random mutations + mutations need to be balanced to prevent a gene from moving towards infinity + total genome must equal 1 (100%) + binary genes have a flat cost + example: phasing through walls might cost 0.2 + spectrum genes have a rate + example: acceleration cost 0.01 per 0.001 + possible genes + genes should only effect it's ability to touch the player + so not damage? + genome: spectrum + acceleration + top speed / air friction + damageReduction + duration? + health decreases naturally? + or they just go away like bullets? + spawn rate + look frequency / memory? + genome: binary + go through walls + blink/teleport (like striker) + grow when near target + split into two + shielded + occurs in a specialized level + named: gene lab, gene factory, genetic lab, genome facility + in the level sequence after lab and before gauntlet? + level ends after a period of time + exit is hidden until time is up and it appears + the level tests player durability/evasion + this is a nice contrast to the final level that tests damage output, and the gauntlet which tests AoE damage rename intro level to something lore related @@ -315,12 +313,6 @@ map: observatory ******************************************************** MOBS ******************************************************** -mobs that buff the stats of mobs when they die - nearby mobs - boss is a group of mobs, they buff each other - give the buff a ramp up time - so there is an advantage to kill them all at once - mob that spawns eggs after they die eggs don't attack but grow back into a mob after about 10s