electric tower chains properly

This commit is contained in:
koneko 2025-02-17 11:49:44 +01:00
parent f84108847b
commit 9d998a45e1
9 changed files with 98 additions and 125 deletions

View File

@ -8,7 +8,7 @@
"textures": [], "textures": [],
"cantCombineWith": [], "cantCombineWith": [],
"specialCombine": [], "specialCombine": [],
"initialGemValue": 10, "initialGemValue": 100,
"genericImprovements": [ "genericImprovements": [
{ {
"damageUp": 2, "damageUp": 2,
@ -16,7 +16,7 @@
"rangeUp": 0, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 0 "gemValueUp": 50
}, },
{ {
"damageUp": 2, "damageUp": 2,
@ -24,14 +24,14 @@
"rangeUp": 0, "rangeUp": 0,
"timeToLiveUp": 0, "timeToLiveUp": 0,
"pierceUp": 1, "pierceUp": 1,
"gemValueUp": 10 "gemValueUp": 100
} }
], ],
"gemResistanceModifications": [ "gemResistanceModifications": [
{ {
"physical": 0, "physical": 0,
"divine": 0, "divine": 0,
"fire": 0.25, "fire": 0.1,
"ice": 0, "ice": 0,
"frostfire": 0 "frostfire": 0
}, },

View File

@ -10,12 +10,12 @@
"description": "The building block of society, nothing more basic exists.", "description": "The building block of society, nothing more basic exists.",
"stats": { "stats": {
"damage": 2, "damage": 2,
"cooldown": 2000, "cooldown": 1500,
"gemSlotsAmount": 2, "gemSlotsAmount": 1,
"cost": 100, "cost": 50,
"range": 4, "range": 3,
"timeToLive": 20, "timeToLive": 20,
"pierce": 1 "pierce": 2
} }
}, },
{ {
@ -28,10 +28,10 @@
"projectileTexturesArrayLength": 4, "projectileTexturesArrayLength": 4,
"description": "If you feel a little circular.", "description": "If you feel a little circular.",
"stats": { "stats": {
"damage": 2, "damage": 3,
"cooldown": 2000, "cooldown": 4000,
"gemSlotsAmount": 3, "gemSlotsAmount": 2,
"cost": 125, "cost": 100,
"range": 2.5, "range": 2.5,
"timeToLive": 12, "timeToLive": 12,
"pierce": 30 "pierce": 30
@ -45,15 +45,15 @@
"projectile": "yellow", "projectile": "yellow",
"projectileTextures": [], "projectileTextures": [],
"projectileTexturesArrayLength": 4, "projectileTexturesArrayLength": 4,
"description": "Think of something", "description": "Zap zap zap!",
"stats": { "stats": {
"damage": 2, "damage": 3,
"cooldown": 2000, "cooldown": 3500,
"gemSlotsAmount": 3, "gemSlotsAmount": 2,
"cost": 125, "cost": 150,
"range": 2.5, "range": 3,
"timeToLive": 12, "timeToLive": 12,
"pierce": 30 "pierce": 10
} }
}, },
{ {
@ -66,13 +66,13 @@
"projectileTexturesArrayLength": 4, "projectileTexturesArrayLength": 4,
"description": "", "description": "",
"stats": { "stats": {
"damage": 2, "damage": 4,
"cooldown": 2000, "cooldown": 1000,
"gemSlotsAmount": 3, "gemSlotsAmount": 3,
"cost": 125, "cost": 200,
"range": 2.5, "range": 2,
"timeToLive": 12, "timeToLive": 15,
"pierce": 30 "pierce": 5
} }
}, },
{ {

View File

@ -98,8 +98,8 @@
"waves": [ "waves": [
{ {
"firstCreepSpawnTick": 500, "firstCreepSpawnTick": 500,
"spawnIntervalTicks": 1000, "spawnIntervalTicks": 500,
"creeps": [0, 0, 0, 0, 0] "creeps": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 2]
} }
], ],
"offeredGems": [0, 0, 0, 0] "offeredGems": [0, 0, 0, 0]
@ -109,10 +109,35 @@
{ {
"firstCreepSpawnTick": 500, "firstCreepSpawnTick": 500,
"spawnIntervalTicks": 1000, "spawnIntervalTicks": 1000,
"creeps": [1, 1, 1, 1, 1] "creeps": [0, 0, 1, 1, 1, 4, 5, 5, 5, 1, 1, 0, 0]
} }
], ],
"offeredGems": [0, 1, 2, 3] "offeredGems": [1, 1, 1, 0]
},
{
"waves": [
{
"firstCreepSpawnTick": 500,
"spawnIntervalTicks": 1000,
"creeps": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
},
{
"firstCreepSpawnTick": 500,
"spawnIntervalTicks": 500,
"creeps": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
],
"offeredGems": [0, 2, 2, 3]
},
{
"waves": [
{
"firstCreepSpawnTick": 500,
"spawnIntervalTicks": 100,
"creeps": [1, 1, 1, 1, 1, 1, 1, 1, 1]
}
],
"offeredGems": [0, 2, 2, 3]
}, },
{ {
"waves": [ "waves": [
@ -122,7 +147,7 @@
"creeps": [2, 2, 2, 2, 2] "creeps": [2, 2, 2, 2, 2]
} }
], ],
"offeredGems": [0, 1, 2, 3] "offeredGems": [0, 1, 3, 3]
} }
] ]
} }

