snake
snakeBoss - boss with a tail that grows longer after damage or eating power ups trying out putting actual system error messages directly into the in-game console charmed baryons: 0.66->0.8x movement grappling hook field: 0.6->0.5 damage taken
This commit is contained in:
@@ -12,6 +12,10 @@ 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.makeTextLog(`<strong style='color:red;'>ERROR:</strong> ${error.message} <u>${error.filename}:${error.lineno}</u>`)
|
||||
});
|
||||
|
||||
document.getElementById("seed").placeholder = Math.initialSeed = String(Math.floor(Date.now() % 100000))
|
||||
Math.seed = Math.abs(Math.hash(Math.initialSeed)) //update randomizer seed in case the player changed it
|
||||
Math.seededRandom = function (min = 0, max = 1) { // in order to work 'Math.seed' must NOT be undefined
|
||||
|
||||
148
js/spawn.js
148
js/spawn.js
@@ -6,8 +6,8 @@ const spawn = {
|
||||
"orbitalBoss", "historyBoss", "shooterBoss", "cellBossCulture", "bomberBoss", "spiderBoss", "launcherBoss", "laserTargetingBoss",
|
||||
"powerUpBoss", "powerUpBossBaby", "streamBoss", "pulsarBoss", "spawnerBossCulture", "grenadierBoss", "growBossCulture", "blinkBoss",
|
||||
"snakeSpitBoss", "laserBombingBoss", "blockBoss", "revolutionBoss", "slashBoss", "shieldingBoss",
|
||||
"timeSkipBoss", "dragonFlyBoss", "beetleBoss", "sneakBoss", "mantisBoss",
|
||||
"laserLayerBoss"
|
||||
"timeSkipBoss", "dragonFlyBoss", "beetleBoss", "sneakBoss", "mantisBoss", "laserLayerBoss",
|
||||
"snakeBoss",
|
||||
],
|
||||
bossTypeSpawnOrder: [], //preset list of boss names calculated at the start of a run by the randomSeed
|
||||
bossTypeSpawnIndex: 0, //increases as the boss type cycles
|
||||
@@ -3870,111 +3870,182 @@ const spawn = {
|
||||
};
|
||||
},
|
||||
snakeBoss(x, y) {
|
||||
mobs.spawn(x, y, 0, 30, `rgba(255,0,200)`); //"rgb(221,102,119)"
|
||||
mobs.spawn(x, y, 0, 25, `rgba(255,0,200)`); //"rgb(221,102,119)"
|
||||
let me = mob[mob.length - 1];
|
||||
me.stroke = "transparent"; //used for drawGhost
|
||||
// Matter.Body.setStatic(me, true); //make static, breaks game on player collision
|
||||
Matter.Body.setDensity(me, 0.002); //extra dense //normal is 0.001 //makes effective life much larger
|
||||
Matter.Body.setDensity(me, 0.03); //extra dense //normal is 0.001 //makes effective life much larger
|
||||
me.isBoss = true;
|
||||
me.damageReduction = 0.02
|
||||
me.damageReduction = 0.6
|
||||
me.startingDamageReduction = me.damageReduction
|
||||
me.isInvulnerable = false
|
||||
me.nextHealthThreshold = 0.75
|
||||
me.invulnerableCount = 0
|
||||
|
||||
me.history = []
|
||||
for (let i = 0; i < 15; i++) {
|
||||
for (let i = 0; i < 20; i++) {
|
||||
me.history.push({ x: me.position.x + i, y: me.position.y })
|
||||
}
|
||||
me.frictionStatic = 0;
|
||||
me.friction = 0;
|
||||
me.memory = 240
|
||||
me.seePlayerFreq = 55
|
||||
me.delay = 6 + 4 * simulation.CDScale;
|
||||
me.delay = 4 + 2 * simulation.CDScale;//8 + 3 * simulation.CDScale;
|
||||
me.nextBlinkCycle = me.delay;
|
||||
me.radius = 30
|
||||
me.JumpDistance = me.radius * 2
|
||||
me.JumpDistance = 0//set in redMode()
|
||||
// spawn.shield(me, x, y, 1);
|
||||
me.collisionFilter.mask = cat.bullet | cat.map //| cat.body //cat.player |
|
||||
me.powerUpNames = []
|
||||
me.redMode = function () {
|
||||
this.color = `rgba(255,0,200,`
|
||||
this.fill = this.color + '1)'
|
||||
this.JumpDistance = 20
|
||||
let cycle = () => {
|
||||
if (this.radius < 25) {
|
||||
if (m.alive && this.JumpDistance === 20) requestAnimationFrame(cycle);
|
||||
if (!simulation.paused && !simulation.isChoosing) {
|
||||
const scale = 1.01;
|
||||
Matter.Body.scale(this, scale, scale);
|
||||
this.radius *= scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
requestAnimationFrame(cycle);
|
||||
}
|
||||
me.redMode();
|
||||
me.blueMode = function () {
|
||||
this.color = `rgba(0,0,255,`//`rgba(255,0,200,`
|
||||
this.fill = this.color + '1)'
|
||||
this.JumpDistance = 37 //adjust this number in the IF below
|
||||
let cycle = () => {
|
||||
if (this.radius > 14) {
|
||||
if (m.alive && this.JumpDistance === 37) requestAnimationFrame(cycle);
|
||||
if (!simulation.paused && !simulation.isChoosing) {
|
||||
const scale = 0.96;
|
||||
Matter.Body.scale(this, scale, scale);
|
||||
this.radius *= scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
requestAnimationFrame(cycle);
|
||||
}
|
||||
me.onDamage = function () {
|
||||
if (this.health < this.nextHealthThreshold) {
|
||||
this.health = this.nextHealthThreshold - 0.01
|
||||
this.nextHealthThreshold = Math.floor(this.health * 4) / 4 //0.75,0.5,0.25
|
||||
this.invulnerableCount = 90
|
||||
this.invulnerableCount = 300
|
||||
this.isInvulnerable = true
|
||||
this.damageReduction = 0
|
||||
this.laserDelay = 130
|
||||
const where = this.history[0]
|
||||
for (let i = 0; i < 10; i++) {
|
||||
this.history.unshift(where)
|
||||
}
|
||||
if (this.history.length < 200) for (let i = 0; i < 11; i++) this.history.unshift(this.history[0])
|
||||
this.blueMode()
|
||||
}
|
||||
};
|
||||
me.onDeath = function () {
|
||||
powerUps.spawnBossPowerUp(this.position.x, this.position.y)
|
||||
|
||||
//respawn all eaten power ups
|
||||
let i = 0
|
||||
let cycle = () => {
|
||||
if (i < this.powerUpNames.length) {
|
||||
if (m.alive) requestAnimationFrame(cycle);
|
||||
if (!simulation.paused && !simulation.isChoosing && powerUp.length < 300) {
|
||||
const index = Math.floor(Math.random() * this.history.length) //random segment of tail
|
||||
const where = { x: this.history[index].x + 25 * (Math.random() - 0.5), y: this.history[index].y + 25 * (Math.random() - 0.5) }
|
||||
powerUps.spawn(where.x, where.y, this.powerUpNames[i]);
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
requestAnimationFrame(cycle);
|
||||
}
|
||||
me.do = function () {
|
||||
const color = `rgba(255,0,200,${0.3 + 0.07 * Math.random()})`
|
||||
|
||||
//check for player in between each segment
|
||||
const color = this.color + (0.35 + 0.25 * Math.random()) + ')'
|
||||
//check for player collisions in between each segment
|
||||
if (m.immuneCycle < m.cycle) {
|
||||
for (let i = 0; i < this.history.length - 1; i++) {
|
||||
if (Matter.Query.ray([player], this.history[i], this.history[i + 1], 10).length > 0) {
|
||||
m.damage(0.004 * simulation.dmgScale);
|
||||
m.immuneCycle = m.cycle + m.collisionImmuneCycles + 60
|
||||
const dmg = 0.25 * simulation.dmgScale
|
||||
m.damage(dmg);
|
||||
simulation.drawList.push({ //add dmg to draw queue
|
||||
x: m.pos.x,
|
||||
y: m.pos.y,
|
||||
radius: 30,
|
||||
radius: dmg * 1500,//30,
|
||||
color: color,
|
||||
time: 10
|
||||
time: 20
|
||||
});
|
||||
|
||||
//reset tail length for a sec to prevent repeat damage
|
||||
for (let i = 0, len = this.history.length; i < len; i++) {
|
||||
this.history[i] = { x: this.position.x, y: this.position.y }
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.nextBlinkCycle < simulation.cycle) { //teleport towards the player
|
||||
this.nextBlinkCycle = simulation.cycle + this.delay;
|
||||
if (this.isSlowed) this.nextBlinkCycle += this.delay
|
||||
if (this.isStunned) this.nextBlinkCycle += this.delay * 3
|
||||
|
||||
//custom see player by history code
|
||||
let move = (target = this.seePlayer.position) => {
|
||||
const dist = Vector.sub(target, this.position);
|
||||
|
||||
Matter.Body.translate(this, Vector.mult(Vector.normalise(dist), this.JumpDistance));
|
||||
Matter.Body.setVelocity(this, { x: 0, y: 0 });
|
||||
Matter.Body.setAngle(this, 0);
|
||||
// Matter.Body.setAngle(this, 0);
|
||||
Matter.Body.setAngularVelocity(this, 0)
|
||||
//track previous locations for the tail
|
||||
this.history.push({ x: this.position.x, y: this.position.y }) //add newest to end
|
||||
this.history.shift() //remove first (oldest)
|
||||
}
|
||||
//look for close powers up in line of sight
|
||||
//look for close power ups in line of sight
|
||||
let close = {
|
||||
dist2: Infinity,
|
||||
targetPos: null
|
||||
dist: Infinity,
|
||||
targetPos: null,
|
||||
index: null,
|
||||
}
|
||||
for (let i = 0; i < powerUp.length; i++) {
|
||||
if (Matter.Query.ray(map, this.position, powerUp[i].position).length === 0) {
|
||||
const dist = Vector.magnitudeSquared(Vector.sub(this.position, powerUp[i].position))
|
||||
if (dist < close.dist2) {
|
||||
const dist = Vector.magnitude(Vector.sub(this.position, powerUp[i].position))
|
||||
if (dist < close.dist) {
|
||||
close = {
|
||||
dist2: dist,
|
||||
// targetPos: { x: powerUp[i].position.x, y: powerUp[i].position.y }
|
||||
target: powerUp[i]
|
||||
dist: dist,
|
||||
target: powerUp[i],
|
||||
index: i,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (close.dist2 < 5000 * 5000) {
|
||||
//chase power ups
|
||||
if (close.dist < 3000) { //chase power ups if they are near
|
||||
move(close.target.position)
|
||||
|
||||
//check if close to power up and eat it
|
||||
if (close.dist2 < 200 * 200) {
|
||||
//eat power up
|
||||
if (close.dist < this.JumpDistance + 2 * this.radius) {
|
||||
this.powerUpNames.push(close.target.name) //save name to return power ups after this mob dies
|
||||
Matter.Composite.remove(engine.world, close.target);
|
||||
powerUp.splice(close.index, 1);
|
||||
this.health = 1 //heal to full
|
||||
//add more segments to tail
|
||||
if (this.history.length < 200) for (let i = 0; i < 4; i++) this.history.unshift(this.history[0])
|
||||
//draw pickup for a single cycle
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.position.x, this.position.y);
|
||||
ctx.lineTo(close.target.position.x, close.target.position.y);
|
||||
ctx.strokeStyle = "#000"
|
||||
ctx.lineWidth = 4
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
} else if (Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 && !m.isCloak) {
|
||||
//go eat blocks to heal?
|
||||
// } else if (this.health < 0.6) {
|
||||
|
||||
} else if (Matter.Query.ray(map, this.position, this.playerPosRandomY()).length === 0 && !m.isCloak) { //chase player
|
||||
this.seePlayer.yes = true;
|
||||
this.locatePlayer();
|
||||
if (!this.seePlayer.yes) this.seePlayer.yes = true;
|
||||
move()
|
||||
} else if (this.seePlayer.recall) {
|
||||
} 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
|
||||
@@ -3998,6 +4069,7 @@ const spawn = {
|
||||
if (this.invulnerableCount < 0) {
|
||||
this.isInvulnerable = false
|
||||
this.damageReduction = this.startingDamageReduction
|
||||
this.redMode()
|
||||
}
|
||||
//draw invulnerable
|
||||
ctx.beginPath();
|
||||
|
||||
@@ -8745,7 +8745,7 @@ const tech = {
|
||||
},
|
||||
{
|
||||
name: "charmed baryons",
|
||||
description: `<strong>0.66x</strong> <strong>movement</strong> and <strong>jumping</strong><br><strong class='color-worm'>wormholes</strong> cost <strong>zero</strong> <strong class='color-f'>energy</strong>`,
|
||||
description: `<strong>0.8x</strong> <strong>movement</strong> and <strong>jumping</strong><br><strong class='color-worm'>wormholes</strong> cost <strong>zero</strong> <strong class='color-f'>energy</strong>`,
|
||||
isFieldTech: true,
|
||||
maxCount: 1,
|
||||
count: 0,
|
||||
@@ -8757,8 +8757,8 @@ const tech = {
|
||||
requires: "wormhole, not affine connection",
|
||||
effect() {
|
||||
tech.isFreeWormHole = true
|
||||
tech.baseFx *= 0.66
|
||||
tech.baseJumpForce *= 0.66
|
||||
tech.baseFx *= 0.8
|
||||
tech.baseJumpForce *= 0.8
|
||||
m.setMovement()
|
||||
},
|
||||
//also removed in m.setHoldDefaults() if player switches into a bad field
|
||||
|
||||
45
todo.txt
45
todo.txt
@@ -1,29 +1,19 @@
|
||||
******************************************************** NEXT PATCH **************************************************
|
||||
|
||||
renamed MACHO -> dark matter
|
||||
tech: MACHO - dark matter is active when you are outside not inside it's range, 1.5 to dark matter effects
|
||||
tech: dark energy - inside dark matter regen 10 energy
|
||||
tech: stability - 0.3x damage taken if health equals maxHealth
|
||||
tech: instability - 2x damage if damage taken is 1x
|
||||
tech: control theory - 1.5x damage if health equals maxHealth
|
||||
tech: inertial confinement - while charging tokamak you can fly, but energy drains
|
||||
tech: stellarator - after firing a block with tokamak, spawn up to 5 heals
|
||||
snakeBoss - boss with a tail that grows longer after damage or eating power ups
|
||||
maybe have it eat blocks too?
|
||||
|
||||
boss health nerf: almost every boss has ~0.8x less health
|
||||
secondary bosses also spawn 2 ammo
|
||||
aerostat 0.85->0.9 damage on the ground
|
||||
Pauli exclusion 6->8 seconds of invulnerable after getting hit
|
||||
Gibbs free energy 2->0 research cost, 1.01->1.05 damage scales with energy below 100->maxEnergy
|
||||
cache 15->17x ammo
|
||||
trying out putting actual system error messages directly into the in-game console
|
||||
|
||||
several bug fixes
|
||||
charmed baryons: 0.66->0.8x movement
|
||||
grappling hook field: 0.6->0.5 damage taken
|
||||
|
||||
******************************************************* DESIGN ******************************************************
|
||||
|
||||
priorities
|
||||
synergies between tech
|
||||
difficult to achieve synergies that feel so powerful they are game breaking / changing
|
||||
randomized content adds repeatability
|
||||
randomized content that adds repeatability
|
||||
bosses, mobs, levels, tech
|
||||
graphical indicators of tech effects and quantity
|
||||
subtle lore woven into unexpected places
|
||||
@@ -44,19 +34,11 @@ list of powerful synergies
|
||||
|
||||
*********************************************************** TODO *****************************************************
|
||||
|
||||
snakeBoss - boss with a tail that grows longer
|
||||
improve behavior for when it can't see player
|
||||
wander around looking for power ups
|
||||
what if it gets lost?
|
||||
eat power ups
|
||||
eject them after you die
|
||||
get longer after eating
|
||||
eat mobs?
|
||||
eat blocks?
|
||||
modes: recolor tail based on modes
|
||||
hunting power ups -> small + fast : blue cyan
|
||||
hunting player -> attack? : red/pink
|
||||
slow high defense : white
|
||||
merge multiple power ups of the same type if nearby
|
||||
5-10 ammo, research, coupling can merge to form a slightly larger power up version
|
||||
check for merger possibility every 60 seconds?
|
||||
adjust mass spawns to just spawn larger power ups versions and change?
|
||||
spawnDelay
|
||||
|
||||
white laser
|
||||
what to name? not much in wikipedia
|
||||
@@ -71,6 +53,9 @@ tech: atomic pile - lose 1 health if you are above the maximum energy
|
||||
do damage?
|
||||
plasma torch tech?
|
||||
|
||||
field tech: molecular assembler - every time you spawn a drone/spore/... become immune to damage for time
|
||||
scales with how much energy was used to spawn drone/...
|
||||
|
||||
make some explosions have less knock back?
|
||||
annoying with flame test, boom bot?
|
||||
|
||||
@@ -1282,7 +1267,7 @@ possible names for tech
|
||||
Josephson junction - superconducting junction
|
||||
Pyroelectricity - voltage from temp changes - upgrade from piezoelectricity
|
||||
Unruh effect - accelerating makes heat/thermal particles
|
||||
configuration space - holds the position of everything
|
||||
configuration space - holds the position of everything (related to fermions/bosons and particle interactions)
|
||||
stress–energy tensor
|
||||
radioisotope thermoelectric generator -
|
||||
retrovirus: these things make JUNK DNA so link it somehow to that tech?
|
||||
|
||||
Reference in New Issue
Block a user