From f84108847b6ba6c337954a742f4dc1a38a2c925b Mon Sep 17 00:00:00 2001 From: koneko <67551503+koneko@users.noreply.github.com> Date: Sun, 16 Feb 2025 23:15:46 +0100 Subject: [PATCH] implement electric tower and buff tower --- public/assets/json/Towers.json | 12 +- public/assets/projectiles/lightning/0.png | Bin 0 -> 3050 bytes public/assets/projectiles/lightning/1.png | Bin 0 -> 3110 bytes public/assets/projectiles/lightning/2.png | Bin 0 -> 3077 bytes public/assets/projectiles/lightning/3.png | Bin 0 -> 3097 bytes .../{quick_tower.png => buff_tower.png} | Bin .../{advanced_tower.png => debuff_tower.png} | Bin public/assets/towers/electric_tower.png | Bin 7704 -> 7418 bytes src/classes/Assets.ts | 4 + src/classes/Bastion.ts | 5 +- src/classes/Definitions.ts | 4 +- src/classes/game/DebrisManager.ts | 41 +++++++ src/classes/game/Grid.ts | 48 ++++++-- src/classes/game/Projectile.ts | 49 +++++++- src/classes/game/Tower.ts | 28 +++-- src/classes/game/TowerBehaviours.ts | 113 ++++++++++++------ src/classes/game/TowerManager.ts | 8 +- src/main.ts | 4 +- 18 files changed, 241 insertions(+), 75 deletions(-) create mode 100644 public/assets/projectiles/lightning/0.png create mode 100644 public/assets/projectiles/lightning/1.png create mode 100644 public/assets/projectiles/lightning/2.png create mode 100644 public/assets/projectiles/lightning/3.png rename public/assets/towers/{quick_tower.png => buff_tower.png} (100%) rename public/assets/towers/{advanced_tower.png => debuff_tower.png} (100%) create mode 100644 src/classes/game/DebrisManager.ts diff --git a/public/assets/json/Towers.json b/public/assets/json/Towers.json index 82a558e..9e1d93c 100644 --- a/public/assets/json/Towers.json +++ b/public/assets/json/Towers.json @@ -57,9 +57,9 @@ } }, { - "name": "Quick Tower", - "behaviour": "QuickTowerBehaviour", - "sprite": "quick_tower", + "name": "Buff Tower", + "behaviour": "BuffTowerBehaviour", + "sprite": "buff_tower", "texture": null, "projectile": "blue", "projectileTextures": [], @@ -133,9 +133,9 @@ } }, { - "name": "Advanced Tower", - "behaviour": "AdvancedTowerBehaviour", - "sprite": "advanced_tower", + "name": "Debuff Tower", + "behaviour": "DebuffTowerBehaviour", + "sprite": "debuff_tower", "texture": null, "projectile": "red", "projectileTextures": [], diff --git a/public/assets/projectiles/lightning/0.png b/public/assets/projectiles/lightning/0.png new file mode 100644 index 0000000000000000000000000000000000000000..5dcca961aa08cf50a820a0bedff1a05d242a43f0 GIT binary patch literal 3050 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 literal 0 HcmV?d00001 diff --git a/public/assets/projectiles/lightning/1.png b/public/assets/projectiles/lightning/1.png new file mode 100644 index 0000000000000000000000000000000000000000..f9e06a2edb07f1e73c50ceb00ab69c80d5e7f2e2 GIT binary patch literal 3110 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 AC;$Ke literal 0 HcmV?d00001 diff --git a/public/assets/projectiles/lightning/2.png b/public/assets/projectiles/lightning/2.png new file mode 100644 index 0000000000000000000000000000000000000000..b43f8de9857819dea1f1b990bd952a8fb89286d2 GIT binary patch literal 3077 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 T8V+of00000NkvXXu0mjfTIdGV literal 0 HcmV?d00001 diff --git a/public/assets/projectiles/lightning/3.png b/public/assets/projectiles/lightning/3.png new file mode 100644 index 0000000000000000000000000000000000000000..4a1e18a6ce0c0f3b811832094baead6a30d0176b GIT binary patch literal 3097 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 literal 0 HcmV?d00001 diff --git a/public/assets/towers/quick_tower.png b/public/assets/towers/buff_tower.png similarity index 100% rename from public/assets/towers/quick_tower.png rename to public/assets/towers/buff_tower.png diff --git a/public/assets/towers/advanced_tower.png b/public/assets/towers/debuff_tower.png similarity index 100% rename from public/assets/towers/advanced_tower.png rename to public/assets/towers/debuff_tower.png diff --git a/public/assets/towers/electric_tower.png b/public/assets/towers/electric_tower.png index fb788c7e17fac5136ecc2f6146776ddf9fa2fca0..072dec40754b41ee475dcba32065aa2dad7ccdb0 100644 GIT binary patch literal 7418 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 literal 7704 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 S1L%JM0000= 0; idx--) { + const db = this.debris[idx]; + if (this.ticks >= db.ticksToDestroyAt) { + db.destroy(); + this.debris.splice(idx, 1); + } else { + db.update(elapsedMS); + } + } + } + public CreateDebris(affectedObject: Container | GameObject, ticksToDestroyAt?: number) { + if (!ticksToDestroyAt) ticksToDestroyAt = 120; + this.debris.push(new Debris(affectedObject, this.ticks + ticksToDestroyAt)); + } +} diff --git a/src/classes/game/Grid.ts b/src/classes/game/Grid.ts index ccd3e95..af0635d 100644 --- a/src/classes/game/Grid.ts +++ b/src/classes/game/Grid.ts @@ -1,10 +1,11 @@ import * as PIXI from 'pixi.js'; import GameObject from '../GameObject'; -import { GameMapDefinition, TerrainType } from '../Definitions'; +import { GameMapDefinition, TerrainType, TowerType } from '../Definitions'; import GameAssets from '../Assets'; import { Engine } from '../Bastion'; import Creep from './Creep'; import { CreepEvents, TowerEvents, GridEvents } from '../Events'; +import { distance, Tower } from './Tower'; let genPath = []; @@ -15,6 +16,7 @@ export class Cell extends GameObject { public isPath: boolean = false; public g: PIXI.Graphics; public hasTowerPlaced: boolean = false; + public isBuffedBy: Tower[] = []; public clickDetector: PIXI.Graphics; constructor(type: TerrainType, row: number, column: number, isPath: boolean) { @@ -55,19 +57,32 @@ export class Cell extends GameObject { this.clickDetector.on('pointerleave', (e) => { if (!Engine.Grid.gridInteractionEnabled || Engine.GameScene.towerPanel.isShown) return; Engine.GameScene.events.emit(GridEvents.CellMouseLeave, this); - Engine.Grid.rangePreview.clear(); }); - Engine.GameScene.events.on(TowerEvents.TowerPlacedEvent, (_, row, col) => { + Engine.GameScene.events.on(TowerEvents.TowerPlacedEvent, (towerName, row, col) => { if (row == this.row && col == this.column) { this.hasTowerPlaced = true; Engine.Grid.rangePreview.clear(); + } else if (towerName == GameAssets.Towers[TowerType.Buff].name) { + let twr = Engine.TowerManager.GetTowerByRowAndCol(row, col); + if (Engine.Grid.IsCellInRangeOfOtherCell(row, col, twr.computedRange, this)) { + this.isBuffedBy.push(twr); + } } }); - Engine.GameScene.events.on(TowerEvents.TowerSoldEvent, (_, row, col) => { + Engine.GameScene.events.on(TowerEvents.TowerSoldEvent, (towerName, row, col) => { + console.log(towerName, row, col); if (row == this.row && col == this.column) { this.hasTowerPlaced = false; Engine.Grid.rangePreview.clear(); + } else if (towerName == GameAssets.Towers[TowerType.Buff].name) { + console.log('TRIpped!'); + let twr = Engine.TowerManager.GetTowerByRowAndCol(row, col); + if (Engine.Grid.IsCellInRangeOfOtherCell(row, col, twr.computedRange, this)) { + console.log('REMOVED!'); + this.isBuffedBy.splice(this.isBuffedBy.indexOf(twr), 1); + console.log(this.isBuffedBy); + } } }); @@ -118,10 +133,12 @@ export class Cell extends GameObject { this.row * Engine.GridCellSize + Engine.GridCellSize / 2 }y` ); - Engine.Grid.rangePreview.circle( - this.column * Engine.GridCellSize + Engine.GridCellSize / 2, - this.row * Engine.GridCellSize + Engine.GridCellSize / 2, - 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 }); } @@ -187,6 +204,10 @@ export class Grid extends GameObject { } this.rangePreview = new PIXI.Graphics({ zIndex: 10, + x: 0, + y: 0, + width: Engine.app.canvas.width, + height: Engine.app.canvas.height, }); this.container.addChild(this.rangePreview); } @@ -216,6 +237,17 @@ export class Grid extends GameObject { console.log(JSON.stringify(newGrid)); } + + public IsCellInRangeOfOtherCell(row, col, range, otherCell) { + range = range * Engine.GridCellSize; + const x = otherCell.column * Engine.GridCellSize + Engine.GridCellSize / 2; + const y = otherCell.row * Engine.GridCellSize + Engine.GridCellSize / 2; + const cellX = col * Engine.GridCellSize + Engine.GridCellSize / 2; + const cellY = row * Engine.GridCellSize + Engine.GridCellSize / 2; + const d = distance(cellX, cellY, x, y); + if (d < range + Engine.GridCellSize / 2) return true; + else return false; + } public toggleGrid(force?: 'hide' | 'show') { this.cells.forEach((cell) => { if (force) { diff --git a/src/classes/game/Projectile.ts b/src/classes/game/Projectile.ts index 210d257..e8f5cd8 100644 --- a/src/classes/game/Projectile.ts +++ b/src/classes/game/Projectile.ts @@ -3,8 +3,9 @@ import GameObject from '../GameObject'; import { Engine } from '../Bastion'; import Creep from './Creep'; import { CreepEvents } from '../Events'; -import { Tower } from './Tower'; +import { distance, Tower } from './Tower'; import { CreepResistancesDefinition } from '../Definitions'; +import GameAssets from '../Assets'; export function calculateAngleToPoint(x, y, targetX, targetY) { const dx = targetX - x; @@ -55,6 +56,7 @@ export default class Projectile extends GameObject { this.angle = angle; this.speed = 0.9; } + public destroy(): void { super.destroy(); this.deleteMe = true; @@ -72,7 +74,7 @@ export default class Projectile extends GameObject { if (!exists) { this.collidedCreepIDs.push(creep); this.pierce--; - this.onCollide(creep); + this.onCollide(creep, this); return; } } @@ -84,14 +86,14 @@ export default class Projectile extends GameObject { this.container.y = this.y; } - public onCollide(creep) { + public onCollide(creep, proj) { /* Note: Right now it is possible for the bullet to 'overshoot' the creep if the bullet speed is too fast and the position is updated so that the new position is beyond the creep (i.e. the bullet is never 'in the creep'). This should be fixed so that we calculate the hit if the creep is in a line from the previous position to the new position. */ - Engine.GameScene.events.emit(CreepEvents.TakenDamage, creep.id, this.damage, this.gemResistanceModifications); + Engine.GameScene.events.emit(CreepEvents.TakenDamage, creep.id, proj.damage, proj.gemResistanceModifications); } public checkCollision(creep: Creep) { @@ -102,3 +104,42 @@ export default class Projectile extends GameObject { return mybb.getBounds().intersects(otherbb.getBounds()); } } + +export class VisualLightning extends GameObject { + public deleteMe: boolean = false; + private c: Creep; + private oc: Creep; + private Lightning: PIXI.AnimatedSprite; + constructor(creep: Creep, otherCreep: Creep) { + super(); + this.c = creep; + this.oc = otherCreep; + let lightningAngle = calculateAngleToPoint(creep.x, creep.y, otherCreep.x, otherCreep.y); + this.Lightning = new PIXI.AnimatedSprite({ + textures: GameAssets.SpecialLightning, + x: creep.x, + y: creep.y, + width: distance(this.c.x, this.c.y, this.oc.x, this.oc.y), + height: 64, + scale: 1.2, + rotation: lightningAngle, + }); + this.Lightning.anchor.set(0, 0.5); + this.Lightning.play(); + Engine.GameMaster.currentScene.stage.addChild(this.Lightning); + Engine.DebrisManager.CreateDebris(this, 30); + } + public destroy(): void { + this.deleteMe = true; + this.container.destroy(); + this.Lightning.destroy(); + } + public update() { + if (this.deleteMe) { + return; + } + this.Lightning.x = this.c.x; + this.Lightning.y = this.c.y; + this.Lightning.width = distance(this.c.x, this.c.y, this.oc.x, this.oc.y); + } +} diff --git a/src/classes/game/Tower.ts b/src/classes/game/Tower.ts index b9f6d45..ae6384c 100644 --- a/src/classes/game/Tower.ts +++ b/src/classes/game/Tower.ts @@ -8,11 +8,11 @@ import Projectile, { calculateAngleToPoint } from './Projectile'; import Creep from './Creep'; import Gem from './Gem'; import { - AdvancedTowerBehaviour, + DebuffTowerBehaviour, BasicTowerBehaviour, CircleTowerBehaviour, ElectricTowerBehaviour, - QuickTowerBehaviour, + BuffTowerBehaviour, RailTowerBehaviour, StrongTowerBehaviour, TrapperTowerBehaviour, @@ -35,12 +35,18 @@ export class Tower extends GameObject { public sprite: PIXI.Sprite; public millisecondsUntilNextShot: number; public graphics: PIXI.Graphics = new PIXI.Graphics(); - public computedDamageToDeal: number; - public computedCooldown: number; - public computedRange: number; - public computedTimeToLive: number; - public computedPierce: number; - public totalGemResistanceModifications: CreepResistancesDefinition; + public computedDamageToDeal: number = 0; + public computedCooldown: number = 0; + public computedRange: number = 0; + public computedTimeToLive: number = 0; + public computedPierce: number = 0; + public totalGemResistanceModifications: CreepResistancesDefinition = { + fire: 0, + frostfire: 0, + divine: 0, + ice: 0, + physical: 0, + }; public parent: Cell; constructor(row, column, texture, definition, behaviour) { @@ -59,6 +65,7 @@ export class Tower extends GameObject { }); this.container.addChild(this.sprite); this.computedDamageToDeal = this.definition.stats.damage; + this.computedRange = this.definition.stats.range; this.parent.container.addChild(this.container); this.container.interactiveChildren = true; this.parent.clickDetector.on('pointerenter', this.onParentCellEnter); @@ -113,6 +120,7 @@ export class Tower extends GameObject { return d < radius + (Engine.GridCellSize * 2) / 3; }); } + public Shoot(angle) { let x = this.column * Engine.GridCellSize + Engine.GridCellSize / 2; let y = this.row * Engine.GridCellSize + Engine.GridCellSize / 2; @@ -153,11 +161,11 @@ export class Tower extends GameObject { if (this.behaviour == TowerBehaviours.BasicTowerBehaviour) BasicTowerBehaviour(this, elapsedMS); if (this.behaviour == TowerBehaviours.CircleTowerBehaviour) CircleTowerBehaviour(this, elapsedMS); if (this.behaviour == TowerBehaviours.ElectricTowerBehaviour) ElectricTowerBehaviour(this, elapsedMS); - if (this.behaviour == TowerBehaviours.QuickTowerBehaviour) QuickTowerBehaviour(this, elapsedMS); + if (this.behaviour == TowerBehaviours.BuffTowerBehaviour) BuffTowerBehaviour(this, elapsedMS); if (this.behaviour == TowerBehaviours.StrongTowerBehaviour) StrongTowerBehaviour(this, elapsedMS); if (this.behaviour == TowerBehaviours.RailTowerBehaviour) RailTowerBehaviour(this, elapsedMS); if (this.behaviour == TowerBehaviours.TrapperTowerBehaviour) TrapperTowerBehaviour(this, elapsedMS); - if (this.behaviour == TowerBehaviours.AdvancedTowerBehaviour) AdvancedTowerBehaviour(this, elapsedMS); + if (this.behaviour == TowerBehaviours.DebuffTowerBehaviour) DebuffTowerBehaviour(this, elapsedMS); } public destroy(): void { diff --git a/src/classes/game/TowerBehaviours.ts b/src/classes/game/TowerBehaviours.ts index 435739a..63fa894 100644 --- a/src/classes/game/TowerBehaviours.ts +++ b/src/classes/game/TowerBehaviours.ts @@ -1,6 +1,11 @@ +import GameAssets from '../Assets'; import { Engine } from '../Bastion'; -import { calculateAngleToPoint } from './Projectile'; -import { Tower } from './Tower'; +import { TowerType } from '../Definitions'; +import { CreepEvents } from '../Events'; +import Creep from './Creep'; +import Projectile, { calculateAngleToPoint, VisualLightning } from './Projectile'; +import { distance, Tower } from './Tower'; +import * as PIXI from 'pixi.js'; /** * Checks the projectiles of the tower and updates or removes them based on their state. @@ -44,34 +49,47 @@ export function computeGemImprovements(tower: Tower) { physical: 0, }; tower.slottedGems.forEach((gem) => { - let ccurrentGemImprovements = gem.currentGemImprovement(); - gemDamage += ccurrentGemImprovements.damageUp; - gemAttackSpeedUp += ccurrentGemImprovements.attackSpeedUp; - gemRangeUp += ccurrentGemImprovements.rangeUp; - gemTimeToLiveUp += ccurrentGemImprovements.timeToLiveUp; - gemPierceUp += ccurrentGemImprovements.pierceUp; + let improvements = gem.currentGemImprovement(); + gemDamage += improvements.damageUp; + gemAttackSpeedUp += improvements.attackSpeedUp; + gemRangeUp += improvements.rangeUp; + gemTimeToLiveUp += improvements.timeToLiveUp; + gemPierceUp += improvements.pierceUp; - let gemResMod = gem.currentGemResistanceModifications(); - tower.totalGemResistanceModifications.physical += gemResMod.physical; - tower.totalGemResistanceModifications.ice += gemResMod.ice; - tower.totalGemResistanceModifications.fire += gemResMod.fire; - tower.totalGemResistanceModifications.divine += gemResMod.divine; - tower.totalGemResistanceModifications.frostfire += gemResMod.frostfire; + let resistances = gem.currentGemResistanceModifications(); + tower.totalGemResistanceModifications.physical += resistances.physical; + tower.totalGemResistanceModifications.ice += resistances.ice; + tower.totalGemResistanceModifications.fire += resistances.fire; + tower.totalGemResistanceModifications.divine += resistances.divine; + tower.totalGemResistanceModifications.frostfire += resistances.frostfire; }); + tower.computedDamageToDeal = tower.definition.stats.damage + gemDamage; tower.computedCooldown = tower.definition.stats.cooldown - gemAttackSpeedUp; tower.computedRange = tower.definition.stats.range + gemRangeUp; tower.computedTimeToLive = tower.definition.stats.timeToLive + gemTimeToLiveUp; tower.computedPierce = tower.definition.stats.pierce + gemPierceUp; + + // Buff tower + if (tower.parent.isBuffedBy.length > 0 && tower.definition.name != GameAssets.Towers[TowerType.Buff].name) { + let buffedBy = tower.parent.isBuffedBy[0]; + tower.computedDamageToDeal += Math.ceil(buffedBy.computedDamageToDeal / 3); + tower.computedCooldown -= Math.ceil(buffedBy.computedCooldown / 5); + tower.computedRange += Math.ceil(buffedBy.computedRange / 10); + tower.computedTimeToLive += Math.ceil(buffedBy.computedTimeToLive / 5); + tower.computedPierce += Math.ceil(buffedBy.computedPierce / 4); + + tower.totalGemResistanceModifications.physical += + (buffedBy.totalGemResistanceModifications.physical * 100) / 2 / 100; + tower.totalGemResistanceModifications.ice += (buffedBy.totalGemResistanceModifications.ice * 100) / 2 / 100; + tower.totalGemResistanceModifications.fire += (buffedBy.totalGemResistanceModifications.fire * 100) / 2 / 100; + tower.totalGemResistanceModifications.divine += + (buffedBy.totalGemResistanceModifications.divine * 100) / 2 / 100; + tower.totalGemResistanceModifications.frostfire += + (buffedBy.totalGemResistanceModifications.frostfire * 100) / 2 / 100; + } } -/** - * Defines the basic behavior of a tower, including computing damage, checking projectiles, - * and handling shooting at creeps within range. - * - * @param tower - The tower whose behavior is being defined. - * @param elapsedMS - The elapsed time in milliseconds since the last update. - */ export function BasicTowerBehaviour(tower: Tower, elapsedMS: number) { computeGemImprovements(tower); projectileCheck(tower, elapsedMS); @@ -96,7 +114,6 @@ export function CircleTowerBehaviour(tower: Tower, elapsedMS: number) { tower.millisecondsUntilNextShot -= elapsedMS * Engine.GameScene.gameSpeedMultiplier; let creepsInRange = tower.GetCreepsInRange(); if (creepsInRange.length > 0) { - let focus = creepsInRange[0]; if (tower.millisecondsUntilNextShot <= 0) { tower.millisecondsUntilNextShot = tower.computedCooldown; let x = tower.column * Engine.GridCellSize + Engine.GridCellSize / 2; @@ -119,34 +136,52 @@ export function ElectricTowerBehaviour(tower: Tower, elapsedMS: number) { if (tower.millisecondsUntilNextShot > 0) 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)); + let proj = tower.Shoot(calculateAngleToPoint(x, y, focus.x, focus.y)); + proj.onCollide = (creep: Creep, proj: Projectile) => { + proj.pierce = 0; + let nearByCreeps = Engine.Grid.creeps.filter((nCreep) => { + if (nCreep.id != creep.id) { + const x = nCreep.x; + const y = nCreep.y; + const radius = 3.5 * Engine.GridCellSize; + const d = distance(creep.x, creep.y, x, y); + return d < radius; + } + }); + nearByCreeps.forEach((nearCreep) => { + new VisualLightning(creep, nearCreep); + Engine.GameScene.events.emit( + CreepEvents.TakenDamage, + nearCreep.id, + proj.damage / 2, + proj.gemResistanceModifications + ); + }); + Engine.GameScene.events.emit( + CreepEvents.TakenDamage, + creep.id, + proj.damage, + proj.gemResistanceModifications + ); + }; } } } -export function QuickTowerBehaviour(tower: Tower, elapsedMS: number) { +export function BuffTowerBehaviour(tower: Tower, elapsedMS: number) { computeGemImprovements(tower); - projectileCheck(tower, elapsedMS); - - if (tower.millisecondsUntilNextShot > 0) - 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)); - } - } + // Buff tower does not do anything and doesn't have a behaviour. + // For how its implemented, Cell tracks when it's placed and removed (via event) + // and tower takes improvements via computeGemImprovements() } export function StrongTowerBehaviour(tower: Tower, elapsedMS: number) { @@ -203,7 +238,7 @@ export function TrapperTowerBehaviour(tower: Tower, elapsedMS: number) { } } -export function AdvancedTowerBehaviour(tower: Tower, elapsedMS: number) { +export function DebuffTowerBehaviour(tower: Tower, elapsedMS: number) { computeGemImprovements(tower); projectileCheck(tower, elapsedMS); diff --git a/src/classes/game/TowerManager.ts b/src/classes/game/TowerManager.ts index daeb8aa..3936eec 100644 --- a/src/classes/game/TowerManager.ts +++ b/src/classes/game/TowerManager.ts @@ -2,7 +2,7 @@ import * as PIXI from 'pixi.js'; import { Engine } from '../Bastion'; import { TerrainType, TowerDefinition } from '../Definitions'; import GameAssets from '../Assets'; -import { Tower } from './Tower'; +import { distance, Tower } from './Tower'; import { Cell } from './Grid'; import { GridEvents, TowerEvents } from '../Events'; @@ -10,11 +10,11 @@ export enum TowerBehaviours { BasicTowerBehaviour = 'BasicTowerBehaviour', CircleTowerBehaviour = 'CircleTowerBehaviour', ElectricTowerBehaviour = 'ElectricTowerBehaviour', - QuickTowerBehaviour = 'QuickTowerBehaviour', + BuffTowerBehaviour = 'BuffTowerBehaviour', StrongTowerBehaviour = 'StrongTowerBehaviour', RailTowerBehaviour = 'RailTowerBehaviour', TrapperTowerBehaviour = 'TrapperTowerBehaviour', - AdvancedTowerBehaviour = 'AdvancedTowerBehaviour', + DebuffTowerBehaviour = 'DebuffTowerBehaviour', } export default class TowerManager { @@ -127,10 +127,10 @@ export default class TowerManager { while (twr.slottedGems.length > 0) { twr.UnslotGem(0); } + Engine.GameScene.events.emit(TowerEvents.TowerSoldEvent, twr.definition.name, twr.row, twr.column); Engine.GameScene.MissionStats.earnGold(twr.definition.stats.cost); twr.destroy(); this.towers.splice(idx, 1); - Engine.GameScene.events.emit(TowerEvents.TowerSoldEvent, twr.name, twr.row, twr.column); } else twr.update(elapsedMS); }); } diff --git a/src/main.ts b/src/main.ts index 3543950..49ca147 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,7 +7,7 @@ import { AnimationManager } from './classes/game/AnimationManager'; import NotificationManager from './classes/game/NotificationManager'; import GameUIConstants from './classes/GameUIConstants'; import KeyboardManager from './classes/game/KeyboardManager'; -import { GemType } from './classes/Definitions'; +import DebrisManager from './classes/game/DebrisManager'; (async () => { const app = new PIXI.Application(); @@ -54,10 +54,12 @@ import { GemType } from './classes/Definitions'; new GameMaster(); Engine.AnimationManager = new AnimationManager(); Engine.NotificationManager = new NotificationManager(); + Engine.DebrisManager = new DebrisManager(); globalThis.Engine = Engine; PIXI.Ticker.shared.add((ticker) => { Engine.NotificationManager.update(ticker.elapsedMS); Engine.AnimationManager.update(ticker.elapsedMS); + Engine.DebrisManager.update(ticker.elapsedMS); }); app.canvas.addEventListener('pointermove', function (event) { Engine.MouseX = ((event.clientX - app.canvas.offsetLeft) / app.canvas.offsetWidth) * 1920;