View File

@ -76,7 +76,6 @@ export class Cell extends GameObject {
this.hasTowerPlaced = false; this.hasTowerPlaced = false;
Engine.Grid.rangePreview.clear(); Engine.Grid.rangePreview.clear();
} else if (towerName == GameAssets.Towers[TowerType.Buff].name) { } else if (towerName == GameAssets.Towers[TowerType.Buff].name) {
console.log('TRIpped!');
let twr = Engine.TowerManager.GetTowerByRowAndCol(row, col); let twr = Engine.TowerManager.GetTowerByRowAndCol(row, col);
if (Engine.Grid.IsCellInRangeOfOtherCell(row, col, twr.computedRange, this)) { if (Engine.Grid.IsCellInRangeOfOtherCell(row, col, twr.computedRange, this)) {
console.log('REMOVED!'); console.log('REMOVED!');
@ -86,59 +85,16 @@ export class Cell extends GameObject {
} }
}); });
// Disable this if you want to add new maps. // See commit f84108847b6ba6c337954a742f4dc1a38a2c925b
if (true) return;
const text = new PIXI.Text({
text: `${this.column}|${this.row}`,
style: new PIXI.TextStyle({
fill: 0xffffff,
fontSize: 16,
stroke: {
color: 0x000000,
width: 2,
},
}),
});
this.container.addChild(text);
text.anchor.set(0.5, 0.5);
text.x = this.bb.width / 2;
text.y = this.bb.height / 2;
if (this.type == TerrainType.Path) {
text.style.fill = 'green';
text.style.fontWeight = 'bold';
}
if (this.type == TerrainType.Restricted) {
text.style.fill = 'gold';
}
this.clickDetector.on('pointerup', () => {
const cellIndex = genPath.findIndex(([col, row]) => col === this.column && row === this.row);
if (cellIndex !== -1) {
text.style.fill = 0xffffff;
genPath.splice(cellIndex, 1);
} else {
text.style.fill = 0xff0000;
genPath.push([this.column, this.row]);
}
console.log('updated gen path');
console.log(JSON.stringify(genPath));
});
} }
public showRangePreview(invalid, range) { public showRangePreview(invalid, range) {
let color = 0xffffff; let color = 0xffffff;
if (invalid) color = 0xff0000; if (invalid) color = 0xff0000;
Engine.Grid.rangePreview.clear(); Engine.Grid.rangePreview.clear();
console.log( Engine.Grid.rangePreview.circle(
`Showing range preview ${this.column * Engine.GridCellSize + Engine.GridCellSize / 2}x - ${ this.column * Engine.GridCellSize + Engine.GridCellSize / 2,
this.row * Engine.GridCellSize + Engine.GridCellSize / 2 this.row * Engine.GridCellSize + Engine.GridCellSize / 2,
}y` range * Engine.GridCellSize
);
console.log(
Engine.Grid.rangePreview.circle(
this.column * Engine.GridCellSize + Engine.GridCellSize / 2,
this.row * Engine.GridCellSize + Engine.GridCellSize / 2,
range * Engine.GridCellSize
)
); );
Engine.Grid.rangePreview.fill({ color: color, alpha: 0.3 }); Engine.Grid.rangePreview.fill({ color: color, alpha: 0.3 });
} }

View File

@ -49,7 +49,7 @@ export default class Projectile extends GameObject {
this.sprite.play(); this.sprite.play();
this.container.x = this.x; this.container.x = this.x;
this.container.y = this.y; this.container.y = this.y;
this.sprite.tint = tint; // this.sprite.tint = tint;
this.container.addChild(this.sprite); this.container.addChild(this.sprite);
Engine.GameMaster.currentScene.stage.addChild(this.container); Engine.GameMaster.currentScene.stage.addChild(this.container);

View File

@ -1,11 +1,10 @@
import { Engine } from '../Bastion'; import { Engine } from '../Bastion';
import * as PIXI from 'pixi.js'; import * as PIXI from 'pixi.js';
import GameObject from '../GameObject'; import GameObject from '../GameObject';
import { CreepResistancesDefinition, GemType, TowerDefinition } from '../Definitions'; import { CreepResistancesDefinition, TowerDefinition } from '../Definitions';
import { Cell } from './Grid'; import { Cell } from './Grid';
import { TowerBehaviours } from './TowerManager'; import { TowerBehaviours } from './TowerManager';
import Projectile, { calculateAngleToPoint } from './Projectile'; import Projectile from './Projectile';
import Creep from './Creep';
import Gem from './Gem'; import Gem from './Gem';
import { import {
DebuffTowerBehaviour, DebuffTowerBehaviour,
@ -145,13 +144,13 @@ export class Tower extends GameObject {
this.totalGemResistanceModifications this.totalGemResistanceModifications
); );
const time = new Date().toISOString(); const time = new Date().toISOString();
console.log(`${time} ${this.definition.name} shot at ${angle} degrees`); // console.log(`${time} ${this.definition.name} shot at ${angle} degrees`);
this.projectiles.push(proj); this.projectiles.push(proj);
return proj; return proj;
} }
public Sell() { public Sell() {
this.setAsSold = true;
// Selling logic is handled in TowerManager.update() // Selling logic is handled in TowerManager.update()
this.setAsSold = true;
} }
public update(elapsedMS: any): void { public update(elapsedMS: any): void {
if (this.sold) return; if (this.sold) return;

View File

@ -73,11 +73,11 @@ export function computeGemImprovements(tower: Tower) {
// Buff tower // Buff tower
if (tower.parent.isBuffedBy.length > 0 && tower.definition.name != GameAssets.Towers[TowerType.Buff].name) { if (tower.parent.isBuffedBy.length > 0 && tower.definition.name != GameAssets.Towers[TowerType.Buff].name) {
let buffedBy = tower.parent.isBuffedBy[0]; let buffedBy = tower.parent.isBuffedBy[0];
tower.computedDamageToDeal += Math.ceil(buffedBy.computedDamageToDeal / 3); tower.computedDamageToDeal += Number((buffedBy.computedDamageToDeal / 2).toFixed(1));
tower.computedCooldown -= Math.ceil(buffedBy.computedCooldown / 5); tower.computedCooldown -= (buffedBy.computedCooldown * 100) / 5 / 100;
tower.computedRange += Math.ceil(buffedBy.computedRange / 10); tower.computedRange += Number((buffedBy.computedRange / 10).toFixed(1));
tower.computedTimeToLive += Math.ceil(buffedBy.computedTimeToLive / 5); tower.computedTimeToLive += (buffedBy.computedTimeToLive * 100) / 5 / 100;
tower.computedPierce += Math.ceil(buffedBy.computedPierce / 4); tower.computedPierce += (buffedBy.computedPierce * 100) / 4 / 100;
tower.totalGemResistanceModifications.physical += tower.totalGemResistanceModifications.physical +=
(buffedBy.totalGemResistanceModifications.physical * 100) / 2 / 100; (buffedBy.totalGemResistanceModifications.physical * 100) / 2 / 100;
@ -147,25 +147,32 @@ export function ElectricTowerBehaviour(tower: Tower, elapsedMS: number) {
tower.millisecondsUntilNextShot = tower.computedCooldown; tower.millisecondsUntilNextShot = tower.computedCooldown;
let proj = tower.Shoot(calculateAngleToPoint(x, y, focus.x, focus.y)); let proj = tower.Shoot(calculateAngleToPoint(x, y, focus.x, focus.y));
proj.onCollide = (creep: Creep, proj: Projectile) => { proj.onCollide = (creep: Creep, proj: Projectile) => {
let chainedCreepIds = [];
proj.pierce = 0; proj.pierce = 0;
let nearByCreeps = Engine.Grid.creeps.filter((nCreep) => { function checkNearBy(c) {
if (nCreep.id != creep.id) { let nearByCreeps = Engine.Grid.creeps.filter((nCreep) => {
const x = nCreep.x; if (nCreep.id != creep.id) {
const y = nCreep.y; const x = nCreep.x;
const radius = 3.5 * Engine.GridCellSize; const y = nCreep.y;
const d = distance(creep.x, creep.y, x, y); const radius = 1.5 * Engine.GridCellSize;
return d < radius; const d = distance(c.x, c.y, x, y);
} return d < radius;
}); }
nearByCreeps.forEach((nearCreep) => { });
new VisualLightning(creep, nearCreep); nearByCreeps.forEach((nearCreep) => {
Engine.GameScene.events.emit( if (!chainedCreepIds.find((crID) => crID == nearCreep.id)) chainedCreepIds.push(nearCreep.id);
CreepEvents.TakenDamage, else return;
nearCreep.id, checkNearBy(nearCreep);
proj.damage / 2, new VisualLightning(c, nearCreep);
proj.gemResistanceModifications Engine.GameScene.events.emit(
); CreepEvents.TakenDamage,
}); nearCreep.id,
Math.round(proj.damage / 2),
proj.gemResistanceModifications
);
});
}
checkNearBy(creep);
Engine.GameScene.events.emit( Engine.GameScene.events.emit(
CreepEvents.TakenDamage, CreepEvents.TakenDamage,
creep.id, creep.id,
@ -226,16 +233,6 @@ export function TrapperTowerBehaviour(tower: Tower, elapsedMS: number) {
if (tower.millisecondsUntilNextShot > 0) if (tower.millisecondsUntilNextShot > 0)
tower.millisecondsUntilNextShot -= elapsedMS * Engine.GameScene.gameSpeedMultiplier; tower.millisecondsUntilNextShot -= elapsedMS * Engine.GameScene.gameSpeedMultiplier;
let creepsInRange = tower.GetCreepsInRange();
if (creepsInRange.length > 0) {
let focus = creepsInRange[0];
if (tower.millisecondsUntilNextShot <= 0) {
let x = tower.column * Engine.GridCellSize + Engine.GridCellSize / 2;
let y = tower.row * Engine.GridCellSize + Engine.GridCellSize / 2;
tower.millisecondsUntilNextShot = tower.computedCooldown;
tower.Shoot(calculateAngleToPoint(x, y, focus.x, focus.y));
}
}
} }
export function DebuffTowerBehaviour(tower: Tower, elapsedMS: number) { export function DebuffTowerBehaviour(tower: Tower, elapsedMS: number) {

View File

@ -2,7 +2,7 @@ import * as PIXI from 'pixi.js';
import { Engine } from '../Bastion'; import { Engine } from '../Bastion';
import { TerrainType, TowerDefinition } from '../Definitions'; import { TerrainType, TowerDefinition } from '../Definitions';
import GameAssets from '../Assets'; import GameAssets from '../Assets';
import { distance, Tower } from './Tower'; import { Tower } from './Tower';
import { Cell } from './Grid'; import { Cell } from './Grid';
import { GridEvents, TowerEvents } from '../Events'; import { GridEvents, TowerEvents } from '../Events';
@ -93,7 +93,6 @@ export default class TowerManager {
this.towers.forEach((tower) => { this.towers.forEach((tower) => {
if (tower.row == row && tower.column == col) returnTower = tower; if (tower.row == row && tower.column == col) returnTower = tower;
}); });
// console.log(returnTower, row, col);
return returnTower; return returnTower;
} }
public PlaceTower(definition: TowerDefinition, row, column, behaviour: string, ignoreCost?) { public PlaceTower(definition: TowerDefinition, row, column, behaviour: string, ignoreCost?) {
@ -117,7 +116,6 @@ export default class TowerManager {
'Can not place tower on path or other tower, choose another spot.', 'Can not place tower on path or other tower, choose another spot.',
'warn' 'warn'
); );
console.warn('Can not place tower on occupied spot or path. Try again.');
} }
} }
public update(elapsedMS) { public update(elapsedMS) {

View File

@ -44,7 +44,7 @@ import DebrisManager from './classes/game/DebrisManager';
app.canvas.style.marginBottom = `0`; app.canvas.style.marginBottom = `0`;
app.canvas.style.display = 'block'; app.canvas.style.display = 'block';
} }
Engine.latestCommit = await fetch('/latest_commit').then((res) => res.text()); Engine.latestCommit = await fetch('./latest_commit').then((res) => res.text());
window.addEventListener('resize', resize); window.addEventListener('resize', resize);
resize(); resize();
@ -78,14 +78,12 @@ import DebrisManager from './classes/game/DebrisManager';
let gamePausedDueToBlur = false; let gamePausedDueToBlur = false;
window.addEventListener('blur', () => { window.addEventListener('blur', () => {
console.log('blur');
if (Engine.GameScene && !Engine.GameScene.isPaused) { if (Engine.GameScene && !Engine.GameScene.isPaused) {
Engine.GameScene.PauseGame(); Engine.GameScene.PauseGame();
gamePausedDueToBlur = true; gamePausedDueToBlur = true;
} }
}); });
window.addEventListener('focus', () => { window.addEventListener('focus', () => {
console.log('focus');
if (Engine.GameScene && gamePausedDueToBlur && Engine.GameScene.isPaused) { if (Engine.GameScene && gamePausedDueToBlur && Engine.GameScene.isPaused) {
gamePausedDueToBlur = false; gamePausedDueToBlur = false;
Engine.GameScene.UnpauseGame(); Engine.GameScene.UnpauseGame();